├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── src ├── CMakeLists.txt ├── Generator.cpp ├── Generator.h ├── ftxpath.cpp ├── ftxpath.h ├── split.cpp └── split.h ├── test ├── CMakeLists.txt ├── main.cpp ├── test_abspath.cpp ├── test_abspath.h ├── test_basename.cpp ├── test_basename.h ├── test_chdir.cpp ├── test_chdir.h ├── test_commonprefix.cpp ├── test_commonprefix.h ├── test_cwd.cpp ├── test_cwd.h ├── test_dirname.cpp ├── test_dirname.h ├── test_exists.cpp ├── test_exists.h ├── test_isabs.cpp ├── test_isabs.h ├── test_isdir.cpp ├── test_isdir.h ├── test_isfile.cpp ├── test_isfile.h ├── test_join.cpp ├── test_join.h ├── test_listdir.cpp ├── test_listdir.h ├── test_makedirs.cpp ├── test_makedirs.h ├── test_normpath.cpp ├── test_normpath.h ├── test_relpath.cpp ├── test_relpath.h ├── test_rmtree.cpp ├── test_rmtree.h ├── test_split.cpp ├── test_split.h ├── test_splitdrive.cpp ├── test_splitdrive.h ├── test_splitext.cpp ├── test_splitext.h ├── test_walk.cpp ├── test_walk.h ├── tester.h └── testlistdir │ ├── dir1 │ └── empty │ ├── dir2 │ └── empty │ ├── file1 │ └── file2 └── toolchain ├── android.toolchain.cmake └── ios.cmake /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | .idea/ 31 | 32 | # Visual Studio 33 | *.vcxproj 34 | *.vcxproj.filters 35 | *.opensdf 36 | *.sdf 37 | *.sln 38 | *.suo 39 | *.pdb 40 | ipch/ 41 | Debug/ 42 | Release/ 43 | Win32/Debug/ 44 | Win32/Release/ 45 | 46 | CMake* 47 | Makefile 48 | Testing/ 49 | 50 | CTestTestfile.cmake 51 | bin/ 52 | test_bin/ 53 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | 3 | project(ftxpath) 4 | 5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 6 | 7 | add_subdirectory(src bin) 8 | 9 | if (NOT (IOS OR ANDROID)) 10 | enable_testing() 11 | add_subdirectory(test test_bin) 12 | endif(NOT (IOS OR ANDROID)) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, 小沉 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### ftxpath ### 2 | Python (os.path) like, c++ path library 3 | 4 | ### 开这个坑的理由是:### 5 | 6 | * Python 的 os.path 库比较好用(个人感受)。 7 | * C++ 并没有找到比较好用的路径库 8 | 9 | * 基于以上非常充分的理由,开个坑,造个轮子,但愿不会烂尾。 10 | 11 | 12 | ### build static library: ### 13 | 14 | $ cmake . 15 | $ make 16 | 17 | ### build for ios device static library: ### 18 | $ cmake . -DCMAKE_TOOLCHAIN_FILE=toolchain/ios.cmake -DIOS_PLATFORM=OS 19 | 20 | ### build for ios simulator static library: ### 21 | $ cmake . -DCMAKE_TOOLCHAIN_FILE=toolchain/ios.cmake -DIOS_PLATFORM=SIMULATOR 22 | 23 | ### build for ios 64bit simulator static library: ### 24 | $ cmake . -DCMAKE_TOOLCHAIN_FILE=toolchain/ios.cmake -DIOS_PLATFORM=SIMULATOR64 25 | 26 | ### build for android: ### 27 | $ cmake . -DCMAKE_TOOLCHAIN_FILE=toolchain/android.toolchain.cmake \ 28 | -DANDROID_NDK= \ 29 | -DANDROID_ABI= 30 | 31 | example:
32 | ``` 33 | $ cmake . -DCMAKE_TOOLCHAIN_FILE=toolchain/android.toolchain.cmake -DANDROID_NDK=/Users/xiaochen/Develop/crystax-ndk-10.2.1 -DANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 -DANDROID_NATIVE_API_LEVEL=8 -DANDROID_ABI=armeabi 34 | ``` 35 | ### build for windows: ### 36 | $ cmake . 37 | and use Visual Studio open the "ftxpath.sln" -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(SOURCE_FILES 3 | Generator.cpp 4 | Generator.h 5 | ftxpath.cpp 6 | ftxpath.h 7 | split.cpp 8 | split.h) 9 | 10 | add_library(ftxpath STATIC ${SOURCE_FILES}) -------------------------------------------------------------------------------- /src/Generator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Generator.cpp 3 | // ftxpath 4 | // 5 | // Created by 王晓辰 on 15/8/16. 6 | // Copyright (c) 2015年 ftxtool. All rights reserved. 7 | // 8 | 9 | #include "Generator.h" 10 | 11 | #include "ftxpath.h" 12 | 13 | 14 | using namespace ftx; 15 | 16 | PathGenerator::PathIterator::PathIterator(PathGenerator* generator) 17 | : _generator(generator) 18 | , _current() 19 | { 20 | next(); 21 | } 22 | 23 | PathGenerator::PathIterator& PathGenerator::PathIterator::operator++() 24 | { 25 | _generator->popRoot(); 26 | next(); 27 | 28 | return *this; 29 | } 30 | 31 | bool PathGenerator::PathIterator::operator!=(const PathIterator& it) 32 | { 33 | return !_generator->empty(); 34 | } 35 | 36 | const PathGenerator::PathTuple& PathGenerator::PathIterator::operator*() 37 | { 38 | return _current; 39 | } 40 | 41 | const PathGenerator::PathTuple& PathGenerator::PathIterator::next() 42 | { 43 | std::string root = _generator->nextRoot(); 44 | std::vector folder_list; 45 | std::vector file_list; 46 | 47 | for (auto name : path::listdir(root)) 48 | { 49 | std::string full_name = path::join(root, name); 50 | if (path::isdir(full_name)) 51 | { 52 | folder_list.push_back(name); 53 | _generator->pushFolder(full_name); 54 | } 55 | else 56 | { 57 | file_list.push_back(name); 58 | } 59 | } 60 | 61 | _current = std::make_tuple(root, folder_list, file_list); 62 | 63 | return _current; 64 | } 65 | 66 | PathGenerator::PathGenerator(const std::string& path) 67 | : _roots({ path::normpath(path::abspath(path)) }) 68 | , _current(this) 69 | { 70 | } 71 | 72 | const PathGenerator::PathIterator& PathGenerator::begin() 73 | { 74 | return _current; 75 | } 76 | 77 | const PathGenerator::PathIterator& PathGenerator::end() 78 | { 79 | return _current; 80 | } 81 | 82 | void PathGenerator::pushFolder(const std::string& folder) 83 | { 84 | _roots.push_back(path::normpath(folder)); 85 | } 86 | 87 | void PathGenerator::popRoot() 88 | { 89 | if (_roots.empty()) 90 | { 91 | return; 92 | } 93 | 94 | _roots.pop_front(); 95 | } 96 | 97 | std::string PathGenerator::nextRoot() 98 | { 99 | if (_roots.empty()) 100 | { 101 | return std::string(); 102 | } 103 | 104 | std::string root = _roots.back(); 105 | if (!path::isdir(root)) 106 | { 107 | return std::string(); 108 | } 109 | 110 | return root; 111 | } 112 | 113 | bool PathGenerator::empty() 114 | { 115 | return _roots.empty(); 116 | } -------------------------------------------------------------------------------- /src/Generator.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generator.h 3 | // libpath 4 | // 5 | // Created by 王晓辰 on 15/8/16. 6 | // Copyright (c) 2015年 ftxtool. All rights reserved. 7 | // 8 | 9 | #ifndef __libpath__Generator__ 10 | #define __libpath__Generator__ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace ftx 19 | { 20 | 21 | class PathGenerator 22 | { 23 | public: 24 | typedef std::tuple, std::vector> PathTuple; 25 | 26 | class PathIterator 27 | { 28 | public: 29 | PathIterator(PathGenerator* generator); 30 | 31 | PathIterator& operator++(); 32 | bool operator!=(const PathIterator& it); 33 | const PathTuple& operator*(); 34 | 35 | private: 36 | const PathTuple& next(); 37 | 38 | private: 39 | PathTuple _current; 40 | PathGenerator* _generator; 41 | }; 42 | 43 | PathGenerator(const std::string& path); 44 | const PathIterator& begin(); 45 | const PathIterator& end(); 46 | 47 | private: 48 | void pushFolder(const std::string& folder); 49 | void popRoot(); 50 | std::string nextRoot(); 51 | bool empty(); 52 | 53 | private: 54 | std::deque _roots; 55 | PathIterator _current; 56 | }; 57 | 58 | } 59 | 60 | #endif /* defined(__libpath__Generator__) */ 61 | -------------------------------------------------------------------------------- /src/ftxpath.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // ftxpath.cpp 3 | // ftxpath 4 | // 5 | // Created by 王晓辰 on 15/8/8. 6 | // Copyright (c) 2015年 ftxtool. All rights reserved. 7 | // 8 | 9 | #include "ftxpath.h" 10 | 11 | #include "split.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #ifdef WIN32 20 | #include 21 | #include 22 | #else 23 | #include 24 | #include 25 | #endif 26 | 27 | 28 | const std::string curdir = "."; 29 | const std::string pardir = ".."; 30 | const std::string extsep = "."; 31 | #ifdef WIN32 32 | const char sep = '\\'; 33 | const char altsep = '/'; 34 | #else 35 | const char sep = '/'; 36 | const char altsep = 0; 37 | #endif 38 | 39 | 40 | using namespace ftx; 41 | 42 | std::string _cwd() 43 | { 44 | char* buff = nullptr; 45 | buff = getcwd(nullptr, 0); 46 | 47 | std::string path(buff); 48 | 49 | if (buff != nullptr) 50 | { 51 | free(buff); 52 | } 53 | 54 | return path; 55 | } 56 | 57 | std::string path::cwd() 58 | { 59 | return _cwd(); 60 | } 61 | 62 | std::tuple path::splitext(const std::string &path) 63 | { 64 | auto sep_index = path.rfind(sep); 65 | auto dot_index = path.rfind(extsep); 66 | 67 | #ifdef WIN32 68 | if (altsep != 0) 69 | { 70 | auto altsep_index = path.rfind(altsep); 71 | if (altsep_index != std::string::npos) 72 | { 73 | if (sep_index == std::string::npos) 74 | { 75 | sep_index = altsep_index; 76 | } 77 | else 78 | { 79 | sep_index = max(sep_index, altsep_index); 80 | } 81 | } 82 | } 83 | #endif 84 | 85 | if (dot_index != std::string::npos) 86 | { 87 | if (sep_index == std::string::npos) 88 | { 89 | return std::make_tuple(path.substr(0, dot_index), path.substr(dot_index)); 90 | } 91 | 92 | if (dot_index > sep_index) 93 | { 94 | auto filename_index = sep_index + 1; 95 | while (filename_index < dot_index) 96 | { 97 | auto c = path[filename_index]; 98 | if (c != sep && c != altsep) 99 | { 100 | return std::make_tuple(path.substr(0, dot_index), path.substr(dot_index)); 101 | } 102 | 103 | ++filename_index; 104 | } 105 | } 106 | } 107 | 108 | return std::make_tuple(path, std::string()); 109 | } 110 | 111 | #ifdef WIN32 112 | std::tuple _splitdrive_win32(const std::string&path) 113 | { 114 | std::string drive = ""; 115 | std::string np = path; 116 | 117 | if (np.size() > 1) 118 | { 119 | std::replace(np.begin(), np.end(), altsep, sep); 120 | std::string normp = np; 121 | if (normp.substr(0, 2) == std::string() + sep + sep 122 | && normp.substr(2, 1) != std::string() + sep) 123 | { 124 | auto index = normp.find(sep, 2); 125 | if (index == std::string::npos) 126 | { 127 | goto EMPTY_RETURN; 128 | } 129 | 130 | auto index2 = normp.find(sep, index + 1); 131 | if (index2 == index + 1) 132 | { 133 | goto EMPTY_RETURN; 134 | } 135 | 136 | if (index2 == std::string::npos) 137 | { 138 | index2 = path.size(); 139 | } 140 | 141 | drive = path.substr(0, index2); 142 | std::string p = path.substr(index2); 143 | 144 | return std::make_tuple(drive, p); 145 | } 146 | 147 | if (normp[1] == ':') 148 | { 149 | drive = path.substr(0, 2); 150 | std::string p = path.substr(2); 151 | 152 | return std::make_tuple(drive, p); 153 | } 154 | } 155 | 156 | EMPTY_RETURN: 157 | return std::make_tuple(drive, path); 158 | } 159 | #endif 160 | 161 | std::tuple path::splitdrive(const std::string &path) 162 | { 163 | #ifdef WIN32 164 | return _splitdrive_win32(path); 165 | #else 166 | return std::make_tuple("", path); 167 | #endif 168 | } 169 | 170 | #ifdef WIN32 171 | std::tuple _split_win32(const std::string &path) 172 | { 173 | std::string drive; 174 | std::string rest; 175 | 176 | std::tie(drive, rest) = _splitdrive_win32(path); 177 | 178 | auto index = rest.size(); 179 | while (index != 0) 180 | { 181 | auto c = rest[index - 1]; 182 | if (c == sep || c == altsep) 183 | { 184 | break; 185 | } 186 | 187 | --index; 188 | } 189 | 190 | std::string head = rest.substr(0, index); 191 | std::string tail = rest.substr(index); 192 | 193 | std::string head2 = head; 194 | while (!head2.empty()) 195 | { 196 | auto c = *(head2.rbegin()); 197 | if (c == sep || c == altsep) 198 | { 199 | head2 = head2.substr(0, head2.size() - 1); 200 | } 201 | else 202 | { 203 | break; 204 | } 205 | } 206 | 207 | if (!head2.empty()) 208 | { 209 | head = head2; 210 | } 211 | 212 | return std::make_tuple(drive + head, tail); 213 | } 214 | #else 215 | std::tuple _split_posix(const std::string &path) 216 | { 217 | auto pos = path.rfind('/'); 218 | 219 | if (pos == std::string::npos) 220 | { 221 | return std::tuple(std::string(), path); 222 | } 223 | 224 | std::string head = path.substr(0, pos + 1); 225 | std::string tail = path.substr(pos + 1); 226 | 227 | for (auto c : head) 228 | { 229 | if (c != '/') 230 | { 231 | while (*(head.rbegin()) == '/') 232 | { 233 | head = head.substr(0, head.size() - 1); 234 | continue; 235 | } 236 | 237 | break; 238 | } 239 | } 240 | 241 | return std::make_tuple(head, tail); 242 | } 243 | #endif 244 | 245 | std::tuple path::split(const std::string &path) 246 | { 247 | #ifdef WIN32 248 | return _split_win32(path); 249 | #else 250 | return _split_posix(path); 251 | #endif 252 | } 253 | 254 | #ifdef WIN32 255 | bool _isabs_win32(const std::string &path) 256 | { 257 | std::string p; 258 | std::tie(std::ignore, p) = _splitdrive_win32(path); 259 | 260 | return p != "" && (p[0] == sep || p[0] == altsep); 261 | } 262 | #else 263 | bool _isabs_posix(const std::string &path) 264 | { 265 | return path[0] == sep; 266 | } 267 | #endif 268 | 269 | bool path::isabs(const std::string &path) 270 | { 271 | #ifdef WIN32 272 | return _isabs_win32(path); 273 | #else 274 | return _isabs_posix(path); 275 | #endif 276 | } 277 | 278 | #ifdef WIN32 279 | void _join_two_win32(std::string &result_drive, std::string &result_path, const std::string &rpath) 280 | { 281 | std::string pdrive; 282 | std::string ppath; 283 | std::tie(pdrive, ppath) = _splitdrive_win32(rpath); 284 | if (!ppath.empty() && (ppath[0] == sep || ppath[0] == altsep)) 285 | { 286 | if (!pdrive.empty() && result_drive.empty()) 287 | { 288 | result_drive = pdrive; 289 | } 290 | result_path = ppath; 291 | return; 292 | } 293 | else if (!pdrive.empty() && pdrive != result_drive) 294 | { 295 | std::string lower_pdrive = pdrive; 296 | std::string lower_lpath = result_drive; 297 | std::transform(lower_pdrive.begin(), lower_pdrive.end(), lower_pdrive.begin(), std::tolower); 298 | std::transform(lower_lpath.begin(), lower_lpath.end(), lower_lpath.begin(), std::tolower); 299 | if (lower_pdrive != lower_lpath) 300 | { 301 | result_drive = pdrive; 302 | result_path = ppath; 303 | return; 304 | } 305 | result_drive = pdrive; 306 | } 307 | 308 | if (!result_path.empty()) 309 | { 310 | auto c = *(result_path.rbegin()); 311 | if (c != sep && c != altsep) 312 | { 313 | result_path += sep; 314 | } 315 | result_path += ppath; 316 | } 317 | } 318 | 319 | std::string _join_win32(const std::string &lpath, const std::string &rpath) 320 | { 321 | std::string result_drive; 322 | std::string result_path; 323 | std::tie(result_drive, result_path) = _splitdrive_win32(lpath); 324 | _join_two_win32(result_drive, result_path, rpath); 325 | 326 | if (!result_drive.empty() && !result_path.empty()) 327 | { 328 | auto pc = result_path[0]; 329 | auto dc = *(result_drive.rbegin()); 330 | if (pc != sep && pc != altsep && dc != ':') 331 | { 332 | return result_drive + sep + result_path; 333 | } 334 | } 335 | 336 | return result_drive + result_path; 337 | } 338 | 339 | std::string _join_win32(const std::string &lpath, const std::vector &rpaths) 340 | { 341 | std::string result_drive; 342 | std::string result_path; 343 | std::tie(result_drive, result_path) = _splitdrive_win32(lpath); 344 | for (auto rp : rpaths) 345 | { 346 | _join_two_win32(result_drive, result_path, rp); 347 | } 348 | 349 | if (!result_drive.empty() && !result_path.empty()) 350 | { 351 | auto pc = result_path[0]; 352 | auto dc = *(result_drive.rbegin()); 353 | if (pc != sep && pc != altsep && dc != ':') 354 | { 355 | return result_drive + sep + result_path; 356 | } 357 | } 358 | 359 | return result_drive + result_path; 360 | } 361 | #else 362 | void _join_two_posix(std::string &lpath, const std::string &rpath) 363 | { 364 | if (_isabs_posix(rpath)) 365 | { 366 | lpath = rpath; 367 | } 368 | else if (lpath.empty() || *(lpath.rbegin()) == sep || *(lpath.rbegin()) == altsep) 369 | { 370 | lpath += rpath; 371 | } 372 | else 373 | { 374 | lpath += sep + rpath; 375 | } 376 | } 377 | 378 | std::string _join_posix(const std::string &lpath, const std::string &rpath) 379 | { 380 | std::string path = lpath; 381 | _join_two_posix(path, rpath); 382 | return path; 383 | } 384 | 385 | std::string _join_posix(const std::string &lpath, const std::vector &rpaths) 386 | { 387 | std::string path = lpath; 388 | for (auto rp : rpaths) 389 | { 390 | _join_two_posix(path, rp); 391 | } 392 | 393 | return path; 394 | } 395 | #endif 396 | 397 | std::string path::join(const std::string &lpath, const std::string &rpath) 398 | { 399 | #ifdef WIN32 400 | return _join_win32(lpath, rpath); 401 | #else 402 | return _join_posix(lpath, rpath); 403 | #endif 404 | } 405 | 406 | std::string path::join(const std::string &lpath, const std::vector &rpaths) 407 | { 408 | #ifdef WIN32 409 | return _join_win32(lpath, rpaths); 410 | #else 411 | return _join_posix(lpath, rpaths); 412 | #endif 413 | } 414 | 415 | std::string path::basename(const std::string &path) 416 | { 417 | std::string basename; 418 | std::tie(std::ignore, basename) = split(path); 419 | 420 | return basename; 421 | } 422 | 423 | std::string path::dirname(const std::string &path) 424 | { 425 | std::string dirname; 426 | std::tie(dirname, std::ignore) = split(path); 427 | 428 | return dirname; 429 | } 430 | 431 | std::string _join_str(const std::string& str, const std::vector& arr) 432 | { 433 | if (arr.empty()) 434 | { 435 | return std::string(); 436 | } 437 | 438 | std::string result; 439 | for (auto iter = arr.cbegin();;) 440 | { 441 | result += *iter; 442 | if (++iter != arr.cend()) 443 | { 444 | result += str; 445 | } 446 | else 447 | { 448 | break; 449 | } 450 | } 451 | 452 | return result; 453 | } 454 | 455 | #ifdef WIN32 456 | std::string _normpath_win32(const std::string &path) 457 | { 458 | std::string backslash = "\\"; 459 | std::string dot = "."; 460 | 461 | std::string np = path; 462 | if (np.substr(0, 4) == "\\\\.\\" || np.substr(0, 4) == "\\\\?\\") 463 | { 464 | return path; 465 | } 466 | 467 | std::replace(np.begin(), np.end(), '/', '\\'); 468 | 469 | std::string prefix; 470 | std::string pth; 471 | std::tie(prefix, pth) = _splitdrive_win32(np); 472 | 473 | if (prefix.empty()) 474 | { 475 | while (pth[0] == '\\') 476 | { 477 | prefix += backslash; 478 | pth = pth.substr(1); 479 | } 480 | } 481 | else 482 | { 483 | if (pth[0] == '\\') 484 | { 485 | prefix += backslash; 486 | pth = pth.substr(1); 487 | } 488 | } 489 | 490 | if (pth.empty()) 491 | { 492 | return prefix; 493 | } 494 | 495 | std::vector comps; 496 | _split(pth, '\\', comps); 497 | 498 | int i = 0; 499 | while (i < comps.size()) 500 | { 501 | if (comps[i] == "." || comps[i] == "") 502 | { 503 | comps.erase(comps.begin() + i); 504 | } 505 | else if (comps[i] == "..") 506 | { 507 | if (i > 0 && comps[i - 1] != "..") 508 | { 509 | comps.erase(comps.begin() + i - 1); 510 | comps.erase(comps.begin() + i - 1); 511 | --i; 512 | } 513 | else if (i == 0 && !prefix.empty() && *(prefix.rbegin()) == '\\') 514 | { 515 | comps.erase(comps.begin() + i); 516 | } 517 | else 518 | { 519 | ++i; 520 | } 521 | } 522 | else 523 | { 524 | ++i; 525 | } 526 | } 527 | 528 | if (prefix.empty() && comps.empty()) 529 | { 530 | comps.push_back(dot); 531 | } 532 | 533 | return prefix + _join_str(backslash, comps); 534 | } 535 | #else 536 | std::string _normpath_posix(const std::string &path) 537 | { 538 | if (path.empty()) 539 | { 540 | return curdir; 541 | } 542 | 543 | int initial_slashes = 0; 544 | if (path[0] == '/') 545 | { 546 | initial_slashes = 1; 547 | } 548 | 549 | if (initial_slashes == 1 && path[1] == '/' && path[2] != '/') 550 | { 551 | initial_slashes = 2; 552 | } 553 | 554 | std::vector comps; 555 | _split(path, '/', comps); 556 | 557 | std::vector new_comps; 558 | for (auto comp : comps) 559 | { 560 | if (comp.empty() || comp == ".") 561 | { 562 | continue; 563 | } 564 | 565 | if (comp != ".." || (initial_slashes == 0 && new_comps.empty()) || (!new_comps.empty() && *(new_comps.crbegin()) == "..")) 566 | { 567 | new_comps.push_back(comp); 568 | } 569 | else if (!new_comps.empty()) 570 | { 571 | new_comps.pop_back(); 572 | } 573 | } 574 | 575 | std::string slash = "/"; 576 | std::string norm_path; 577 | if (initial_slashes != 0) 578 | { 579 | for (int i = 0; i < initial_slashes; ++i) 580 | { 581 | norm_path += slash; 582 | } 583 | } 584 | else 585 | { 586 | if (new_comps.empty()) 587 | { 588 | return curdir; 589 | } 590 | } 591 | 592 | norm_path += _join_str(slash, new_comps); 593 | return norm_path; 594 | } 595 | #endif 596 | 597 | std::string path::normpath(const std::string &path) 598 | { 599 | #ifdef WIN32 600 | return _normpath_win32(path); 601 | #else 602 | return _normpath_posix(path); 603 | #endif 604 | } 605 | 606 | #ifdef WIN32 607 | std::string _abspath_win32(const std::string &path) 608 | { 609 | std::string abs_path = path; 610 | 611 | char** lppPart = { NULL }; 612 | char out_path[MAX_PATH] = {0}; 613 | GetFullPathNameA(abs_path.c_str(), MAX_PATH, out_path, lppPart); 614 | abs_path = out_path; 615 | 616 | if (!_isabs_win32(abs_path)) 617 | { 618 | abs_path = _join_win32(_cwd(), abs_path); 619 | } 620 | 621 | return _normpath_win32(abs_path); 622 | } 623 | #else 624 | std::string _abspath_posix(const std::string &path) 625 | { 626 | std::string abs_path = path; 627 | 628 | if (!_isabs_posix(abs_path)) 629 | { 630 | abs_path = _join_posix(_cwd(), abs_path); 631 | } 632 | 633 | return _normpath_posix(abs_path); 634 | } 635 | #endif 636 | 637 | std::string path::abspath(const std::string &path) 638 | { 639 | #ifdef WIN32 640 | return _abspath_win32(path); 641 | #else 642 | return _abspath_posix(path); 643 | #endif 644 | } 645 | 646 | #ifdef WIN32 647 | std::tuple _splitunc_win32(const std::string &path) 648 | { 649 | std::string firstTwo; 650 | if (path[1] == ':') 651 | { 652 | goto EMPTY_PATH_TUPLE; 653 | } 654 | 655 | firstTwo = path.substr(0, 2); 656 | if (firstTwo == "//" || firstTwo == "\\\\") 657 | { 658 | std::string normp = path; 659 | std::replace(normp.begin(), normp.end(), '\\', '/'); 660 | 661 | auto index = normp.find('/', 2); 662 | if (index <= 2) 663 | { 664 | goto EMPTY_PATH_TUPLE; 665 | } 666 | 667 | auto index2 = normp.find('/', index + 1); 668 | if (index2 == index + 1) 669 | { 670 | goto EMPTY_PATH_TUPLE; 671 | } 672 | 673 | if (index2 == std::string::npos) 674 | { 675 | index2 = path.size(); 676 | } 677 | 678 | return std::make_tuple(path.substr(0, index2), path.substr(index2)); 679 | } 680 | 681 | EMPTY_PATH_TUPLE: 682 | return std::make_tuple(std::string(), path); 683 | } 684 | 685 | std::tuple> _abspath_split(const std::string path) 686 | { 687 | std::string abs = _abspath_win32(_normpath_win32(path)); 688 | 689 | std::string drive; 690 | std::string rest; 691 | 692 | std::tie(drive, rest) = _splitunc_win32(abs); 693 | bool is_unc = !drive.empty(); 694 | if (!is_unc) 695 | { 696 | std::tie(drive, rest) = _splitdrive_win32(abs); 697 | } 698 | 699 | std::vector path_list; 700 | _split(rest, sep, path_list); 701 | 702 | return std::make_tuple(is_unc, drive, path_list); 703 | } 704 | 705 | std::string _relpath_win32(const std::string &path, const std::string &start) 706 | { 707 | std::string np = path; 708 | std::string ns = start.empty() ? curdir : start; 709 | 710 | if (path.empty()) 711 | { 712 | return path; 713 | } 714 | 715 | bool s_is_unc, p_is_unc; 716 | std::string s_prefix, p_prefix; 717 | std::vector s_list, p_list; 718 | std::tie(s_is_unc, s_prefix, s_list) = _abspath_split(start); 719 | std::tie(p_is_unc, p_prefix, p_list) = _abspath_split(path); 720 | 721 | if (s_is_unc ^ p_is_unc) 722 | { 723 | return path; 724 | } 725 | 726 | std::string lower_sprefix = s_prefix; 727 | std::string lower_pprefix = p_prefix; 728 | std::transform(lower_sprefix.begin(), lower_sprefix.end(), lower_sprefix.begin(), std::tolower); 729 | std::transform(lower_pprefix.begin(), lower_pprefix.end(), lower_pprefix.begin(), std::tolower); 730 | 731 | if (lower_sprefix != lower_pprefix) 732 | { 733 | return path; 734 | } 735 | 736 | int i = 0; 737 | int end = min(s_list.size(), p_list.size()); 738 | for (; i < end; ++i) 739 | { 740 | std::string lower_snode = s_list[i]; 741 | std::string lower_pnode = p_list[i]; 742 | std::transform(lower_snode.begin(), lower_snode.end(), lower_snode.begin(), std::tolower); 743 | std::transform(lower_pnode.begin(), lower_pnode.end(), lower_pnode.begin(), std::tolower); 744 | 745 | if (lower_snode != lower_pnode) 746 | { 747 | break; 748 | } 749 | } 750 | 751 | std::vector rel_list; 752 | for (int j = s_list.size() - i; j > 0; --j) 753 | { 754 | rel_list.push_back(pardir); 755 | } 756 | 757 | for (int k = i; k < p_list.size(); ++k) 758 | { 759 | rel_list.push_back(p_list[k]); 760 | } 761 | 762 | if (rel_list.empty()) 763 | { 764 | return curdir; 765 | } 766 | 767 | std::string rel_path = rel_list[0]; 768 | for (int i = 1; i < rel_list.size(); ++i) 769 | { 770 | rel_path += sep; 771 | rel_path += rel_list[i]; 772 | } 773 | 774 | return rel_path; 775 | } 776 | #else 777 | std::string _relpath_posix(const std::string &path, const std::string &start) 778 | { 779 | std::string np = path; 780 | std::string ns = start.empty() ? curdir : start; 781 | 782 | std::vector path_list; 783 | _split(_abspath_posix(np), sep, path_list); 784 | 785 | std::vector start_list; 786 | _split(_abspath_posix(ns), sep, start_list); 787 | 788 | std::vector rel_list; 789 | 790 | auto path_it = path_list.cbegin(); 791 | auto start_it = start_list.cbegin(); 792 | for (; path_it != path_list.cend() && start_it != start_list.cend(); ++path_it, ++start_it) 793 | { 794 | if (*path_it != *start_it) 795 | { 796 | break; 797 | } 798 | } 799 | 800 | for (; start_it != start_list.cend(); ++start_it) 801 | { 802 | rel_list.push_back(pardir); 803 | } 804 | 805 | for (; path_it != path_list.cend(); ++path_it) 806 | { 807 | rel_list.push_back(*path_it); 808 | } 809 | 810 | std::string rel_path; 811 | for (auto node : rel_list) 812 | { 813 | _join_two_posix(rel_path, node); 814 | } 815 | 816 | return rel_path; 817 | } 818 | #endif 819 | 820 | std::string path::relpath(const std::string &path, const std::string &start) 821 | { 822 | #ifdef WIN32 823 | return _relpath_win32(path, start); 824 | #else 825 | return _relpath_posix(path, start); 826 | #endif 827 | } 828 | 829 | void _make_path_list(const std::string& path, std::vector& path_list) 830 | { 831 | #ifdef WIN32 832 | std::string abspath = _normpath_win32(_abspath_win32(path)); 833 | std::tie(std::ignore, abspath) = _splitdrive_win32(abspath); 834 | #else 835 | std::string abspath = _normpath_posix(_abspath_posix(path)); 836 | #endif 837 | 838 | _split(abspath, sep, path_list); 839 | std::remove_if(path_list.begin(), path_list.end(), [](const std::string &node){ 840 | return node.empty(); 841 | }); 842 | } 843 | 844 | std::vector _make_path_list(const std::string& path) 845 | { 846 | std::vector path_list; 847 | _make_path_list(path, path_list); 848 | return path_list; 849 | } 850 | 851 | std::string path::commonprefix(const std::string &path1, const std::string &path2) 852 | { 853 | if (path1.empty() || path2.empty()) 854 | { 855 | return std::string(); 856 | } 857 | 858 | std::string p1 = path1; 859 | std::string p2 = path2; 860 | 861 | #ifdef WIN32 862 | std::string drive1, drive2; 863 | std::tie(drive1, p1) = _splitdrive_win32(_abspath_win32(p1)); 864 | std::tie(drive2, p2) = _splitdrive_win32(_abspath_win32(p2)); 865 | 866 | if (drive1 != drive2) 867 | { 868 | return std::string(); 869 | } 870 | #endif 871 | 872 | std::vector path1_list = _make_path_list(p1); 873 | std::vector path2_list = _make_path_list(p2); 874 | 875 | std::vector common_list; 876 | for (auto i = 0; i < path1_list.size() && i < path2_list.size(); ++i) 877 | { 878 | std::string node1 = path1_list[i]; 879 | std::string node2 = path2_list[i]; 880 | if (node1 == node2) 881 | { 882 | common_list.push_back(node1); 883 | } 884 | else 885 | { 886 | break; 887 | } 888 | } 889 | 890 | std::string common_path; 891 | 892 | #ifdef WIN32 893 | if (!drive1.empty()) 894 | { 895 | common_path += drive1; 896 | } 897 | 898 | common_path += sep; 899 | common_path = _join_win32(common_path, common_list); 900 | #else 901 | common_path += sep; 902 | common_path = _join_posix(common_path, common_list); 903 | #endif 904 | 905 | return common_path; 906 | } 907 | 908 | #ifndef MAXUINT32 909 | #define MAXUINT32 (-1) 910 | #endif 911 | 912 | std::string path::commonprefix(const std::vector &path_list) 913 | { 914 | if (path_list.empty()) 915 | { 916 | return std::string(); 917 | } 918 | 919 | std::vector paths = path_list; 920 | #ifdef WIN32 921 | std::string common_drive; 922 | bool is_init = false; 923 | std::vector tails; 924 | #endif 925 | for (std::string path : paths) 926 | { 927 | if (path.empty()) 928 | { 929 | return std::string(); 930 | } 931 | 932 | #ifdef WIN32 933 | std::string drive; 934 | std::string tail; 935 | std::tie(drive, tail) = _splitdrive_win32(_abspath_win32(path)); 936 | 937 | if (!is_init) 938 | { 939 | common_drive = drive; 940 | is_init = true; 941 | } 942 | else 943 | { 944 | if (drive != common_drive) 945 | { 946 | return std::string(); 947 | } 948 | } 949 | 950 | tails.push_back(tail); 951 | } 952 | 953 | paths = tails; 954 | #else 955 | } 956 | #endif 957 | 958 | std::vector> path_list_table; 959 | size_t min_size = MAXUINT32; 960 | for (std::string path : paths) 961 | { 962 | std::vector list = _make_path_list(path); 963 | if (list.size() < min_size) 964 | { 965 | min_size = list.size(); 966 | } 967 | path_list_table.push_back(list); 968 | } 969 | 970 | std::vector common_list; 971 | for (auto i = 0; i < min_size; ++i) 972 | { 973 | std::string common_node; 974 | for (auto list : path_list_table) 975 | { 976 | std::string node = list[i]; 977 | if (common_node.empty()) 978 | { 979 | common_node = node; 980 | continue; 981 | } 982 | 983 | if (node != common_node) 984 | { 985 | goto ENDING; 986 | } 987 | } 988 | 989 | common_list.push_back(common_node); 990 | } 991 | 992 | ENDING: 993 | 994 | std::string common_path; 995 | 996 | #ifdef WIN32 997 | if (!common_drive.empty()) 998 | { 999 | common_path += common_drive; 1000 | } 1001 | 1002 | common_path += sep; 1003 | common_path = _join_win32(common_path, common_list); 1004 | #else 1005 | common_path += sep; 1006 | common_path = _join_posix(common_path, common_list); 1007 | #endif 1008 | 1009 | return common_path; 1010 | } 1011 | 1012 | #ifdef WIN32 1013 | std::vector _listdir_win32(const std::string &path) 1014 | { 1015 | std::vector list_dir; 1016 | 1017 | std::string strFind = _join_win32(path, "*.*"); 1018 | WIN32_FIND_DATAA FindFileData; 1019 | HANDLE hFind = FindFirstFileA(strFind.c_str(), &FindFileData); 1020 | 1021 | if (INVALID_HANDLE_VALUE == hFind) 1022 | { 1023 | return list_dir; 1024 | } 1025 | 1026 | do 1027 | { 1028 | std::string name = FindFileData.cFileName; 1029 | if (name == curdir || name == pardir) 1030 | { 1031 | continue; 1032 | } 1033 | list_dir.push_back(name); 1034 | } while (FindNextFileA(hFind, &FindFileData)); 1035 | 1036 | FindClose(hFind); 1037 | 1038 | return list_dir; 1039 | } 1040 | #else 1041 | std::vector _listdir_posix(const std::string &path) 1042 | { 1043 | std::vector list_dir; 1044 | DIR* pDir = opendir(path.c_str()); 1045 | if (pDir != nullptr) 1046 | { 1047 | struct dirent *ent; 1048 | while ((ent = readdir(pDir)) != nullptr) 1049 | { 1050 | std::string name = ent->d_name; 1051 | if (name == curdir || name == pardir) 1052 | { 1053 | continue; 1054 | } 1055 | list_dir.push_back(ent->d_name); 1056 | } 1057 | closedir(pDir); 1058 | } 1059 | 1060 | return list_dir; 1061 | } 1062 | #endif 1063 | 1064 | std::vector path::listdir(const std::string &path) 1065 | { 1066 | #ifdef WIN32 1067 | return _listdir_win32(path); 1068 | #else 1069 | return _listdir_posix(path); 1070 | #endif 1071 | } 1072 | 1073 | #ifdef WIN32 1074 | #define S_ISDIR(st_mode) (_S_IFDIR & st_mode) 1075 | #define S_ISREG(st_mode) (_S_IFREG & st_mode) 1076 | #endif 1077 | 1078 | bool path::isdir(const std::string &path) 1079 | { 1080 | struct stat buf; 1081 | return stat(path.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode); 1082 | } 1083 | 1084 | bool path::isfile(const std::string &path) 1085 | { 1086 | struct stat buf; 1087 | return stat(path.c_str(), &buf) == 0 && S_ISREG(buf.st_mode); 1088 | } 1089 | 1090 | bool path::exists(const std::string &path) 1091 | { 1092 | struct stat buf; 1093 | return stat(path.c_str(), &buf) == 0; 1094 | } 1095 | 1096 | int path::cd(const std::string &path) 1097 | { 1098 | return chdir(path.c_str()); 1099 | } 1100 | 1101 | void path::makedirs(const std::string &path) 1102 | { 1103 | std::string npath = normpath(abspath(path)); 1104 | 1105 | std::string temp_path; 1106 | #ifdef WIN32 1107 | std::tie(temp_path, npath) = splitdrive(npath); 1108 | if (temp_path.empty()) 1109 | { 1110 | return; 1111 | } 1112 | #endif 1113 | temp_path += + sep; 1114 | 1115 | auto node_list = _split(npath, sep); 1116 | for (auto node : node_list) 1117 | { 1118 | temp_path = join(temp_path, node); 1119 | if (!isdir(temp_path)) 1120 | { 1121 | #ifdef WIN32 1122 | mkdir(temp_path.c_str()); 1123 | #else 1124 | mkdir(temp_path.c_str(), ACCESSPERMS); 1125 | #endif 1126 | } 1127 | } 1128 | } 1129 | 1130 | void path::rmtree(const std::string &path) 1131 | { 1132 | if (!isdir(path)) 1133 | { 1134 | remove(path.c_str()); 1135 | } 1136 | 1137 | std::string temp_path = relpath(path); 1138 | auto nodes = listdir(temp_path); 1139 | while (nodes.size() != 0) 1140 | { 1141 | std::string node_path = join(temp_path, nodes[0]); 1142 | 1143 | if (isdir(node_path)) 1144 | { 1145 | auto temp_nodes = listdir(node_path); 1146 | if (temp_nodes.size() == 0) 1147 | { 1148 | rmdir(node_path.c_str()); 1149 | } 1150 | else 1151 | { 1152 | temp_path = node_path; 1153 | } 1154 | } 1155 | else 1156 | { 1157 | remove(node_path.c_str()); 1158 | } 1159 | 1160 | nodes = listdir(temp_path); 1161 | 1162 | while (nodes.size() == 0) 1163 | { 1164 | std::string root; 1165 | std::string node; 1166 | std::tie(root, node) = split(relpath(temp_path, path)); 1167 | 1168 | if (node.empty() || node == curdir || root.find(pardir) != std::string::npos) 1169 | { 1170 | break; 1171 | } 1172 | 1173 | rmdir(temp_path.c_str()); 1174 | 1175 | temp_path = join(path, root); 1176 | nodes = listdir(temp_path); 1177 | } 1178 | } 1179 | 1180 | rmdir(path.c_str()); 1181 | } 1182 | 1183 | PathGenerator path::walk(const std::string &path) 1184 | { 1185 | return PathGenerator(path); 1186 | } 1187 | 1188 | void path::walk(const std::string &path, std::function folders, std::vector files)> func) 1189 | { 1190 | for (auto p : walk(path)) 1191 | { 1192 | std::string root; 1193 | std::vector folders; 1194 | std::vector files; 1195 | 1196 | std::tie(root, folders, files) = p; 1197 | func(root, folders, files); 1198 | } 1199 | } 1200 | -------------------------------------------------------------------------------- /src/ftxpath.h: -------------------------------------------------------------------------------- 1 | // 2 | // ftxpath.h 3 | // ftxpath 4 | // 5 | // Created by 王晓辰 on 15/8/8. 6 | // Copyright (c) 2015年 ftxtool. All rights reserved. 7 | // 8 | 9 | #ifndef __ftxpath__ftxpath__ 10 | #define __ftxpath__ftxpath__ 11 | 12 | #include 13 | #include 14 | #include 15 | #include "Generator.h" 16 | 17 | namespace ftx { 18 | class path { 19 | public: 20 | 21 | static std::string cwd(); 22 | 23 | static std::tuple splitext(const std::string&); 24 | static std::tuple splitdrive(const std::string&); 25 | static std::tuple split(const std::string&); 26 | 27 | static bool isabs(const std::string&); 28 | 29 | static std::string join(const std::string&, const std::string&); 30 | static std::string join(const std::string&, const std::vector&); 31 | 32 | static std::string basename(const std::string&); 33 | static std::string dirname(const std::string&); 34 | 35 | static std::string normpath(const std::string&); 36 | static std::string abspath(const std::string&); 37 | static std::string relpath(const std::string&, const std::string& start = std::string()); 38 | 39 | static std::string commonprefix(const std::string&, const std::string&); 40 | static std::string commonprefix(const std::vector&); 41 | 42 | static std::vector listdir(const std::string&); 43 | static bool isdir(const std::string&); 44 | static bool isfile(const std::string&); 45 | static bool exists(const std::string&); 46 | 47 | // chdir 48 | static int cd(const std::string&); 49 | 50 | static void makedirs(const std::string&); 51 | static void rmtree(const std::string&); 52 | 53 | /* 54 | for (auto p : walk(path)) 55 | { 56 | std::cout<< std::get<0>(p) <(p)) 58 | { 59 | std::cout<< folder <(p)) 62 | { 63 | std::cout<< file < folders, std::vector files){ 71 | std::cout<< root < folders, std::vector files)>); 83 | }; 84 | } 85 | 86 | #endif /* defined(__ftxpath__ftxpath__) */ 87 | -------------------------------------------------------------------------------- /src/split.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // split.cpp 3 | // libpath 4 | // 5 | // Created by 王晓辰 on 15/8/9. 6 | // Copyright (c) 2015年 ftxtool. All rights reserved. 7 | // 8 | 9 | #include "split.h" 10 | 11 | #include 12 | 13 | 14 | 15 | std::vector &ftx::_split(const std::string &s, char delim, std::vector &elems) { 16 | std::stringstream ss(s); 17 | std::string item; 18 | while (std::getline(ss, item, delim)) { 19 | /*if(!item.empty())*/ elems.push_back(item); 20 | } 21 | return elems; 22 | } 23 | 24 | 25 | std::vector ftx::_split(const std::string &s, char delim) { 26 | std::vector elems; 27 | _split(s, delim, elems); 28 | return elems; 29 | } -------------------------------------------------------------------------------- /src/split.h: -------------------------------------------------------------------------------- 1 | // 2 | // split.h 3 | // libpath 4 | // 5 | // Created by 王晓辰 on 15/8/9. 6 | // Copyright (c) 2015年 ftxtool. All rights reserved. 7 | // 8 | 9 | #ifndef libpath_split_h 10 | #define libpath_split_h 11 | 12 | #include 13 | #include 14 | 15 | namespace ftx 16 | { 17 | std::vector &_split(const std::string &s, char delim, std::vector &elems); 18 | std::vector _split(const std::string &s, char delim); 19 | } 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(SOURCE_FILES 3 | main.cpp 4 | tester.h 5 | test_cwd.cpp 6 | test_cwd.h 7 | test_isabs.cpp 8 | test_isabs.h 9 | test_join.cpp 10 | test_join.h 11 | test_basename.cpp 12 | test_basename.h 13 | test_dirname.cpp 14 | test_dirname.h 15 | test_split.cpp 16 | test_split.h 17 | test_normpath.cpp 18 | test_normpath.h 19 | test_abspath.cpp 20 | test_abspath.h 21 | test_relpath.cpp 22 | test_relpath.h 23 | test_listdir.cpp 24 | test_listdir.h 25 | test_isdir.cpp 26 | test_isdir.h 27 | test_isfile.cpp 28 | test_isfile.h 29 | test_walk.cpp 30 | test_walk.h 31 | test_exists.cpp 32 | test_exists.h 33 | test_commonprefix.cpp 34 | test_commonprefix.h 35 | test_splitext.cpp 36 | test_splitext.h 37 | test_splitdrive.cpp 38 | test_splitdrive.h 39 | test_chdir.cpp 40 | test_chdir.h 41 | test_makedirs.cpp 42 | test_makedirs.h 43 | test_rmtree.cpp 44 | test_rmtree.h) 45 | 46 | include_directories(../src) 47 | 48 | link_directories(../bin) 49 | 50 | add_executable(ftxpathtest ${SOURCE_FILES}) 51 | 52 | target_link_libraries(ftxpathtest ftxpath) 53 | 54 | add_test(test_run ftxpathtest run) 55 | add_test(test_cwd ftxpathtest cwd) 56 | add_test(test_isabs ftxpathtest isabs) 57 | add_test(test_join ftxpathtest join) 58 | add_test(test_basename ftxpathtest basename) 59 | add_test(test_dirname ftxpathtest dirname) 60 | add_test(test_split ftxpathtest split) 61 | add_test(test_normpath ftxpathtest normpath) 62 | add_test(test_abspath ftxpathtest abspath) 63 | add_test(test_relpath ftxpathtest relpath) 64 | add_test(test_listdir ftxpathtest listdir) 65 | add_test(test_isdir ftxpathtest isdir) 66 | add_test(test_isfile ftxpathtest isfile) 67 | add_test(test_walk ftxpathtest walk) 68 | add_test(test_exists ftxpathtest exists) 69 | add_test(test_commonprefix ftxpathtest commonprefix) 70 | add_test(test_splitext ftxpathtest splitext) 71 | add_test(test_splitdrive ftxpathtest splitdrive) 72 | add_test(test_chdir ftxpathtest chdir) 73 | add_test(test_makedirs ftxpathtest makedirs) 74 | add_test(test_rmtree ftxpathtest rmtree) -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/1. 3 | // 4 | 5 | #include "tester.h" 6 | 7 | #include "test_cwd.h" 8 | #include "test_isabs.h" 9 | #include "test_join.h" 10 | #include "test_basename.h" 11 | #include "test_dirname.h" 12 | #include "test_split.h" 13 | #include "test_normpath.h" 14 | #include "test_abspath.h" 15 | #include "test_relpath.h" 16 | #include "test_listdir.h" 17 | #include "test_isdir.h" 18 | #include "test_isfile.h" 19 | #include "test_walk.h" 20 | #include "test_exists.h" 21 | #include "test_commonprefix.h" 22 | #include "test_splitext.h" 23 | #include "test_splitdrive.h" 24 | #include "test_chdir.h" 25 | #include "test_makedirs.h" 26 | #include "test_rmtree.h" 27 | 28 | 29 | int main(int argc, char* argv[]) 30 | { 31 | if (argc < 2) 32 | { 33 | return 1; 34 | } 35 | 36 | CASE_ONE_TEST_BY_ARGV1("cwd", test_cwd()); 37 | CASE_ONE_TEST_BY_ARGV1("isabs", test_isabs()); 38 | CASE_ONE_TEST_BY_ARGV1("join", test_join()); 39 | CASE_ONE_TEST_BY_ARGV1("basename", test_basename()); 40 | CASE_ONE_TEST_BY_ARGV1("dirname", test_dirname()); 41 | CASE_ONE_TEST_BY_ARGV1("splitext", test_splitext()); 42 | CASE_ONE_TEST_BY_ARGV1("splitdrive", test_splitdrive()); 43 | CASE_ONE_TEST_BY_ARGV1("split", test_split()); 44 | CASE_ONE_TEST_BY_ARGV1("normpath", test_normpath()); 45 | CASE_ONE_TEST_BY_ARGV1("abspath", test_abspath()); 46 | CASE_ONE_TEST_BY_ARGV1("relpath", test_relpath()); 47 | CASE_ONE_TEST_BY_ARGV1("listdir", test_listdir()); 48 | CASE_ONE_TEST_BY_ARGV1("isdir", test_isdir()); 49 | CASE_ONE_TEST_BY_ARGV1("isfile", test_isfile()); 50 | CASE_ONE_TEST_BY_ARGV1("walk", test_walk()); 51 | CASE_ONE_TEST_BY_ARGV1("exists", test_exists()); 52 | CASE_ONE_TEST_BY_ARGV1("commonprefix", test_commonprefix()); 53 | CASE_ONE_TEST_BY_ARGV1("chdir", test_chdir()); 54 | CASE_ONE_TEST_BY_ARGV1("makedirs", test_makedirs()); 55 | CASE_ONE_TEST_BY_ARGV1("rmtree", test_rmtree()); 56 | 57 | return 0; 58 | } -------------------------------------------------------------------------------- /test/test_abspath.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #include "test_abspath.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool test_abspath_absolute() 11 | { 12 | std::string abspath = "/a/b/c"; 13 | 14 | #ifdef WIN32 15 | abspath = "c:\\a\\b\\c"; 16 | #endif 17 | 18 | return abspath == ftx::path::abspath(abspath); 19 | } 20 | 21 | bool test_abspath_relative() 22 | { 23 | std::string relpath = "a/b/c"; 24 | 25 | #ifdef WIN32 26 | relpath = "a\\b\\c"; 27 | #endif 28 | 29 | std::string curpath = ftx::path::cwd(); 30 | std::string abspath = ftx::path::join(curpath, relpath); 31 | 32 | return abspath == ftx::path::abspath(relpath); 33 | } 34 | 35 | bool test_abspath() { 36 | 37 | LOG_TEST_STRING(""); 38 | 39 | TEST_BOOL_TO_BOOL(test_abspath_absolute(), "test absolute path error"); 40 | 41 | TEST_BOOL_TO_BOOL(test_abspath_relative(), "test relative path error"); 42 | 43 | return true; 44 | } 45 | -------------------------------------------------------------------------------- /test/test_abspath.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #ifndef ftxpath_ABSPATH_H 6 | #define ftxpath_ABSPATH_H 7 | 8 | bool test_abspath(); 9 | 10 | #endif //ftxpath_ABSPATH_H 11 | -------------------------------------------------------------------------------- /test/test_basename.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #include "test_basename.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool test_basename_dir() 11 | { 12 | std::string path = "dir1/dir2/dir3"; 13 | std::string basename = "dir3"; 14 | 15 | return basename == ftx::path::basename(path); 16 | } 17 | 18 | bool test_basename_file() 19 | { 20 | std::string filepath = "a.txt"; 21 | std::string basename = "a.txt"; 22 | 23 | return basename == ftx::path::basename(filepath); 24 | } 25 | 26 | bool test_basename_folder() 27 | { 28 | std::string folderpath = "dir1/dir2/folder/"; 29 | std::string folderbasename = ""; 30 | 31 | return folderbasename == ftx::path::basename(folderpath); 32 | } 33 | 34 | bool test_basename() { 35 | 36 | LOG_TEST_STRING("") 37 | 38 | TEST_BOOL_TO_BOOL(test_basename_dir(), "dir basename failed"); 39 | 40 | TEST_BOOL_TO_BOOL(test_basename_file(), "file path basename failed"); 41 | 42 | TEST_BOOL_TO_BOOL(test_basename_folder(), "folder path basename failed"); 43 | 44 | return true; 45 | } 46 | -------------------------------------------------------------------------------- /test/test_basename.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #ifndef ftxpath_TEST_BASENAME_H 6 | #define ftxpath_TEST_BASENAME_H 7 | 8 | bool test_basename(); 9 | 10 | #endif //ftxpath_TEST_BASENAME_H 11 | -------------------------------------------------------------------------------- /test/test_chdir.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/7. 3 | // 4 | 5 | #include "test_chdir.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool test_chdir_relpath() 11 | { 12 | std::string path = "../test/testlistdir"; 13 | ftx::path::cd(path); 14 | 15 | return ftx::path::exists("dir1"); 16 | } 17 | 18 | bool test_chdir_abspath() 19 | { 20 | std::string path = "../test/testlistdir"; 21 | std::string abspath = ftx::path::join(ftx::path::cwd(), path); 22 | ftx::path::cd(abspath); 23 | 24 | return ftx::path::exists("dir1"); 25 | } 26 | 27 | bool test_chdir_notdir() 28 | { 29 | std::string path = "../test/testlistdir/file1"; 30 | 31 | return ftx::path::cd(path) != 0; 32 | } 33 | 34 | bool test_chdir() { 35 | LOG_TEST_STRING(""); 36 | 37 | std::string cwd = ftx::path::cwd(); 38 | 39 | TEST_BOOL_TO_BOOL(test_chdir_relpath(), "test chdir by relpath error"); 40 | chdir(cwd.c_str()); 41 | 42 | TEST_BOOL_TO_BOOL(test_chdir_abspath(), "test chdir by abspath error"); 43 | chdir(cwd.c_str()); 44 | 45 | TEST_BOOL_TO_BOOL(test_chdir_notdir(), "test chdir not dir error"); 46 | chdir(cwd.c_str()); 47 | return true; 48 | } 49 | -------------------------------------------------------------------------------- /test/test_chdir.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/7. 3 | // 4 | 5 | #ifndef ftxpath_TEST_CHDIR_H 6 | #define ftxpath_TEST_CHDIR_H 7 | 8 | bool test_chdir(); 9 | 10 | #endif //ftxpath_TEST_CHDIR_H 11 | -------------------------------------------------------------------------------- /test/test_commonprefix.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/3. 3 | // 4 | 5 | #include "test_commonprefix.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool test_commonprefix_exists() 11 | { 12 | std::string curpath = ftx::path::cwd(); 13 | std::string path1 = ftx::path::join(curpath, "../test/testlistdir/dir1"); 14 | std::string path2 = ftx::path::join(curpath, "../test/testlistdir/dir2"); 15 | 16 | std::string common = ftx::path::join(curpath, "../test/testlistdir"); 17 | 18 | return (ftx::path::normpath(common) == ftx::path::commonprefix(path1, path2)); 19 | } 20 | 21 | bool test_commonprefix_not_exists() 22 | { 23 | std::string curpath = ftx::path::cwd(); 24 | 25 | std::string path1 = ""; 26 | std::string path2 = ftx::path::join(curpath, "../test"); 27 | std::string path3 = "../test/testlistdir"; 28 | 29 | return ftx::path::commonprefix({ path1, path2, path3 }).empty(); 30 | } 31 | 32 | bool test_commonprefix_multipath() 33 | { 34 | std::string curpath = ftx::path::cwd(); 35 | std::string path1 = ftx::path::join(curpath, "../test/testlistdir/dir1"); 36 | std::string path2 = ftx::path::join(curpath, "../test/testlistdir/dir2"); 37 | std::string path3 = "../test/testlistdir/file1"; 38 | std::string path4 = "../test/testlistdir/file2"; 39 | 40 | std::string common = ftx::path::join(curpath, "../test/testlistdir"); 41 | 42 | return (ftx::path::normpath(common) == ftx::path::commonprefix({ path1, path2, path3, path4 })); 43 | } 44 | 45 | bool test_commonprefix() { 46 | 47 | LOG_TEST_STRING(""); 48 | 49 | TEST_BOOL_TO_BOOL(test_commonprefix_exists(), "common path error"); 50 | 51 | TEST_BOOL_TO_BOOL(test_commonprefix_not_exists(), "common path not exists error"); 52 | 53 | TEST_BOOL_TO_BOOL(test_commonprefix_multipath(), "common path multi path error"); 54 | 55 | return true; 56 | } 57 | -------------------------------------------------------------------------------- /test/test_commonprefix.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/3. 3 | // 4 | 5 | #ifndef ftxpath_TEST_COMMONPREFIX_H 6 | #define ftxpath_TEST_COMMONPREFIX_H 7 | 8 | bool test_commonprefix(); 9 | 10 | #endif //ftxpath_TEST_COMMONPREFIX_H 11 | -------------------------------------------------------------------------------- /test/test_cwd.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/1. 3 | // 4 | 5 | #include "test_cwd.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | #include 11 | 12 | std::string mycwd() 13 | { 14 | char* buff = nullptr; 15 | buff = getcwd(nullptr, 0); 16 | 17 | std::string path(buff); 18 | 19 | if (buff != nullptr) 20 | { 21 | free(buff); 22 | } 23 | 24 | return path; 25 | } 26 | 27 | bool test_cwd_isdir(std::string path) 28 | { 29 | struct stat buf; 30 | return stat(path.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode); 31 | } 32 | 33 | bool test_cwd() { 34 | std::string str_cwd = ftx::path::cwd(); 35 | 36 | LOG_TEST_STRING(str_cwd); 37 | 38 | TEST_BOOL_TO_BOOL(!str_cwd.empty(), "cwd empty"); 39 | 40 | TEST_BOOL_TO_BOOL((mycwd() == str_cwd), "cwd path error"); 41 | 42 | TEST_BOOL_TO_BOOL(test_cwd_isdir(str_cwd), "cwd not dir"); 43 | 44 | 45 | return true; 46 | } 47 | -------------------------------------------------------------------------------- /test/test_cwd.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/1. 3 | // 4 | 5 | #ifndef ftxpath_TEST_CWD_H 6 | #define ftxpath_TEST_CWD_H 7 | 8 | bool test_cwd(); 9 | 10 | #endif //ftxpath_TEST_CWD_H -------------------------------------------------------------------------------- /test/test_dirname.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #include "test_dirname.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool test_dirname_path() 11 | { 12 | std::string path = "/a/b/c/d"; 13 | std::string dirname = "/a/b/c"; 14 | 15 | return dirname == ftx::path::dirname(path); 16 | } 17 | 18 | bool test_dirname_onename() 19 | { 20 | std::string name = "name"; 21 | return ftx::path::dirname(name).empty(); 22 | } 23 | 24 | bool test_dirname_filepath() 25 | { 26 | std::string filepath = "a/b/c/d.txt"; 27 | std::string dirname = "a/b/c"; 28 | 29 | return dirname == ftx::path::dirname(filepath); 30 | } 31 | 32 | bool test_dirname_folderpath() 33 | { 34 | std::string folderpath = "a/b/c/folder/"; 35 | std::string dirname = "a/b/c/folder"; 36 | 37 | return dirname == ftx::path::dirname(folderpath); 38 | } 39 | 40 | bool test_dirname_root() 41 | { 42 | std::string root = "/"; 43 | 44 | return root == ftx::path::dirname(root); 45 | } 46 | 47 | bool test_dirname() { 48 | 49 | LOG_TEST_STRING(""); 50 | 51 | TEST_BOOL_TO_BOOL(test_dirname_path(), "dir dirname failed"); 52 | 53 | TEST_BOOL_TO_BOOL(test_dirname_onename(), "one name dirname failed"); 54 | 55 | TEST_BOOL_TO_BOOL(test_dirname_filepath(), "file path dirname failed"); 56 | 57 | TEST_BOOL_TO_BOOL(test_dirname_folderpath(), "folder path dirname failed"); 58 | 59 | TEST_BOOL_TO_BOOL(test_dirname_root(), "root dirname failed"); 60 | 61 | return true; 62 | } 63 | -------------------------------------------------------------------------------- /test/test_dirname.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #ifndef ftxpath_TEST_DIRNAME_H 6 | #define ftxpath_TEST_DIRNAME_H 7 | 8 | bool test_dirname(); 9 | 10 | #endif //ftxpath_TEST_DIRNAME_H 11 | -------------------------------------------------------------------------------- /test/test_exists.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #include "test_exists.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool test_exists_check() 11 | { 12 | std::string path = "../test/testlistdir"; 13 | return ftx::path::exists(path); 14 | } 15 | 16 | bool test_exists_check_not() 17 | { 18 | std::string path = "asdffds"; 19 | return !ftx::path::exists(path); 20 | } 21 | 22 | bool test_exists() { 23 | 24 | LOG_TEST_STRING(""); 25 | 26 | TEST_BOOL_TO_BOOL(test_exists_check(), "exists check error, is exists"); 27 | 28 | TEST_BOOL_TO_BOOL(test_exists_check_not(), "exists checknot error, is not exists"); 29 | 30 | return true; 31 | } 32 | -------------------------------------------------------------------------------- /test/test_exists.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #ifndef ftxpath_TEST_EXISTS_H 6 | #define ftxpath_TEST_EXISTS_H 7 | 8 | bool test_exists(); 9 | 10 | #endif //ftxpath_TEST_EXISTS_H 11 | -------------------------------------------------------------------------------- /test/test_isabs.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/1. 3 | // 4 | 5 | #include "test_isabs.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool test_isabs_check_abspath() 11 | { 12 | std::string abspath = "/a/b/c"; 13 | #ifdef WIN32 14 | abspath = "c:\\a\\b\\c"; 15 | #endif 16 | return ftx::path::isabs(abspath); 17 | } 18 | 19 | bool test_isabs_check_relpath() 20 | { 21 | std::string relpath = "../a/b/c"; 22 | return !ftx::path::isabs(relpath); 23 | } 24 | 25 | bool test_isabs() { 26 | 27 | LOG_TEST_STRING(""); 28 | 29 | TEST_BOOL_TO_BOOL(test_isabs_check_abspath(), "is abspath but return false"); 30 | 31 | TEST_BOOL_TO_BOOL(test_isabs_check_relpath(), "is relpath but reutrn true"); 32 | 33 | return true; 34 | } 35 | -------------------------------------------------------------------------------- /test/test_isabs.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/1. 3 | // 4 | 5 | #ifndef ftxpath_TEST_ISABS_H 6 | #define ftxpath_TEST_ISABS_H 7 | 8 | bool test_isabs(); 9 | 10 | #endif //ftxpath_TEST_ISABS_H 11 | -------------------------------------------------------------------------------- /test/test_isdir.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #include "test_isdir.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool test_isdir_dir() 11 | { 12 | std::string path = "../test/testlistdir"; 13 | return ftx::path::isdir(path); 14 | } 15 | 16 | bool test_isdir_file() 17 | { 18 | std::string path = "../test/testlistdir/file1"; 19 | return !ftx::path::isdir(path); 20 | } 21 | 22 | bool test_isdir_ghost() 23 | { 24 | std::string path = "asdfgh"; 25 | return !ftx::path::isdir(path); 26 | } 27 | 28 | bool test_isdir() { 29 | 30 | LOG_TEST_STRING("") 31 | 32 | TEST_BOOL_TO_BOOL(test_isdir_dir(), "return is not dir but it is"); 33 | 34 | TEST_BOOL_TO_BOOL(test_isdir_file(), "return is dir but it is not"); 35 | 36 | TEST_BOOL_TO_BOOL(test_isdir_ghost(), "test is dir error"); 37 | 38 | return true; 39 | } 40 | -------------------------------------------------------------------------------- /test/test_isdir.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #ifndef ftxpath_TEST_ISDIR_H 6 | #define ftxpath_TEST_ISDIR_H 7 | 8 | bool test_isdir(); 9 | 10 | #endif //ftxpath_TEST_ISDIR_H 11 | -------------------------------------------------------------------------------- /test/test_isfile.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #include "test_isfile.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool test_isfile_file() 11 | { 12 | std::string path = "../test/testlistdir/file1"; 13 | return ftx::path::isfile(path); 14 | } 15 | 16 | bool test_isfile_dir() 17 | { 18 | std::string path = "../test/testlistdir"; 19 | return !ftx::path::isfile(path); 20 | } 21 | 22 | bool test_isfile_ghost() 23 | { 24 | std::string path = "asdfgh"; 25 | return !ftx::path::isfile(path); 26 | } 27 | 28 | bool test_isfile() { 29 | 30 | LOG_TEST_STRING(""); 31 | 32 | TEST_BOOL_TO_BOOL(test_isfile_file(), "return is not file but it is"); 33 | 34 | TEST_BOOL_TO_BOOL(test_isfile_dir(), "return is file but it is not"); 35 | 36 | TEST_BOOL_TO_BOOL(test_isfile_ghost(), "test is file error"); 37 | 38 | return true; 39 | } 40 | -------------------------------------------------------------------------------- /test/test_isfile.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #ifndef ftxpath_TEST_ISFILE_H 6 | #define ftxpath_TEST_ISFILE_H 7 | 8 | bool test_isfile(); 9 | 10 | #endif //ftxpath_TEST_ISFILE_H 11 | -------------------------------------------------------------------------------- /test/test_join.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #include "test_join.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool join_string() 11 | { 12 | std::string result = ftx::path::join("dir1", "dir2"); 13 | std::string right_res = "dir1/dir2"; 14 | 15 | #ifdef WIN32 16 | right_res = "dir1\\dir2"; 17 | #endif 18 | 19 | std::cout<< "join str & str result: " << result < 8 | #include "tester.h" 9 | 10 | #include 11 | 12 | bool test_listdir_check() 13 | { 14 | std::string dirpath = "../test/testlistdir"; 15 | 16 | std::set right_set = {"dir1", "dir2", "file1", "file2"}; 17 | std::vector path_list = ftx::path::listdir(dirpath); 18 | 19 | for (auto node : path_list) 20 | { 21 | if (node != ".DS_Store" && right_set.find(node) == right_set.end()) 22 | { 23 | std::cout<< "listdir ***** " << node < 8 | #include "tester.h" 9 | 10 | bool test_makedirs_one() 11 | { 12 | std::string path = "../test/testmakedirs"; 13 | ftx::path::makedirs(path); 14 | 15 | bool result = ftx::path::isdir(path); 16 | 17 | rmdir(path.c_str()); 18 | 19 | return result; 20 | } 21 | 22 | bool test_makedirs_multi() 23 | { 24 | std::string path = "../test/testmakedirs/dir1/dir2"; 25 | std::string dir1 = "../test/testmakedirs"; 26 | std::string dir2 = "../test/testmakedirs/dir1"; 27 | std::string dir3 = "../test/testmakedirs/dir1/dir2"; 28 | 29 | ftx::path::makedirs(path); 30 | 31 | bool res1 = ftx::path::isdir(dir1); 32 | bool res2 = ftx::path::isdir(dir2); 33 | bool res3 = ftx::path::isdir(dir3); 34 | 35 | if (res3) 36 | { 37 | rmdir(dir3.c_str()); 38 | } 39 | if (res2) 40 | { 41 | rmdir(dir2.c_str()); 42 | } 43 | if (res1) 44 | { 45 | rmdir(dir1.c_str()); 46 | } 47 | 48 | return (res1 && res2 && res3); 49 | } 50 | 51 | bool test_makedirs() { 52 | LOG_TEST_STRING(""); 53 | 54 | TEST_BOOL_TO_BOOL(test_makedirs_one(), "test makedirs one dir failed"); 55 | 56 | TEST_BOOL_TO_BOOL(test_makedirs_multi(), "test makedirs multi dir failed"); 57 | 58 | return true; 59 | } 60 | -------------------------------------------------------------------------------- /test/test_makedirs.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/7. 3 | // 4 | 5 | #ifndef ftxpath_TEST_MAKEDIRS_H 6 | #define ftxpath_TEST_MAKEDIRS_H 7 | 8 | bool test_makedirs(); 9 | 10 | #endif //ftxpath_TEST_MAKEDIRS_H 11 | -------------------------------------------------------------------------------- /test/test_normpath.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #include "test_normpath.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool test_normpath_normal() 11 | { 12 | std::string path = "/a/b/c"; 13 | 14 | #ifdef WIN32 15 | path = "c:\\a\\b\\c"; 16 | #endif 17 | 18 | return path == ftx::path::normpath(path); 19 | } 20 | 21 | bool test_normpath_pardir() 22 | { 23 | std::string path = "../a/b/c/../.."; 24 | std::string normpath = "../a"; 25 | 26 | #ifdef WIN32 27 | normpath = "..\\a"; 28 | #endif 29 | 30 | return normpath == ftx::path::normpath(path); 31 | } 32 | 33 | bool test_normpath_curdir() 34 | { 35 | std::string path = "./a/b"; 36 | std::string normpath = "a/b"; 37 | 38 | #ifdef WIN32 39 | normpath = "a\\b"; 40 | #endif 41 | 42 | return normpath == ftx::path::normpath(path); 43 | } 44 | 45 | bool test_normpath() { 46 | 47 | LOG_TEST_STRING(""); 48 | 49 | TEST_BOOL_TO_BOOL(test_normpath_normal(), "normal path error"); 50 | 51 | TEST_BOOL_TO_BOOL(test_normpath_pardir(), "pardir path normal path error"); 52 | 53 | TEST_BOOL_TO_BOOL(test_normpath_curdir(), "curdir path normal path error"); 54 | 55 | return true; 56 | } 57 | -------------------------------------------------------------------------------- /test/test_normpath.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #ifndef ftxpath_TEST_NORMPATH_H 6 | #define ftxpath_TEST_NORMPATH_H 7 | 8 | bool test_normpath(); 9 | 10 | #endif //ftxpath_TEST_NORMPATH_H 11 | -------------------------------------------------------------------------------- /test/test_relpath.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #include "test_relpath.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool test_relpath_relative() 11 | { 12 | std::string relpath = "a/b/c"; 13 | 14 | #ifdef WIN32 15 | relpath = "a\\b\\c"; 16 | #endif 17 | 18 | return relpath == ftx::path::relpath(relpath); 19 | } 20 | 21 | bool test_relpath_relative_start() 22 | { 23 | std::string relpath = "a/b/c"; 24 | std::string startpath = "a/b"; 25 | std::string result = ftx::path::relpath(relpath, startpath); 26 | 27 | std::string right_res = "c"; 28 | 29 | return right_res == result; 30 | } 31 | 32 | bool test_relpath_absolute_start() 33 | { 34 | std::string relpath = "a/b/c"; 35 | std::string startpath = "/a/b"; 36 | 37 | #ifdef WIN32 38 | startpath = "\\a\\b"; 39 | #endif 40 | 41 | std::string result = ftx::path::relpath(relpath, startpath); 42 | 43 | std::string curpath = ftx::path::cwd(); 44 | 45 | std::string right_res = "../.." + curpath + "/" + relpath; 46 | 47 | #ifdef WIN32 48 | std::tie(std::ignore, curpath) = ftx::path::splitdrive(curpath); 49 | right_res = "..\\.." + curpath + "\\" + relpath; 50 | right_res = ftx::path::normpath(right_res); 51 | #endif 52 | 53 | return right_res == result; 54 | } 55 | 56 | bool test_relpath() { 57 | 58 | LOG_TEST_STRING(""); 59 | 60 | TEST_BOOL_TO_BOOL(test_relpath_relative(), "test relative path error"); 61 | 62 | TEST_BOOL_TO_BOOL(test_relpath_relative_start(), "test relpath start relative path error"); 63 | 64 | TEST_BOOL_TO_BOOL(test_relpath_absolute_start(), "test relpath start absolute path error"); 65 | 66 | return true; 67 | } 68 | -------------------------------------------------------------------------------- /test/test_relpath.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #ifndef ftxpath_TEST_RELPATH_H 6 | #define ftxpath_TEST_RELPATH_H 7 | 8 | bool test_relpath(); 9 | 10 | #endif //ftxpath_TEST_RELPATH_H 11 | -------------------------------------------------------------------------------- /test/test_rmtree.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/7. 3 | // 4 | 5 | #include "test_rmtree.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | void make_test_tree() 11 | { 12 | std::string path = "../test/testrmtree"; 13 | std::string tree_folder1 = "dir1/dir2/dir3"; 14 | std::string tree_folder2 = "dir1/dir4/dir5"; 15 | std::string tree_file1 = "file1"; 16 | std::string tree_file2 = "dir1/dir2/file2"; 17 | std::string tree_file3 = "dir1/dir2/file3"; 18 | std::string tree_file4 = "dir1/dir2/file4"; 19 | std::string tree_file5 = "dir1/dir2/dir3/file5"; 20 | std::string tree_file6 = "file6"; 21 | 22 | ftx::path::makedirs(ftx::path::join(path, tree_folder1)); 23 | ftx::path::makedirs(ftx::path::join(path, tree_folder2)); 24 | 25 | FILE* fp = fopen(ftx::path::join(path, tree_file1).c_str(), "w"); 26 | fclose(fp); 27 | fp = fopen(ftx::path::join(path, tree_file2).c_str(), "w"); 28 | fclose(fp); 29 | fp = fopen(ftx::path::join(path, tree_file3).c_str(), "w"); 30 | fclose(fp); 31 | fp = fopen(ftx::path::join(path, tree_file4).c_str(), "w"); 32 | fclose(fp); 33 | fp = fopen(ftx::path::join(path, tree_file5).c_str(), "w"); 34 | fclose(fp); 35 | fp = fopen(ftx::path::join(path, tree_file6).c_str(), "w"); 36 | fclose(fp); 37 | } 38 | 39 | bool test_rmtree_check_make_tree() 40 | { 41 | std::string path = "../test/testrmtree"; 42 | return ftx::path::isdir(path); 43 | } 44 | 45 | bool test_rmtree_one_file() 46 | { 47 | std::string path = "../test/testrmtree/file6"; 48 | ftx::path::rmtree(path); 49 | 50 | return !ftx::path::exists(path); 51 | } 52 | 53 | bool test_rmtree_normal() 54 | { 55 | std::string path = "../test/testrmtree"; 56 | 57 | ftx::path::rmtree(path); 58 | 59 | return !ftx::path::exists(path); 60 | } 61 | 62 | bool test_rmtree() { 63 | LOG_TEST_STRING(""); 64 | 65 | make_test_tree(); 66 | 67 | TEST_BOOL_TO_BOOL(test_rmtree_check_make_tree(), "make test tree failed"); 68 | 69 | TEST_BOOL_TO_BOOL(test_rmtree_one_file(), "test rmtree one file error"); 70 | 71 | TEST_BOOL_TO_BOOL(test_rmtree_normal(), "test rmtree normal error"); 72 | 73 | return true; 74 | } 75 | -------------------------------------------------------------------------------- /test/test_rmtree.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/7. 3 | // 4 | 5 | #ifndef ftxpath_TEST_RMTREE_H 6 | #define ftxpath_TEST_RMTREE_H 7 | 8 | bool test_rmtree(); 9 | 10 | #endif //ftxpath_TEST_RMTREE_H 11 | -------------------------------------------------------------------------------- /test/test_split.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #include "test_split.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool test_split_path() 11 | { 12 | std::string path = "/a/b/c"; 13 | std::string res1 = "/a/b"; 14 | std::string res2 = "c"; 15 | 16 | auto tuple = ftx::path::split(path); 17 | 18 | return res1 == std::get<0>(tuple) && res2 == std::get<1>(tuple); 19 | } 20 | 21 | bool test_split_onename() 22 | { 23 | std::string name = "name"; 24 | 25 | auto tuple = ftx::path::split(name); 26 | 27 | return std::get<0>(tuple).empty() && name == std::get<1>(tuple); 28 | } 29 | 30 | bool test_split_folderpath() 31 | { 32 | std::string folderpath = "a/b/c/"; 33 | std::string basename = "a/b/c"; 34 | 35 | auto tuple = ftx::path::split(folderpath); 36 | 37 | return basename == std::get<0>(tuple) && std::get<1>(tuple).empty(); 38 | } 39 | 40 | bool test_split_root() 41 | { 42 | std::string root = "/"; 43 | 44 | auto tuple = ftx::path::split(root); 45 | 46 | return root == std::get<0>(tuple) && std::get<1>(tuple).empty(); 47 | } 48 | 49 | bool test_split() { 50 | 51 | LOG_TEST_STRING("") 52 | 53 | TEST_BOOL_TO_BOOL(test_split_path(), "split path failed"); 54 | 55 | TEST_BOOL_TO_BOOL(test_split_onename(), "split one name failed"); 56 | 57 | TEST_BOOL_TO_BOOL(test_split_folderpath(), "split folder path failed"); 58 | 59 | TEST_BOOL_TO_BOOL(test_split_root(), "split root failed"); 60 | 61 | return true; 62 | } 63 | -------------------------------------------------------------------------------- /test/test_split.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #ifndef ftxpath_TEST_SPLIT_H 6 | #define ftxpath_TEST_SPLIT_H 7 | 8 | bool test_split(); 9 | 10 | #endif //ftxpath_TEST_SPLIT_H 11 | -------------------------------------------------------------------------------- /test/test_splitdrive.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 16/2/6. 3 | // 4 | 5 | #include "test_splitdrive.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | 11 | bool test_splitdrive_normal() 12 | { 13 | std::string path = "c:/a/b"; 14 | std::string head = "c:"; 15 | std::string tail = "/a/b"; 16 | 17 | auto tuple = ftx::path::splitdrive(path); 18 | 19 | std::cout << std::get<0>(tuple) << "\n" << std::get<1>(tuple) << std::endl; 20 | 21 | #ifdef WIN32 22 | return head == std::get<0>(tuple) && tail == std::get<1>(tuple); 23 | #else 24 | return "" == std::get<0>(tuple) && path == std::get<1>(tuple); 25 | #endif 26 | } 27 | 28 | bool test_splitdrive_unc() 29 | { 30 | std::string path = "//machine/share/a/b/c"; 31 | std::string head = "//machine/share"; 32 | std::string tail = "/a/b/c"; 33 | 34 | auto tuple = ftx::path::splitdrive(path); 35 | 36 | std::cout << std::get<0>(tuple) << "\n" << std::get<1>(tuple) << std::endl; 37 | 38 | #ifdef WIN32 39 | return head == std::get<0>(tuple) && tail == std::get<1>(tuple); 40 | #else 41 | return "" == std::get<0>(tuple) && path == std::get<1>(tuple); 42 | #endif 43 | } 44 | 45 | bool test_splitdrive_root() 46 | { 47 | std::string path = "/"; 48 | 49 | auto tuple = ftx::path::splitdrive(path); 50 | 51 | return "" == std::get<0>(tuple) && path == std::get<1>(tuple); 52 | } 53 | 54 | bool test_splitdrive_slash() 55 | { 56 | std::string path = "\\\\\\"; 57 | 58 | auto tuple = ftx::path::splitdrive(path); 59 | 60 | return "" == std::get<0>(tuple) && path == std::get<1>(tuple); 61 | } 62 | 63 | bool test_splitdrive() { 64 | 65 | LOG_TEST_STRING(""); 66 | 67 | TEST_BOOL_TO_BOOL(test_splitdrive_normal(), "test splitdrive normal case failed"); 68 | 69 | TEST_BOOL_TO_BOOL(test_splitdrive_unc(), "test splitdrive unc format case failed"); 70 | 71 | TEST_BOOL_TO_BOOL(test_splitdrive_root(), "test splitdrive root case failed"); 72 | 73 | TEST_BOOL_TO_BOOL(test_splitdrive_slash(), "test splitdrive slash case failed"); 74 | 75 | return true; 76 | } 77 | -------------------------------------------------------------------------------- /test/test_splitdrive.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 16/2/6. 3 | // 4 | 5 | #ifndef ftxpath_TEST_SPLITDEIVE_H 6 | #define ftxpath_TEST_SPLITDEIVE_H 7 | 8 | bool test_splitdrive(); 9 | 10 | #endif //ftxpath_TEST_SPLITDEIVE_H 11 | -------------------------------------------------------------------------------- /test/test_splitext.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/3. 3 | // 4 | 5 | #include "test_splitext.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool test_splitext_normal() 11 | { 12 | std::string path = "/a/b/c/a.txt"; 13 | std::string root = "/a/b/c/a"; 14 | std::string ext = ".txt"; 15 | 16 | auto tuple = ftx::path::splitext(path); 17 | 18 | return root == std::get<0>(tuple) && ext == std::get<1>(tuple); 19 | } 20 | 21 | bool test_splitext_noext() 22 | { 23 | std::string path = "a/s/d/f/"; 24 | 25 | auto tuple = ftx::path::splitext(path); 26 | 27 | return path == std::get<0>(tuple) && std::get<1>(tuple).empty(); 28 | } 29 | 30 | bool test_splitext_onefile() 31 | { 32 | std::string path = "a.a.a"; 33 | std::string root = "a.a"; 34 | std::string ext = ".a"; 35 | 36 | auto tuple = ftx::path::splitext(path); 37 | 38 | return root == std::get<0>(tuple) && ext == std::get<1>(tuple); 39 | } 40 | 41 | bool test_splitext_hidefile() 42 | { 43 | std::string path = "a/b/.ext"; 44 | 45 | auto tuple = ftx::path::splitext(path); 46 | 47 | return path == std::get<0>(tuple) && std::get<1>(tuple).empty(); 48 | } 49 | 50 | bool test_splitext_multidot() 51 | { 52 | std::string path = "a.a/b.b.b/c.c.c/../a.b.b.b"; 53 | std::string root = "a.a/b.b.b/c.c.c/../a.b.b"; 54 | std::string ext = ".b"; 55 | 56 | auto tuple = ftx::path::splitext(path); 57 | 58 | return root == std::get<0>(tuple) && ext == std::get<1>(tuple); 59 | } 60 | 61 | bool test_splitext() { 62 | 63 | LOG_TEST_STRING(""); 64 | 65 | TEST_BOOL_TO_BOOL(test_splitext_normal(), "test splitext normal case failed"); 66 | 67 | TEST_BOOL_TO_BOOL(test_splitext_noext(), "test splitext no ext case failed"); 68 | 69 | TEST_BOOL_TO_BOOL(test_splitext_onefile(), "test splitext one file case failed"); 70 | 71 | TEST_BOOL_TO_BOOL(test_splitext_hidefile(), "test splitext hide file case failed"); 72 | 73 | TEST_BOOL_TO_BOOL(test_splitext_multidot(), "test splitext multi dot case failed"); 74 | 75 | return true; 76 | } 77 | -------------------------------------------------------------------------------- /test/test_splitext.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/3. 3 | // 4 | 5 | #ifndef ftxpath_TEST_SPLITEXT_H 6 | #define ftxpath_TEST_SPLITEXT_H 7 | 8 | bool test_splitext(); 9 | 10 | #endif //ftxpath_TEST_SPLITEXT_H 11 | -------------------------------------------------------------------------------- /test/test_walk.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 王晓辰 on 15/10/2. 3 | // 4 | 5 | #include "test_walk.h" 6 | 7 | #include 8 | #include "tester.h" 9 | 10 | bool test_walk_ghost() 11 | { 12 | std::string path = "asdfgh"; 13 | 14 | for (auto p : ftx::path::walk(path)) 15 | { 16 | if (!std::get<0>(p).empty()) 17 | { 18 | std::cout<< "walk ghost root not empty" <(p).empty()) 23 | { 24 | std::cout<< "walk ghost dirs not empty" <(p).empty()) 29 | { 30 | std::cout<< "walk ghost files not empty" <(p); 46 | if (root.empty()) 47 | { 48 | std::cout<< "walk check root empty" <(p); 58 | if (dirs.empty() && state == 0) 59 | { 60 | std::cout<< "walk check dirs empty" <(p)) 64 | { 65 | if (!ftx::path::isdir(ftx::path::join(root, dir))) 66 | { 67 | std::cout<< "walk check dir but not dir" <(p); 73 | if (files.empty()) 74 | { 75 | std::cout<< "walk check files empty" <(p)) 79 | { 80 | if (!ftx::path::isfile(ftx::path::join(root, file))) 81 | { 82 | std::cout<< "walk check file but not file" < 9 | #include 10 | #include 11 | 12 | #ifdef WIN32 13 | #include 14 | #endif 15 | 16 | #define TEST_BOOL_TO_BOOL(b, str) \ 17 | if (!b) \ 18 | { \ 19 | std::cout<< str <=): 66 | # ANDROID_NDK=/opt/android-ndk - path to the NDK root. 67 | # Can be set as environment variable. Can be set only at first cmake run. 68 | # 69 | # ANDROID_STANDALONE_TOOLCHAIN=/opt/android-toolchain - path to the 70 | # standalone toolchain. This option is not used if full NDK is found 71 | # (ignored if ANDROID_NDK is set). 72 | # Can be set as environment variable. Can be set only at first cmake run. 73 | # 74 | # ANDROID_ABI=armeabi-v7a - specifies the target Application Binary 75 | # Interface (ABI). This option nearly matches to the APP_ABI variable 76 | # used by ndk-build tool from Android NDK. 77 | # 78 | # Possible targets are: 79 | # "armeabi" - matches to the NDK ABI with the same name. 80 | # See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. 81 | # "armeabi-v7a" - matches to the NDK ABI with the same name. 82 | # See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. 83 | # "armeabi-v7a with NEON" - same as armeabi-v7a, but 84 | # sets NEON as floating-point unit 85 | # "armeabi-v7a with VFPV3" - same as armeabi-v7a, but 86 | # sets VFPV3 as floating-point unit (has 32 registers instead of 16). 87 | # "armeabi-v6 with VFP" - tuned for ARMv6 processors having VFP. 88 | # "x86" - matches to the NDK ABI with the same name. 89 | # See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. 90 | # "mips" - matches to the NDK ABI with the same name. 91 | # See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation. 92 | # 93 | # ANDROID_NATIVE_API_LEVEL=android-8 - level of Android API compile for. 94 | # Option is read-only when standalone toolchain is used. 95 | # 96 | # ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.6 - the name of compiler 97 | # toolchain to be used. The list of possible values depends on the NDK 98 | # version. For NDK r8c the possible values are: 99 | # 100 | # * arm-linux-androideabi-4.4.3 101 | # * arm-linux-androideabi-4.6 102 | # * arm-linux-androideabi-clang3.1 103 | # * mipsel-linux-android-4.4.3 104 | # * mipsel-linux-android-4.6 105 | # * mipsel-linux-android-clang3.1 106 | # * x86-4.4.3 107 | # * x86-4.6 108 | # * x86-clang3.1 109 | # 110 | # ANDROID_FORCE_ARM_BUILD=OFF - set ON to generate 32-bit ARM instructions 111 | # instead of Thumb. Is not available for "x86" (inapplicable) and 112 | # "armeabi-v6 with VFP" (is forced to be ON) ABIs. 113 | # 114 | # ANDROID_NO_UNDEFINED=ON - set ON to show all undefined symbols as linker 115 | # errors even if they are not used. 116 | # 117 | # ANDROID_SO_UNDEFINED=OFF - set ON to allow undefined symbols in shared 118 | # libraries. Automatically turned for NDK r5x and r6x due to GLESv2 119 | # problems. 120 | # 121 | # LIBRARY_OUTPUT_PATH_ROOT=${CMAKE_SOURCE_DIR} - where to output binary 122 | # files. See additional details below. 123 | # 124 | # ANDROID_SET_OBSOLETE_VARIABLES=ON - if set, then toolchain defines some 125 | # obsolete variables which were used by previous versions of this file for 126 | # backward compatibility. 127 | # 128 | # ANDROID_STL=gnustl_static - specify the runtime to use. 129 | # 130 | # Possible values are: 131 | # none -> Do not configure the runtime. 132 | # system -> Use the default minimal system C++ runtime library. 133 | # Implies -fno-rtti -fno-exceptions. 134 | # Is not available for standalone toolchain. 135 | # system_re -> Use the default minimal system C++ runtime library. 136 | # Implies -frtti -fexceptions. 137 | # Is not available for standalone toolchain. 138 | # gabi++_static -> Use the GAbi++ runtime as a static library. 139 | # Implies -frtti -fno-exceptions. 140 | # Available for NDK r7 and newer. 141 | # Is not available for standalone toolchain. 142 | # gabi++_shared -> Use the GAbi++ runtime as a shared library. 143 | # Implies -frtti -fno-exceptions. 144 | # Available for NDK r7 and newer. 145 | # Is not available for standalone toolchain. 146 | # stlport_static -> Use the STLport runtime as a static library. 147 | # Implies -fno-rtti -fno-exceptions for NDK before r7. 148 | # Implies -frtti -fno-exceptions for NDK r7 and newer. 149 | # Is not available for standalone toolchain. 150 | # stlport_shared -> Use the STLport runtime as a shared library. 151 | # Implies -fno-rtti -fno-exceptions for NDK before r7. 152 | # Implies -frtti -fno-exceptions for NDK r7 and newer. 153 | # Is not available for standalone toolchain. 154 | # gnustl_static -> Use the GNU STL as a static library. 155 | # Implies -frtti -fexceptions. 156 | # gnustl_shared -> Use the GNU STL as a shared library. 157 | # Implies -frtti -fno-exceptions. 158 | # Available for NDK r7b and newer. 159 | # Silently degrades to gnustl_static if not available. 160 | # 161 | # ANDROID_STL_FORCE_FEATURES=ON - turn rtti and exceptions support based on 162 | # chosen runtime. If disabled, then the user is responsible for settings 163 | # these options. 164 | # 165 | # What?: 166 | # android-cmake toolchain searches for NDK/toolchain in the following order: 167 | # ANDROID_NDK - cmake parameter 168 | # ANDROID_NDK - environment variable 169 | # ANDROID_STANDALONE_TOOLCHAIN - cmake parameter 170 | # ANDROID_STANDALONE_TOOLCHAIN - environment variable 171 | # ANDROID_NDK - default locations 172 | # ANDROID_STANDALONE_TOOLCHAIN - default locations 173 | # 174 | # Make sure to do the following in your scripts: 175 | # SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}" ) 176 | # SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}" ) 177 | # The flags will be prepopulated with critical flags, so don't loose them. 178 | # Also be aware that toolchain also sets configuration-specific compiler 179 | # flags and linker flags. 180 | # 181 | # ANDROID and BUILD_ANDROID will be set to true, you may test any of these 182 | # variables to make necessary Android-specific configuration changes. 183 | # 184 | # Also ARMEABI or ARMEABI_V7A or X86 or MIPS will be set true, mutually 185 | # exclusive. NEON option will be set true if VFP is set to NEON. 186 | # 187 | # LIBRARY_OUTPUT_PATH_ROOT should be set in cache to determine where Android 188 | # libraries will be installed. 189 | # Default is ${CMAKE_SOURCE_DIR}, and the android libs will always be 190 | # under the ${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME} 191 | # (depending on the target ABI). This is convenient for Android packaging. 192 | # 193 | # Change Log: 194 | # - initial version December 2010 195 | # - April 2011 196 | # [+] added possibility to build with NDK (without standalone toolchain) 197 | # [+] support cross-compilation on Windows (native, no cygwin support) 198 | # [+] added compiler option to force "char" type to be signed 199 | # [+] added toolchain option to compile to 32-bit ARM instructions 200 | # [+] added toolchain option to disable SWIG search 201 | # [+] added platform "armeabi-v7a with VFPV3" 202 | # [~] ARM_TARGETS renamed to ARM_TARGET 203 | # [+] EXECUTABLE_OUTPUT_PATH is set by toolchain (required on Windows) 204 | # [~] Fixed bug with ANDROID_API_LEVEL variable 205 | # [~] turn off SWIG search if it is not found first time 206 | # - May 2011 207 | # [~] ANDROID_LEVEL is renamed to ANDROID_API_LEVEL 208 | # [+] ANDROID_API_LEVEL is detected by toolchain if not specified 209 | # [~] added guard to prevent changing of output directories on the first 210 | # cmake pass 211 | # [~] toolchain exits with error if ARM_TARGET is not recognized 212 | # - June 2011 213 | # [~] default NDK path is updated for version r5c 214 | # [+] variable CMAKE_SYSTEM_PROCESSOR is set based on ARM_TARGET 215 | # [~] toolchain install directory is added to linker paths 216 | # [-] removed SWIG-related stuff from toolchain 217 | # [+] added macro find_host_package, find_host_program to search 218 | # packages/programs on the host system 219 | # [~] fixed path to STL library 220 | # - July 2011 221 | # [~] fixed options caching 222 | # [~] search for all supported NDK versions 223 | # [~] allowed spaces in NDK path 224 | # - September 2011 225 | # [~] updated for NDK r6b 226 | # - November 2011 227 | # [*] rewritten for NDK r7 228 | # [+] x86 toolchain support (experimental) 229 | # [+] added "armeabi-v6 with VFP" ABI for ARMv6 processors. 230 | # [~] improved compiler and linker flags management 231 | # [+] support different build flags for Release and Debug configurations 232 | # [~] by default compiler flags the same as used by ndk-build (but only 233 | # where reasonable) 234 | # [~] ANDROID_NDK_TOOLCHAIN_ROOT is splitted to ANDROID_STANDALONE_TOOLCHAIN 235 | # and ANDROID_TOOLCHAIN_ROOT 236 | # [~] ARM_TARGET is renamed to ANDROID_ABI 237 | # [~] ARMEABI_NDK_NAME is renamed to ANDROID_NDK_ABI_NAME 238 | # [~] ANDROID_API_LEVEL is renamed to ANDROID_NATIVE_API_LEVEL 239 | # - January 2012 240 | # [+] added stlport_static support (experimental) 241 | # [+] added special check for cygwin 242 | # [+] filtered out hidden files (starting with .) while globbing inside NDK 243 | # [+] automatically applied GLESv2 linkage fix for NDK revisions 5-6 244 | # [+] added ANDROID_GET_ABI_RAWNAME to get NDK ABI names by CMake flags 245 | # - February 2012 246 | # [+] updated for NDK r7b 247 | # [~] fixed cmake try_compile() command 248 | # [~] Fix for missing install_name_tool on OS X 249 | # - March 2012 250 | # [~] fixed incorrect C compiler flags 251 | # [~] fixed CMAKE_SYSTEM_PROCESSOR change on ANDROID_ABI change 252 | # [+] improved toolchain loading speed 253 | # [+] added assembler language support (.S) 254 | # [+] allowed preset search paths and extra search suffixes 255 | # - April 2012 256 | # [+] updated for NDK r7c 257 | # [~] fixed most of problems with compiler/linker flags and caching 258 | # [+] added option ANDROID_FUNCTION_LEVEL_LINKING 259 | # - May 2012 260 | # [+] updated for NDK r8 261 | # [+] added mips architecture support 262 | # - August 2012 263 | # [+] updated for NDK r8b 264 | # [~] all intermediate files generated by toolchain are moved to CMakeFiles 265 | # [~] libstdc++ and libsupc are removed from explicit link libraries 266 | # [+] added CCache support (via NDK_CCACHE environment or cmake variable) 267 | # [+] added gold linker support for NDK r8b 268 | # [~] fixed mips linker flags for NDK r8b 269 | # - September 2012 270 | # [+] added NDK release name detection (see ANDROID_NDK_RELEASE) 271 | # [+] added support for all C++ runtimes from NDK 272 | # (system, gabi++, stlport, gnustl) 273 | # [+] improved warnings on known issues of NDKs 274 | # [~] use gold linker as default if available (NDK r8b) 275 | # [~] globally turned off rpath 276 | # [~] compiler options are aligned with NDK r8b 277 | # - October 2012 278 | # [~] fixed C++ linking: explicitly link with math library (OpenCV #2426) 279 | # - November 2012 280 | # [+] updated for NDK r8c 281 | # [+] added support for clang compiler 282 | # - December 2012 283 | # [+] suppress warning about unused CMAKE_TOOLCHAIN_FILE variable 284 | # [+] adjust API level to closest compatible as NDK does 285 | # [~] fixed ccache full path search 286 | # [+] updated for NDK r8d 287 | # [~] compiler options are aligned with NDK r8d 288 | # - March 2013 289 | # [+] updated for NDK r8e (x86 version) 290 | # [+] support x86_64 version of NDK 291 | # - April 2013 292 | # [+] support non-release NDK layouts (from Linaro git and Android git) 293 | # [~] automatically detect if explicit link to crtbegin_*.o is needed 294 | # - June 2013 295 | # [~] fixed stl include path for standalone toolchain made by NDK >= r8c 296 | # - July 2013 297 | # [+] updated for NDK r9 298 | # - November 2013 299 | # [+] updated for NDK r9b 300 | # - December 2013 301 | # [+] updated for NDK r9c 302 | # - January 2014 303 | # [~] fix copying of shared STL 304 | # - April 2014 305 | # [+] updated for NDK r9d 306 | # ------------------------------------------------------------------------------ 307 | 308 | cmake_minimum_required( VERSION 2.6.3 ) 309 | 310 | if( DEFINED CMAKE_CROSSCOMPILING ) 311 | # subsequent toolchain loading is not really needed 312 | return() 313 | endif() 314 | 315 | if( CMAKE_TOOLCHAIN_FILE ) 316 | # touch toolchain variable only to suppress "unused variable" warning 317 | endif() 318 | 319 | get_property( _CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE ) 320 | if( _CMAKE_IN_TRY_COMPILE ) 321 | include( "${CMAKE_CURRENT_SOURCE_DIR}/../android.toolchain.config.cmake" OPTIONAL ) 322 | endif() 323 | 324 | # this one is important 325 | set( CMAKE_SYSTEM_NAME Linux ) 326 | # this one not so much 327 | set( CMAKE_SYSTEM_VERSION 1 ) 328 | 329 | # rpath makes low sence for Android 330 | set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." ) 331 | 332 | set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) 333 | if(NOT DEFINED ANDROID_NDK_SEARCH_PATHS) 334 | if( CMAKE_HOST_WIN32 ) 335 | file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS ) 336 | set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}/android-ndk" "$ENV{SystemDrive}/NVPACK/android-ndk" ) 337 | else() 338 | file( TO_CMAKE_PATH "$ENV{HOME}" ANDROID_NDK_SEARCH_PATHS ) 339 | set( ANDROID_NDK_SEARCH_PATHS /opt/android-ndk "${ANDROID_NDK_SEARCH_PATHS}/NVPACK/android-ndk" ) 340 | endif() 341 | endif() 342 | if(NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH) 343 | set( ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH /opt/android-toolchain ) 344 | endif() 345 | 346 | set( ANDROID_SUPPORTED_ABIS_arm "armeabi-v7a;armeabi;armeabi-v7a with NEON;armeabi-v7a with VFPV3;armeabi-v6 with VFP" ) 347 | set( ANDROID_SUPPORTED_ABIS_x86 "x86" ) 348 | set( ANDROID_SUPPORTED_ABIS_mipsel "mips" ) 349 | 350 | set( ANDROID_DEFAULT_NDK_API_LEVEL 8 ) 351 | set( ANDROID_DEFAULT_NDK_API_LEVEL_x86 9 ) 352 | set( ANDROID_DEFAULT_NDK_API_LEVEL_mips 9 ) 353 | 354 | 355 | macro( __LIST_FILTER listvar regex ) 356 | if( ${listvar} ) 357 | foreach( __val ${${listvar}} ) 358 | if( __val MATCHES "${regex}" ) 359 | list( REMOVE_ITEM ${listvar} "${__val}" ) 360 | endif() 361 | endforeach() 362 | endif() 363 | endmacro() 364 | 365 | macro( __INIT_VARIABLE var_name ) 366 | set( __test_path 0 ) 367 | foreach( __var ${ARGN} ) 368 | if( __var STREQUAL "PATH" ) 369 | set( __test_path 1 ) 370 | break() 371 | endif() 372 | endforeach() 373 | if( __test_path AND NOT EXISTS "${${var_name}}" ) 374 | unset( ${var_name} CACHE ) 375 | endif() 376 | if( "${${var_name}}" STREQUAL "" ) 377 | set( __values 0 ) 378 | foreach( __var ${ARGN} ) 379 | if( __var STREQUAL "VALUES" ) 380 | set( __values 1 ) 381 | elseif( NOT __var STREQUAL "PATH" ) 382 | set( __obsolete 0 ) 383 | if( __var MATCHES "^OBSOLETE_.*$" ) 384 | string( REPLACE "OBSOLETE_" "" __var "${__var}" ) 385 | set( __obsolete 1 ) 386 | endif() 387 | if( __var MATCHES "^ENV_.*$" ) 388 | string( REPLACE "ENV_" "" __var "${__var}" ) 389 | set( __value "$ENV{${__var}}" ) 390 | elseif( DEFINED ${__var} ) 391 | set( __value "${${__var}}" ) 392 | else() 393 | if( __values ) 394 | set( __value "${__var}" ) 395 | else() 396 | set( __value "" ) 397 | endif() 398 | endif() 399 | if( NOT "${__value}" STREQUAL "" ) 400 | if( __test_path ) 401 | if( EXISTS "${__value}" ) 402 | file( TO_CMAKE_PATH "${__value}" ${var_name} ) 403 | if( __obsolete AND NOT _CMAKE_IN_TRY_COMPILE ) 404 | message( WARNING "Using value of obsolete variable ${__var} as initial value for ${var_name}. Please note, that ${__var} can be completely removed in future versions of the toolchain." ) 405 | endif() 406 | break() 407 | endif() 408 | else() 409 | set( ${var_name} "${__value}" ) 410 | if( __obsolete AND NOT _CMAKE_IN_TRY_COMPILE ) 411 | message( WARNING "Using value of obsolete variable ${__var} as initial value for ${var_name}. Please note, that ${__var} can be completely removed in future versions of the toolchain." ) 412 | endif() 413 | break() 414 | endif() 415 | endif() 416 | endif() 417 | endforeach() 418 | unset( __value ) 419 | unset( __values ) 420 | unset( __obsolete ) 421 | elseif( __test_path ) 422 | file( TO_CMAKE_PATH "${${var_name}}" ${var_name} ) 423 | endif() 424 | unset( __test_path ) 425 | endmacro() 426 | 427 | macro( __DETECT_NATIVE_API_LEVEL _var _path ) 428 | SET( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*$" ) 429 | FILE( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" ) 430 | if( NOT __apiFileContent ) 431 | message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." ) 432 | endif() 433 | string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" ) 434 | unset( __apiFileContent ) 435 | unset( __ndkApiLevelRegex ) 436 | endmacro() 437 | 438 | macro( __DETECT_TOOLCHAIN_MACHINE_NAME _var _root ) 439 | if( EXISTS "${_root}" ) 440 | file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" ) 441 | __LIST_FILTER( __gccExePath "^[.].*" ) 442 | list( LENGTH __gccExePath __gccExePathsCount ) 443 | if( NOT __gccExePathsCount EQUAL 1 AND NOT _CMAKE_IN_TRY_COMPILE ) 444 | message( WARNING "Could not determine machine name for compiler from ${_root}" ) 445 | set( ${_var} "" ) 446 | else() 447 | get_filename_component( __gccExeName "${__gccExePath}" NAME_WE ) 448 | string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" ) 449 | endif() 450 | unset( __gccExePath ) 451 | unset( __gccExePathsCount ) 452 | unset( __gccExeName ) 453 | else() 454 | set( ${_var} "" ) 455 | endif() 456 | endmacro() 457 | 458 | 459 | # fight against cygwin 460 | set( ANDROID_FORBID_SYGWIN TRUE CACHE BOOL "Prevent cmake from working under cygwin and using cygwin tools") 461 | mark_as_advanced( ANDROID_FORBID_SYGWIN ) 462 | if( ANDROID_FORBID_SYGWIN ) 463 | if( CYGWIN ) 464 | message( FATAL_ERROR "Android NDK and android-cmake toolchain are not welcome Cygwin. It is unlikely that this cmake toolchain will work under cygwin. But if you want to try then you can set cmake variable ANDROID_FORBID_SYGWIN to FALSE and rerun cmake." ) 465 | endif() 466 | 467 | if( CMAKE_HOST_WIN32 ) 468 | # remove cygwin from PATH 469 | set( __new_path "$ENV{PATH}") 470 | __LIST_FILTER( __new_path "cygwin" ) 471 | set(ENV{PATH} "${__new_path}") 472 | unset(__new_path) 473 | endif() 474 | endif() 475 | 476 | 477 | # detect current host platform 478 | if( NOT DEFINED ANDROID_NDK_HOST_X64 AND (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64" OR CMAKE_HOST_APPLE) ) 479 | set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" ) 480 | mark_as_advanced( ANDROID_NDK_HOST_X64 ) 481 | endif() 482 | 483 | set( TOOL_OS_SUFFIX "" ) 484 | if( CMAKE_HOST_APPLE ) 485 | set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86_64" ) 486 | set( ANDROID_NDK_HOST_SYSTEM_NAME2 "darwin-x86" ) 487 | elseif( CMAKE_HOST_WIN32 ) 488 | set( ANDROID_NDK_HOST_SYSTEM_NAME "windows-x86_64" ) 489 | set( ANDROID_NDK_HOST_SYSTEM_NAME2 "windows" ) 490 | set( TOOL_OS_SUFFIX ".exe" ) 491 | elseif( CMAKE_HOST_UNIX ) 492 | set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86_64" ) 493 | set( ANDROID_NDK_HOST_SYSTEM_NAME2 "linux-x86" ) 494 | else() 495 | message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" ) 496 | endif() 497 | 498 | if( NOT ANDROID_NDK_HOST_X64 ) 499 | set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) 500 | endif() 501 | 502 | # see if we have path to Android NDK 503 | __INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK ) 504 | if( NOT ANDROID_NDK ) 505 | # see if we have path to Android standalone toolchain 506 | __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN OBSOLETE_ANDROID_NDK_TOOLCHAIN_ROOT OBSOLETE_ENV_ANDROID_NDK_TOOLCHAIN_ROOT ) 507 | 508 | if( NOT ANDROID_STANDALONE_TOOLCHAIN ) 509 | #try to find Android NDK in one of the the default locations 510 | set( __ndkSearchPaths ) 511 | foreach( __ndkSearchPath ${ANDROID_NDK_SEARCH_PATHS} ) 512 | foreach( suffix ${ANDROID_SUPPORTED_NDK_VERSIONS} ) 513 | list( APPEND __ndkSearchPaths "${__ndkSearchPath}${suffix}" ) 514 | endforeach() 515 | endforeach() 516 | __INIT_VARIABLE( ANDROID_NDK PATH VALUES ${__ndkSearchPaths} ) 517 | unset( __ndkSearchPaths ) 518 | 519 | if( ANDROID_NDK ) 520 | message( STATUS "Using default path for Android NDK: ${ANDROID_NDK}" ) 521 | message( STATUS " If you prefer to use a different location, please define a cmake or environment variable: ANDROID_NDK" ) 522 | else() 523 | #try to find Android standalone toolchain in one of the the default locations 524 | __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH ) 525 | 526 | if( ANDROID_STANDALONE_TOOLCHAIN ) 527 | message( STATUS "Using default path for standalone toolchain ${ANDROID_STANDALONE_TOOLCHAIN}" ) 528 | message( STATUS " If you prefer to use a different location, please define the variable: ANDROID_STANDALONE_TOOLCHAIN" ) 529 | endif( ANDROID_STANDALONE_TOOLCHAIN ) 530 | endif( ANDROID_NDK ) 531 | endif( NOT ANDROID_STANDALONE_TOOLCHAIN ) 532 | endif( NOT ANDROID_NDK ) 533 | 534 | # remember found paths 535 | if( ANDROID_NDK ) 536 | get_filename_component( ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE ) 537 | set( ANDROID_NDK "${ANDROID_NDK}" CACHE INTERNAL "Path of the Android NDK" FORCE ) 538 | set( BUILD_WITH_ANDROID_NDK True ) 539 | if( EXISTS "${ANDROID_NDK}/RELEASE.TXT" ) 540 | file( STRINGS "${ANDROID_NDK}/RELEASE.TXT" ANDROID_NDK_RELEASE_FULL LIMIT_COUNT 1 REGEX r[0-9]+[a-z]? ) 541 | string( REGEX MATCH r[0-9]+[a-z]? ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_FULL}" ) 542 | else() 543 | set( ANDROID_NDK_RELEASE "r1x" ) 544 | set( ANDROID_NDK_RELEASE_FULL "unreleased" ) 545 | endif() 546 | elseif( ANDROID_STANDALONE_TOOLCHAIN ) 547 | get_filename_component( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" ABSOLUTE ) 548 | # try to detect change 549 | if( CMAKE_AR ) 550 | string( LENGTH "${ANDROID_STANDALONE_TOOLCHAIN}" __length ) 551 | string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidStandaloneToolchainPreviousPath ) 552 | if( NOT __androidStandaloneToolchainPreviousPath STREQUAL ANDROID_STANDALONE_TOOLCHAIN ) 553 | message( FATAL_ERROR "It is not possible to change path to the Android standalone toolchain on subsequent run." ) 554 | endif() 555 | unset( __androidStandaloneToolchainPreviousPath ) 556 | unset( __length ) 557 | endif() 558 | set( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" CACHE INTERNAL "Path of the Android standalone toolchain" FORCE ) 559 | set( BUILD_WITH_STANDALONE_TOOLCHAIN True ) 560 | else() 561 | list(GET ANDROID_NDK_SEARCH_PATHS 0 ANDROID_NDK_SEARCH_PATH) 562 | message( FATAL_ERROR "Could not find neither Android NDK nor Android standalone toolchain. 563 | You should either set an environment variable: 564 | export ANDROID_NDK=~/my-android-ndk 565 | or 566 | export ANDROID_STANDALONE_TOOLCHAIN=~/my-android-toolchain 567 | or put the toolchain or NDK in the default path: 568 | sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH} 569 | sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" ) 570 | endif() 571 | 572 | # android NDK layout 573 | if( BUILD_WITH_ANDROID_NDK ) 574 | if( NOT DEFINED ANDROID_NDK_LAYOUT ) 575 | # try to automatically detect the layout 576 | if( EXISTS "${ANDROID_NDK}/RELEASE.TXT") 577 | set( ANDROID_NDK_LAYOUT "RELEASE" ) 578 | elseif( EXISTS "${ANDROID_NDK}/../../linux-x86/toolchain/" ) 579 | set( ANDROID_NDK_LAYOUT "LINARO" ) 580 | elseif( EXISTS "${ANDROID_NDK}/../../gcc/" ) 581 | set( ANDROID_NDK_LAYOUT "ANDROID" ) 582 | endif() 583 | endif() 584 | set( ANDROID_NDK_LAYOUT "${ANDROID_NDK_LAYOUT}" CACHE STRING "The inner layout of NDK" ) 585 | mark_as_advanced( ANDROID_NDK_LAYOUT ) 586 | if( ANDROID_NDK_LAYOUT STREQUAL "LINARO" ) 587 | set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment 588 | set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../${ANDROID_NDK_HOST_SYSTEM_NAME}/toolchain" ) 589 | set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) 590 | set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) 591 | elseif( ANDROID_NDK_LAYOUT STREQUAL "ANDROID" ) 592 | set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment 593 | set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../gcc/${ANDROID_NDK_HOST_SYSTEM_NAME}/arm" ) 594 | set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) 595 | set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) 596 | else() # ANDROID_NDK_LAYOUT STREQUAL "RELEASE" 597 | set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/toolchains" ) 598 | set( ANDROID_NDK_TOOLCHAINS_SUBPATH "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) 599 | set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME2}" ) 600 | endif() 601 | get_filename_component( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK_TOOLCHAINS_PATH}" ABSOLUTE ) 602 | 603 | # try to detect change of NDK 604 | if( CMAKE_AR ) 605 | string( LENGTH "${ANDROID_NDK_TOOLCHAINS_PATH}" __length ) 606 | string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath ) 607 | if( NOT __androidNdkPreviousPath STREQUAL ANDROID_NDK_TOOLCHAINS_PATH ) 608 | message( FATAL_ERROR "It is not possible to change the path to the NDK on subsequent CMake run. You must remove all generated files from your build folder first. 609 | " ) 610 | endif() 611 | unset( __androidNdkPreviousPath ) 612 | unset( __length ) 613 | endif() 614 | endif() 615 | 616 | 617 | # get all the details about standalone toolchain 618 | if( BUILD_WITH_STANDALONE_TOOLCHAIN ) 619 | __DETECT_NATIVE_API_LEVEL( ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h" ) 620 | set( ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) 621 | set( __availableToolchains "standalone" ) 622 | __DETECT_TOOLCHAIN_MACHINE_NAME( __availableToolchainMachines "${ANDROID_STANDALONE_TOOLCHAIN}" ) 623 | if( NOT __availableToolchainMachines ) 624 | message( FATAL_ERROR "Could not determine machine name of your toolchain. Probably your Android standalone toolchain is broken." ) 625 | endif() 626 | if( __availableToolchainMachines MATCHES i686 ) 627 | set( __availableToolchainArchs "x86" ) 628 | elseif( __availableToolchainMachines MATCHES arm ) 629 | set( __availableToolchainArchs "arm" ) 630 | elseif( __availableToolchainMachines MATCHES mipsel ) 631 | set( __availableToolchainArchs "mipsel" ) 632 | endif() 633 | execute_process( COMMAND "${ANDROID_STANDALONE_TOOLCHAIN}/bin/${__availableToolchainMachines}-gcc${TOOL_OS_SUFFIX}" -dumpversion 634 | OUTPUT_VARIABLE __availableToolchainCompilerVersions OUTPUT_STRIP_TRAILING_WHITESPACE ) 635 | string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9]+)?" __availableToolchainCompilerVersions "${__availableToolchainCompilerVersions}" ) 636 | if( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/bin/clang${TOOL_OS_SUFFIX}" ) 637 | list( APPEND __availableToolchains "standalone-clang" ) 638 | list( APPEND __availableToolchainMachines ${__availableToolchainMachines} ) 639 | list( APPEND __availableToolchainArchs ${__availableToolchainArchs} ) 640 | list( APPEND __availableToolchainCompilerVersions ${__availableToolchainCompilerVersions} ) 641 | endif() 642 | endif() 643 | 644 | macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst __toolchain_subpath ) 645 | foreach( __toolchain ${${__availableToolchainsLst}} ) 646 | if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" ) 647 | string( REGEX REPLACE "-clang3[.][0-9]$" "-4.6" __gcc_toolchain "${__toolchain}" ) 648 | else() 649 | set( __gcc_toolchain "${__toolchain}" ) 650 | endif() 651 | __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK_TOOLCHAINS_PATH}/${__gcc_toolchain}${__toolchain_subpath}" ) 652 | if( __machine ) 653 | string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9x]+)?$" __version "${__gcc_toolchain}" ) 654 | if( __machine MATCHES i686 ) 655 | set( __arch "x86" ) 656 | elseif( __machine MATCHES arm ) 657 | set( __arch "arm" ) 658 | elseif( __machine MATCHES mipsel ) 659 | set( __arch "mipsel" ) 660 | endif() 661 | list( APPEND __availableToolchainMachines "${__machine}" ) 662 | list( APPEND __availableToolchainArchs "${__arch}" ) 663 | list( APPEND __availableToolchainCompilerVersions "${__version}" ) 664 | list( APPEND ${__availableToolchainsVar} "${__toolchain}" ) 665 | endif() 666 | unset( __gcc_toolchain ) 667 | endforeach() 668 | endmacro() 669 | 670 | # get all the details about NDK 671 | if( BUILD_WITH_ANDROID_NDK ) 672 | file( GLOB ANDROID_SUPPORTED_NATIVE_API_LEVELS RELATIVE "${ANDROID_NDK}/platforms" "${ANDROID_NDK}/platforms/android-*" ) 673 | string( REPLACE "android-" "" ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_SUPPORTED_NATIVE_API_LEVELS}" ) 674 | set( __availableToolchains "" ) 675 | set( __availableToolchainMachines "" ) 676 | set( __availableToolchainArchs "" ) 677 | set( __availableToolchainCompilerVersions "" ) 678 | if( ANDROID_TOOLCHAIN_NAME AND EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_TOOLCHAIN_NAME}/" ) 679 | # do not go through all toolchains if we know the name 680 | set( __availableToolchainsLst "${ANDROID_TOOLCHAIN_NAME}" ) 681 | __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) 682 | if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) 683 | __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) 684 | if( __availableToolchains ) 685 | set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) 686 | endif() 687 | endif() 688 | endif() 689 | if( NOT __availableToolchains ) 690 | file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" ) 691 | if( __availableToolchains ) 692 | list(SORT __availableToolchainsLst) # we need clang to go after gcc 693 | endif() 694 | __LIST_FILTER( __availableToolchainsLst "^[.]" ) 695 | __LIST_FILTER( __availableToolchainsLst "llvm" ) 696 | __LIST_FILTER( __availableToolchainsLst "renderscript" ) 697 | __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) 698 | if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) 699 | __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) 700 | if( __availableToolchains ) 701 | set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) 702 | endif() 703 | endif() 704 | endif() 705 | if( NOT __availableToolchains ) 706 | message( FATAL_ERROR "Could not find any working toolchain in the NDK. Probably your Android NDK is broken." ) 707 | endif() 708 | endif() 709 | 710 | # build list of available ABIs 711 | set( ANDROID_SUPPORTED_ABIS "" ) 712 | set( __uniqToolchainArchNames ${__availableToolchainArchs} ) 713 | list( REMOVE_DUPLICATES __uniqToolchainArchNames ) 714 | list( SORT __uniqToolchainArchNames ) 715 | foreach( __arch ${__uniqToolchainArchNames} ) 716 | list( APPEND ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${__arch}} ) 717 | endforeach() 718 | unset( __uniqToolchainArchNames ) 719 | if( NOT ANDROID_SUPPORTED_ABIS ) 720 | message( FATAL_ERROR "No one of known Android ABIs is supported by this cmake toolchain." ) 721 | endif() 722 | 723 | # choose target ABI 724 | __INIT_VARIABLE( ANDROID_ABI OBSOLETE_ARM_TARGET OBSOLETE_ARM_TARGETS VALUES ${ANDROID_SUPPORTED_ABIS} ) 725 | # verify that target ABI is supported 726 | list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx ) 727 | if( __androidAbiIdx EQUAL -1 ) 728 | string( REPLACE ";" "\", \"" PRINTABLE_ANDROID_SUPPORTED_ABIS "${ANDROID_SUPPORTED_ABIS}" ) 729 | message( FATAL_ERROR "Specified ANDROID_ABI = \"${ANDROID_ABI}\" is not supported by this cmake toolchain or your NDK/toolchain. 730 | Supported values are: \"${PRINTABLE_ANDROID_SUPPORTED_ABIS}\" 731 | " ) 732 | endif() 733 | unset( __androidAbiIdx ) 734 | 735 | # set target ABI options 736 | if( ANDROID_ABI STREQUAL "x86" ) 737 | set( X86 true ) 738 | set( ANDROID_NDK_ABI_NAME "x86" ) 739 | set( ANDROID_ARCH_NAME "x86" ) 740 | set( ANDROID_ARCH_FULLNAME "x86" ) 741 | set( ANDROID_LLVM_TRIPLE "i686-none-linux-android" ) 742 | set( CMAKE_SYSTEM_PROCESSOR "i686" ) 743 | elseif( ANDROID_ABI STREQUAL "mips" ) 744 | set( MIPS true ) 745 | set( ANDROID_NDK_ABI_NAME "mips" ) 746 | set( ANDROID_ARCH_NAME "mips" ) 747 | set( ANDROID_ARCH_FULLNAME "mipsel" ) 748 | set( ANDROID_LLVM_TRIPLE "mipsel-none-linux-android" ) 749 | set( CMAKE_SYSTEM_PROCESSOR "mips" ) 750 | elseif( ANDROID_ABI STREQUAL "armeabi" ) 751 | set( ARMEABI true ) 752 | set( ANDROID_NDK_ABI_NAME "armeabi" ) 753 | set( ANDROID_ARCH_NAME "arm" ) 754 | set( ANDROID_ARCH_FULLNAME "arm" ) 755 | set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" ) 756 | set( CMAKE_SYSTEM_PROCESSOR "armv5te" ) 757 | elseif( ANDROID_ABI STREQUAL "armeabi-v6 with VFP" ) 758 | set( ARMEABI_V6 true ) 759 | set( ANDROID_NDK_ABI_NAME "armeabi" ) 760 | set( ANDROID_ARCH_NAME "arm" ) 761 | set( ANDROID_ARCH_FULLNAME "arm" ) 762 | set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" ) 763 | set( CMAKE_SYSTEM_PROCESSOR "armv6" ) 764 | # need always fallback to older platform 765 | set( ARMEABI true ) 766 | elseif( ANDROID_ABI STREQUAL "armeabi-v7a") 767 | set( ARMEABI_V7A true ) 768 | set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) 769 | set( ANDROID_ARCH_NAME "arm" ) 770 | set( ANDROID_ARCH_FULLNAME "arm" ) 771 | set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) 772 | set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) 773 | elseif( ANDROID_ABI STREQUAL "armeabi-v7a with VFPV3" ) 774 | set( ARMEABI_V7A true ) 775 | set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) 776 | set( ANDROID_ARCH_NAME "arm" ) 777 | set( ANDROID_ARCH_FULLNAME "arm" ) 778 | set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) 779 | set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) 780 | set( VFPV3 true ) 781 | elseif( ANDROID_ABI STREQUAL "armeabi-v7a with NEON" ) 782 | set( ARMEABI_V7A true ) 783 | set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) 784 | set( ANDROID_ARCH_NAME "arm" ) 785 | set( ANDROID_ARCH_FULLNAME "arm" ) 786 | set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) 787 | set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) 788 | set( VFPV3 true ) 789 | set( NEON true ) 790 | else() 791 | message( SEND_ERROR "Unknown ANDROID_ABI=\"${ANDROID_ABI}\" is specified." ) 792 | endif() 793 | 794 | if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" ) 795 | # really dirty hack 796 | # it is not possible to change CMAKE_SYSTEM_PROCESSOR after the first run... 797 | file( APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" "SET(CMAKE_SYSTEM_PROCESSOR \"${CMAKE_SYSTEM_PROCESSOR}\")\n" ) 798 | endif() 799 | 800 | if( ANDROID_ARCH_NAME STREQUAL "arm" AND NOT ARMEABI_V6 ) 801 | __INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD OBSOLETE_FORCE_ARM VALUES OFF ) 802 | set( ANDROID_FORCE_ARM_BUILD ${ANDROID_FORCE_ARM_BUILD} CACHE BOOL "Use 32-bit ARM instructions instead of Thumb-1" FORCE ) 803 | mark_as_advanced( ANDROID_FORCE_ARM_BUILD ) 804 | else() 805 | unset( ANDROID_FORCE_ARM_BUILD CACHE ) 806 | endif() 807 | 808 | # choose toolchain 809 | if( ANDROID_TOOLCHAIN_NAME ) 810 | list( FIND __availableToolchains "${ANDROID_TOOLCHAIN_NAME}" __toolchainIdx ) 811 | if( __toolchainIdx EQUAL -1 ) 812 | list( SORT __availableToolchains ) 813 | string( REPLACE ";" "\n * " toolchains_list "${__availableToolchains}" ) 814 | set( toolchains_list " * ${toolchains_list}") 815 | message( FATAL_ERROR "Specified toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is missing in your NDK or broken. Please verify that your NDK is working or select another compiler toolchain. 816 | To configure the toolchain set CMake variable ANDROID_TOOLCHAIN_NAME to one of the following values:\n${toolchains_list}\n" ) 817 | endif() 818 | list( GET __availableToolchainArchs ${__toolchainIdx} __toolchainArch ) 819 | if( NOT __toolchainArch STREQUAL ANDROID_ARCH_FULLNAME ) 820 | message( SEND_ERROR "Selected toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is not able to compile binaries for the \"${ANDROID_ARCH_NAME}\" platform." ) 821 | endif() 822 | else() 823 | set( __toolchainIdx -1 ) 824 | set( __applicableToolchains "" ) 825 | set( __toolchainMaxVersion "0.0.0" ) 826 | list( LENGTH __availableToolchains __availableToolchainsCount ) 827 | math( EXPR __availableToolchainsCount "${__availableToolchainsCount}-1" ) 828 | foreach( __idx RANGE ${__availableToolchainsCount} ) 829 | list( GET __availableToolchainArchs ${__idx} __toolchainArch ) 830 | if( __toolchainArch STREQUAL ANDROID_ARCH_FULLNAME ) 831 | list( GET __availableToolchainCompilerVersions ${__idx} __toolchainVersion ) 832 | string( REPLACE "x" "99" __toolchainVersion "${__toolchainVersion}") 833 | if( __toolchainVersion VERSION_GREATER __toolchainMaxVersion ) 834 | set( __toolchainMaxVersion "${__toolchainVersion}" ) 835 | set( __toolchainIdx ${__idx} ) 836 | endif() 837 | endif() 838 | endforeach() 839 | unset( __availableToolchainsCount ) 840 | unset( __toolchainMaxVersion ) 841 | unset( __toolchainVersion ) 842 | endif() 843 | unset( __toolchainArch ) 844 | if( __toolchainIdx EQUAL -1 ) 845 | message( FATAL_ERROR "No one of available compiler toolchains is able to compile for ${ANDROID_ARCH_NAME} platform." ) 846 | endif() 847 | list( GET __availableToolchains ${__toolchainIdx} ANDROID_TOOLCHAIN_NAME ) 848 | list( GET __availableToolchainMachines ${__toolchainIdx} ANDROID_TOOLCHAIN_MACHINE_NAME ) 849 | list( GET __availableToolchainCompilerVersions ${__toolchainIdx} ANDROID_COMPILER_VERSION ) 850 | 851 | unset( __toolchainIdx ) 852 | unset( __availableToolchains ) 853 | unset( __availableToolchainMachines ) 854 | unset( __availableToolchainArchs ) 855 | unset( __availableToolchainCompilerVersions ) 856 | 857 | # choose native API level 858 | __INIT_VARIABLE( ANDROID_NATIVE_API_LEVEL ENV_ANDROID_NATIVE_API_LEVEL ANDROID_API_LEVEL ENV_ANDROID_API_LEVEL ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME} ANDROID_DEFAULT_NDK_API_LEVEL ) 859 | string( REGEX MATCH "[0-9]+" ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" ) 860 | # adjust API level 861 | set( __real_api_level ${ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME}} ) 862 | foreach( __level ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) 863 | if( NOT __level GREATER ANDROID_NATIVE_API_LEVEL AND NOT __level LESS __real_api_level ) 864 | set( __real_api_level ${__level} ) 865 | endif() 866 | endforeach() 867 | if( __real_api_level AND NOT ANDROID_NATIVE_API_LEVEL EQUAL __real_api_level ) 868 | message( STATUS "Adjusting Android API level 'android-${ANDROID_NATIVE_API_LEVEL}' to 'android-${__real_api_level}'") 869 | set( ANDROID_NATIVE_API_LEVEL ${__real_api_level} ) 870 | endif() 871 | unset(__real_api_level) 872 | # validate 873 | list( FIND ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_NATIVE_API_LEVEL}" __levelIdx ) 874 | if( __levelIdx EQUAL -1 ) 875 | message( SEND_ERROR "Specified Android native API level 'android-${ANDROID_NATIVE_API_LEVEL}' is not supported by your NDK/toolchain." ) 876 | else() 877 | if( BUILD_WITH_ANDROID_NDK ) 878 | __DETECT_NATIVE_API_LEVEL( __realApiLevel "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}/usr/include/android/api-level.h" ) 879 | if( NOT __realApiLevel EQUAL ANDROID_NATIVE_API_LEVEL ) 880 | message( SEND_ERROR "Specified Android API level (${ANDROID_NATIVE_API_LEVEL}) does not match to the level found (${__realApiLevel}). Probably your copy of NDK is broken." ) 881 | endif() 882 | unset( __realApiLevel ) 883 | endif() 884 | set( ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android API level for native code" FORCE ) 885 | if( CMAKE_VERSION VERSION_GREATER "2.8" ) 886 | list( SORT ANDROID_SUPPORTED_NATIVE_API_LEVELS ) 887 | set_property( CACHE ANDROID_NATIVE_API_LEVEL PROPERTY STRINGS ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) 888 | endif() 889 | endif() 890 | unset( __levelIdx ) 891 | 892 | 893 | # remember target ABI 894 | set( ANDROID_ABI "${ANDROID_ABI}" CACHE STRING "The target ABI for Android. If arm, then armeabi-v7a is recommended for hardware floating point." FORCE ) 895 | if( CMAKE_VERSION VERSION_GREATER "2.8" ) 896 | list( SORT ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_FULLNAME} ) 897 | set_property( CACHE ANDROID_ABI PROPERTY STRINGS ${ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_FULLNAME}} ) 898 | endif() 899 | 900 | 901 | # runtime choice (STL, rtti, exceptions) 902 | if( NOT ANDROID_STL ) 903 | # honor legacy ANDROID_USE_STLPORT 904 | if( DEFINED ANDROID_USE_STLPORT ) 905 | if( ANDROID_USE_STLPORT ) 906 | set( ANDROID_STL stlport_static ) 907 | endif() 908 | message( WARNING "You are using an obsolete variable ANDROID_USE_STLPORT to select the STL variant. Use -DANDROID_STL=stlport_static instead." ) 909 | endif() 910 | if( NOT ANDROID_STL ) 911 | set( ANDROID_STL gnustl_static ) 912 | endif() 913 | endif() 914 | set( ANDROID_STL "${ANDROID_STL}" CACHE STRING "C++ runtime" ) 915 | set( ANDROID_STL_FORCE_FEATURES ON CACHE BOOL "automatically configure rtti and exceptions support based on C++ runtime" ) 916 | mark_as_advanced( ANDROID_STL ANDROID_STL_FORCE_FEATURES ) 917 | 918 | if( BUILD_WITH_ANDROID_NDK ) 919 | if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared)$") 920 | message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\". 921 | The possible values are: 922 | none -> Do not configure the runtime. 923 | system -> Use the default minimal system C++ runtime library. 924 | system_re -> Same as system but with rtti and exceptions. 925 | gabi++_static -> Use the GAbi++ runtime as a static library. 926 | gabi++_shared -> Use the GAbi++ runtime as a shared library. 927 | stlport_static -> Use the STLport runtime as a static library. 928 | stlport_shared -> Use the STLport runtime as a shared library. 929 | gnustl_static -> (default) Use the GNU STL as a static library. 930 | gnustl_shared -> Use the GNU STL as a shared library. 931 | " ) 932 | endif() 933 | elseif( BUILD_WITH_STANDALONE_TOOLCHAIN ) 934 | if( NOT "${ANDROID_STL}" MATCHES "^(none|gnustl_static|gnustl_shared)$") 935 | message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\". 936 | The possible values are: 937 | none -> Do not configure the runtime. 938 | gnustl_static -> (default) Use the GNU STL as a static library. 939 | gnustl_shared -> Use the GNU STL as a shared library. 940 | " ) 941 | endif() 942 | endif() 943 | 944 | unset( ANDROID_RTTI ) 945 | unset( ANDROID_EXCEPTIONS ) 946 | unset( ANDROID_STL_INCLUDE_DIRS ) 947 | unset( __libstl ) 948 | unset( __libsupcxx ) 949 | 950 | if( NOT _CMAKE_IN_TRY_COMPILE AND ANDROID_NDK_RELEASE STREQUAL "r7b" AND ARMEABI_V7A AND NOT VFPV3 AND ANDROID_STL MATCHES "gnustl" ) 951 | message( WARNING "The GNU STL armeabi-v7a binaries from NDK r7b can crash non-NEON devices. The files provided with NDK r7b were not configured properly, resulting in crashes on Tegra2-based devices and others when trying to use certain floating-point functions (e.g., cosf, sinf, expf). 952 | You are strongly recommended to switch to another NDK release. 953 | " ) 954 | endif() 955 | 956 | if( NOT _CMAKE_IN_TRY_COMPILE AND X86 AND ANDROID_STL MATCHES "gnustl" AND ANDROID_NDK_RELEASE STREQUAL "r6" ) 957 | message( WARNING "The x86 system header file from NDK r6 has incorrect definition for ptrdiff_t. You are recommended to upgrade to a newer NDK release or manually patch the header: 958 | See https://android.googlesource.com/platform/development.git f907f4f9d4e56ccc8093df6fee54454b8bcab6c2 959 | diff --git a/ndk/platforms/android-9/arch-x86/include/machine/_types.h b/ndk/platforms/android-9/arch-x86/include/machine/_types.h 960 | index 5e28c64..65892a1 100644 961 | --- a/ndk/platforms/android-9/arch-x86/include/machine/_types.h 962 | +++ b/ndk/platforms/android-9/arch-x86/include/machine/_types.h 963 | @@ -51,7 +51,11 @@ typedef long int ssize_t; 964 | #endif 965 | #ifndef _PTRDIFF_T 966 | #define _PTRDIFF_T 967 | -typedef long ptrdiff_t; 968 | +# ifdef __ANDROID__ 969 | + typedef int ptrdiff_t; 970 | +# else 971 | + typedef long ptrdiff_t; 972 | +# endif 973 | #endif 974 | " ) 975 | endif() 976 | 977 | 978 | # setup paths and STL for standalone toolchain 979 | if( BUILD_WITH_STANDALONE_TOOLCHAIN ) 980 | set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) 981 | set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) 982 | set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" ) 983 | 984 | if( NOT ANDROID_STL STREQUAL "none" ) 985 | set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/include/c++/${ANDROID_COMPILER_VERSION}" ) 986 | if( NOT EXISTS "${ANDROID_STL_INCLUDE_DIRS}" ) 987 | # old location ( pre r8c ) 988 | set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) 989 | endif() 990 | if( ARMEABI_V7A AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/bits" ) 991 | list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}" ) 992 | elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb/bits" ) 993 | list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb" ) 994 | else() 995 | list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" ) 996 | endif() 997 | # always search static GNU STL to get the location of libsupc++.a 998 | if( ARMEABI_V7A AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libstdc++.a" ) 999 | set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb" ) 1000 | elseif( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libstdc++.a" ) 1001 | set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}" ) 1002 | elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libstdc++.a" ) 1003 | set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb" ) 1004 | elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libstdc++.a" ) 1005 | set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib" ) 1006 | endif() 1007 | if( __libstl ) 1008 | set( __libsupcxx "${__libstl}/libsupc++.a" ) 1009 | set( __libstl "${__libstl}/libstdc++.a" ) 1010 | endif() 1011 | if( NOT EXISTS "${__libsupcxx}" ) 1012 | message( FATAL_ERROR "The required libstdsupc++.a is missing in your standalone toolchain. 1013 | Usually it happens because of bug in make-standalone-toolchain.sh script from NDK r7, r7b and r7c. 1014 | You need to either upgrade to newer NDK or manually copy 1015 | $ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a 1016 | to 1017 | ${__libsupcxx} 1018 | " ) 1019 | endif() 1020 | if( ANDROID_STL STREQUAL "gnustl_shared" ) 1021 | if( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" ) 1022 | set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" ) 1023 | elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" ) 1024 | set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" ) 1025 | elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" ) 1026 | set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" ) 1027 | endif() 1028 | endif() 1029 | endif() 1030 | endif() 1031 | 1032 | # clang 1033 | if( "${ANDROID_TOOLCHAIN_NAME}" STREQUAL "standalone-clang" ) 1034 | set( ANDROID_COMPILER_IS_CLANG 1 ) 1035 | execute_process( COMMAND "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/clang${TOOL_OS_SUFFIX}" --version OUTPUT_VARIABLE ANDROID_CLANG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) 1036 | string( REGEX MATCH "[0-9]+[.][0-9]+" ANDROID_CLANG_VERSION "${ANDROID_CLANG_VERSION}") 1037 | elseif( "${ANDROID_TOOLCHAIN_NAME}" MATCHES "-clang3[.][0-9]?$" ) 1038 | string( REGEX MATCH "3[.][0-9]$" ANDROID_CLANG_VERSION "${ANDROID_TOOLCHAIN_NAME}") 1039 | string( REGEX REPLACE "-clang${ANDROID_CLANG_VERSION}$" "-4.6" ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) 1040 | if( NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}/bin/clang${TOOL_OS_SUFFIX}" ) 1041 | message( FATAL_ERROR "Could not find the Clang compiler driver" ) 1042 | endif() 1043 | set( ANDROID_COMPILER_IS_CLANG 1 ) 1044 | set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) 1045 | else() 1046 | set( ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) 1047 | unset( ANDROID_COMPILER_IS_CLANG CACHE ) 1048 | endif() 1049 | 1050 | string( REPLACE "." "" _clang_name "clang${ANDROID_CLANG_VERSION}" ) 1051 | if( NOT EXISTS "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" ) 1052 | set( _clang_name "clang" ) 1053 | endif() 1054 | 1055 | 1056 | # setup paths and STL for NDK 1057 | if( BUILD_WITH_ANDROID_NDK ) 1058 | set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) 1059 | set( ANDROID_SYSROOT "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}" ) 1060 | 1061 | if( ANDROID_STL STREQUAL "none" ) 1062 | # do nothing 1063 | elseif( ANDROID_STL STREQUAL "system" ) 1064 | set( ANDROID_RTTI OFF ) 1065 | set( ANDROID_EXCEPTIONS OFF ) 1066 | set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" ) 1067 | elseif( ANDROID_STL STREQUAL "system_re" ) 1068 | set( ANDROID_RTTI ON ) 1069 | set( ANDROID_EXCEPTIONS ON ) 1070 | set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" ) 1071 | elseif( ANDROID_STL MATCHES "gabi" ) 1072 | if( ANDROID_NDK_RELEASE STRLESS "r7" ) 1073 | message( FATAL_ERROR "gabi++ is not awailable in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.") 1074 | endif() 1075 | set( ANDROID_RTTI ON ) 1076 | set( ANDROID_EXCEPTIONS OFF ) 1077 | set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/gabi++/include" ) 1078 | set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gabi++/libs/${ANDROID_NDK_ABI_NAME}/libgabi++_static.a" ) 1079 | elseif( ANDROID_STL MATCHES "stlport" ) 1080 | if( NOT ANDROID_NDK_RELEASE STRLESS "r8d" ) 1081 | set( ANDROID_EXCEPTIONS ON ) 1082 | else() 1083 | set( ANDROID_EXCEPTIONS OFF ) 1084 | endif() 1085 | if( ANDROID_NDK_RELEASE STRLESS "r7" ) 1086 | set( ANDROID_RTTI OFF ) 1087 | else() 1088 | set( ANDROID_RTTI ON ) 1089 | endif() 1090 | set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/stlport/stlport" ) 1091 | set( __libstl "${ANDROID_NDK}/sources/cxx-stl/stlport/libs/${ANDROID_NDK_ABI_NAME}/libstlport_static.a" ) 1092 | elseif( ANDROID_STL MATCHES "gnustl" ) 1093 | set( ANDROID_EXCEPTIONS ON ) 1094 | set( ANDROID_RTTI ON ) 1095 | if( EXISTS "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" ) 1096 | if( ARMEABI_V7A AND ANDROID_COMPILER_VERSION VERSION_EQUAL "4.7" AND ANDROID_NDK_RELEASE STREQUAL "r8d" ) 1097 | # gnustl binary for 4.7 compiler is buggy :( 1098 | # TODO: look for right fix 1099 | set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.6" ) 1100 | else() 1101 | set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" ) 1102 | endif() 1103 | else() 1104 | set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++" ) 1105 | endif() 1106 | set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" ) 1107 | if( EXISTS "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" ) 1108 | set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" ) 1109 | else() 1110 | set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libstdc++.a" ) 1111 | endif() 1112 | else() 1113 | message( FATAL_ERROR "Unknown runtime: ${ANDROID_STL}" ) 1114 | endif() 1115 | # find libsupc++.a - rtti & exceptions 1116 | if( ANDROID_STL STREQUAL "system_re" OR ANDROID_STL MATCHES "gnustl" ) 1117 | set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r8b or newer 1118 | if( NOT EXISTS "${__libsupcxx}" ) 1119 | set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r7-r8 1120 | endif() 1121 | if( NOT EXISTS "${__libsupcxx}" ) # before r7 1122 | if( ARMEABI_V7A ) 1123 | if( ANDROID_FORCE_ARM_BUILD ) 1124 | set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libsupc++.a" ) 1125 | else() 1126 | set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libsupc++.a" ) 1127 | endif() 1128 | elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD ) 1129 | set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libsupc++.a" ) 1130 | else() 1131 | set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libsupc++.a" ) 1132 | endif() 1133 | endif() 1134 | if( NOT EXISTS "${__libsupcxx}") 1135 | message( ERROR "Could not find libsupc++.a for a chosen platform. Either your NDK is not supported or is broken.") 1136 | endif() 1137 | endif() 1138 | endif() 1139 | 1140 | 1141 | # case of shared STL linkage 1142 | if( ANDROID_STL MATCHES "shared" AND DEFINED __libstl ) 1143 | string( REPLACE "_static.a" "_shared.so" __libstl "${__libstl}" ) 1144 | # TODO: check if .so file exists before the renaming 1145 | endif() 1146 | 1147 | 1148 | # ccache support 1149 | __INIT_VARIABLE( _ndk_ccache NDK_CCACHE ENV_NDK_CCACHE ) 1150 | if( _ndk_ccache ) 1151 | if( DEFINED NDK_CCACHE AND NOT EXISTS NDK_CCACHE ) 1152 | unset( NDK_CCACHE CACHE ) 1153 | endif() 1154 | find_program( NDK_CCACHE "${_ndk_ccache}" DOC "The path to ccache binary") 1155 | else() 1156 | unset( NDK_CCACHE CACHE ) 1157 | endif() 1158 | unset( _ndk_ccache ) 1159 | 1160 | 1161 | # setup the cross-compiler 1162 | if( NOT CMAKE_C_COMPILER ) 1163 | if( NDK_CCACHE AND NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) 1164 | set( CMAKE_C_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C compiler" ) 1165 | set( CMAKE_CXX_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C++ compiler" ) 1166 | if( ANDROID_COMPILER_IS_CLANG ) 1167 | set( CMAKE_C_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") 1168 | set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") 1169 | else() 1170 | set( CMAKE_C_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") 1171 | set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") 1172 | endif() 1173 | else() 1174 | if( ANDROID_COMPILER_IS_CLANG ) 1175 | set( CMAKE_C_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") 1176 | set( CMAKE_CXX_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") 1177 | else() 1178 | set( CMAKE_C_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler" ) 1179 | set( CMAKE_CXX_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler" ) 1180 | endif() 1181 | endif() 1182 | set( CMAKE_ASM_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "assembler" ) 1183 | set( CMAKE_STRIP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip" ) 1184 | set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" ) 1185 | set( CMAKE_LINKER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker" ) 1186 | set( CMAKE_NM "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-nm${TOOL_OS_SUFFIX}" CACHE PATH "nm" ) 1187 | set( CMAKE_OBJCOPY "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" ) 1188 | set( CMAKE_OBJDUMP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objdump${TOOL_OS_SUFFIX}" CACHE PATH "objdump" ) 1189 | set( CMAKE_RANLIB "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ranlib${TOOL_OS_SUFFIX}" CACHE PATH "ranlib" ) 1190 | endif() 1191 | 1192 | set( _CMAKE_TOOLCHAIN_PREFIX "${ANDROID_TOOLCHAIN_MACHINE_NAME}-" ) 1193 | if( CMAKE_VERSION VERSION_LESS 2.8.5 ) 1194 | set( CMAKE_ASM_COMPILER_ARG1 "-c" ) 1195 | endif() 1196 | if( APPLE ) 1197 | find_program( CMAKE_INSTALL_NAME_TOOL NAMES install_name_tool ) 1198 | if( NOT CMAKE_INSTALL_NAME_TOOL ) 1199 | message( FATAL_ERROR "Could not find install_name_tool, please check your installation." ) 1200 | endif() 1201 | mark_as_advanced( CMAKE_INSTALL_NAME_TOOL ) 1202 | endif() 1203 | 1204 | # Force set compilers because standard identification works badly for us 1205 | include( CMakeForceCompiler ) 1206 | CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU ) 1207 | if( ANDROID_COMPILER_IS_CLANG ) 1208 | set( CMAKE_C_COMPILER_ID Clang) 1209 | endif() 1210 | set( CMAKE_C_PLATFORM_ID Linux ) 1211 | set( CMAKE_C_SIZEOF_DATA_PTR 4 ) 1212 | set( CMAKE_C_HAS_ISYSROOT 1 ) 1213 | set( CMAKE_C_COMPILER_ABI ELF ) 1214 | CMAKE_FORCE_CXX_COMPILER( "${CMAKE_CXX_COMPILER}" GNU ) 1215 | if( ANDROID_COMPILER_IS_CLANG ) 1216 | set( CMAKE_CXX_COMPILER_ID Clang) 1217 | endif() 1218 | set( CMAKE_CXX_PLATFORM_ID Linux ) 1219 | set( CMAKE_CXX_SIZEOF_DATA_PTR 4 ) 1220 | set( CMAKE_CXX_HAS_ISYSROOT 1 ) 1221 | set( CMAKE_CXX_COMPILER_ABI ELF ) 1222 | set( CMAKE_CXX_SOURCE_FILE_EXTENSIONS cc cp cxx cpp CPP c++ C ) 1223 | # force ASM compiler (required for CMake < 2.8.5) 1224 | set( CMAKE_ASM_COMPILER_ID_RUN TRUE ) 1225 | set( CMAKE_ASM_COMPILER_ID GNU ) 1226 | set( CMAKE_ASM_COMPILER_WORKS TRUE ) 1227 | set( CMAKE_ASM_COMPILER_FORCED TRUE ) 1228 | set( CMAKE_COMPILER_IS_GNUASM 1) 1229 | set( CMAKE_ASM_SOURCE_FILE_EXTENSIONS s S asm ) 1230 | 1231 | # flags and definitions 1232 | remove_definitions( -DANDROID ) 1233 | add_definitions( -DANDROID ) 1234 | 1235 | if( ANDROID_SYSROOT MATCHES "[ ;\"]" ) 1236 | if( CMAKE_HOST_WIN32 ) 1237 | # try to convert path to 8.3 form 1238 | file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "@echo %~s1" ) 1239 | execute_process( COMMAND "$ENV{ComSpec}" /c "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "${ANDROID_SYSROOT}" 1240 | OUTPUT_VARIABLE __path OUTPUT_STRIP_TRAILING_WHITESPACE 1241 | RESULT_VARIABLE __result ERROR_QUIET ) 1242 | if( __result EQUAL 0 ) 1243 | file( TO_CMAKE_PATH "${__path}" ANDROID_SYSROOT ) 1244 | set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) 1245 | else() 1246 | set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" ) 1247 | endif() 1248 | else() 1249 | set( ANDROID_CXX_FLAGS "'--sysroot=${ANDROID_SYSROOT}'" ) 1250 | endif() 1251 | if( NOT _CMAKE_IN_TRY_COMPILE ) 1252 | # quotes can break try_compile and compiler identification 1253 | message(WARNING "Path to your Android NDK (or toolchain) has non-alphanumeric symbols.\nThe build might be broken.\n") 1254 | endif() 1255 | else() 1256 | set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) 1257 | endif() 1258 | 1259 | # NDK flags 1260 | if( ARMEABI OR ARMEABI_V7A ) 1261 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -funwind-tables" ) 1262 | if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 ) 1263 | set( ANDROID_CXX_FLAGS_RELEASE "-mthumb -fomit-frame-pointer -fno-strict-aliasing" ) 1264 | set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) 1265 | if( NOT ANDROID_COMPILER_IS_CLANG ) 1266 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -finline-limit=64" ) 1267 | endif() 1268 | else() 1269 | # always compile ARMEABI_V6 in arm mode; otherwise there is no difference from ARMEABI 1270 | set( ANDROID_CXX_FLAGS_RELEASE "-marm -fomit-frame-pointer -fstrict-aliasing" ) 1271 | set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) 1272 | if( NOT ANDROID_COMPILER_IS_CLANG ) 1273 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) 1274 | endif() 1275 | endif() 1276 | elseif( X86 ) 1277 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) 1278 | if( NOT ANDROID_COMPILER_IS_CLANG ) 1279 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) 1280 | else() 1281 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fPIC" ) 1282 | endif() 1283 | set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) 1284 | set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) 1285 | elseif( MIPS ) 1286 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fpic -fno-strict-aliasing -finline-functions -ffunction-sections -funwind-tables -fmessage-length=0" ) 1287 | set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" ) 1288 | set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer" ) 1289 | if( NOT ANDROID_COMPILER_IS_CLANG ) 1290 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers" ) 1291 | set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) 1292 | endif() 1293 | elseif() 1294 | set( ANDROID_CXX_FLAGS_RELEASE "" ) 1295 | set( ANDROID_CXX_FLAGS_DEBUG "" ) 1296 | endif() 1297 | 1298 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" ) # good/necessary when porting desktop libraries 1299 | 1300 | if( NOT X86 AND NOT ANDROID_COMPILER_IS_CLANG ) 1301 | set( ANDROID_CXX_FLAGS "-Wno-psabi ${ANDROID_CXX_FLAGS}" ) 1302 | endif() 1303 | 1304 | if( NOT ANDROID_COMPILER_VERSION VERSION_LESS "4.6" ) 1305 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -no-canonical-prefixes" ) # see https://android-review.googlesource.com/#/c/47564/ 1306 | endif() 1307 | 1308 | # ABI-specific flags 1309 | if( ARMEABI_V7A ) 1310 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv7-a -mfloat-abi=softfp" ) 1311 | if( NEON ) 1312 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=neon" ) 1313 | elseif( VFPV3 ) 1314 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3" ) 1315 | else() 1316 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3-d16" ) 1317 | endif() 1318 | elseif( ARMEABI_V6 ) 1319 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv6 -mfloat-abi=softfp -mfpu=vfp" ) # vfp == vfpv2 1320 | elseif( ARMEABI ) 1321 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv5te -mtune=xscale -msoft-float" ) 1322 | endif() 1323 | 1324 | if( ANDROID_STL MATCHES "gnustl" AND (EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}") ) 1325 | set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) 1326 | set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) 1327 | set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) 1328 | else() 1329 | set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) 1330 | set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) 1331 | set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) 1332 | endif() 1333 | 1334 | # STL 1335 | if( EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}" ) 1336 | if( EXISTS "${__libstl}" ) 1337 | set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libstl}\"" ) 1338 | set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libstl}\"" ) 1339 | set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libstl}\"" ) 1340 | endif() 1341 | if( EXISTS "${__libsupcxx}" ) 1342 | set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" ) 1343 | set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" ) 1344 | set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) 1345 | # C objects: 1346 | set( CMAKE_C_CREATE_SHARED_LIBRARY " -o " ) 1347 | set( CMAKE_C_CREATE_SHARED_MODULE " -o " ) 1348 | set( CMAKE_C_LINK_EXECUTABLE " -o " ) 1349 | set( CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" ) 1350 | set( CMAKE_C_CREATE_SHARED_MODULE "${CMAKE_C_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" ) 1351 | set( CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) 1352 | endif() 1353 | if( ANDROID_STL MATCHES "gnustl" ) 1354 | if( NOT EXISTS "${ANDROID_LIBM_PATH}" ) 1355 | set( ANDROID_LIBM_PATH -lm ) 1356 | endif() 1357 | set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} ${ANDROID_LIBM_PATH}" ) 1358 | set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} ${ANDROID_LIBM_PATH}" ) 1359 | set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} ${ANDROID_LIBM_PATH}" ) 1360 | endif() 1361 | endif() 1362 | 1363 | # variables controlling optional build flags 1364 | if (ANDROID_NDK_RELEASE STRLESS "r7") 1365 | # libGLESv2.so in NDK's prior to r7 refers to missing external symbols. 1366 | # So this flag option is required for all projects using OpenGL from native. 1367 | __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES ON ) 1368 | else() 1369 | __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES OFF ) 1370 | endif() 1371 | __INIT_VARIABLE( ANDROID_NO_UNDEFINED OBSOLETE_NO_UNDEFINED VALUES ON ) 1372 | __INIT_VARIABLE( ANDROID_FUNCTION_LEVEL_LINKING VALUES ON ) 1373 | __INIT_VARIABLE( ANDROID_GOLD_LINKER VALUES ON ) 1374 | __INIT_VARIABLE( ANDROID_NOEXECSTACK VALUES ON ) 1375 | __INIT_VARIABLE( ANDROID_RELRO VALUES ON ) 1376 | 1377 | set( ANDROID_NO_UNDEFINED ${ANDROID_NO_UNDEFINED} CACHE BOOL "Show all undefined symbols as linker errors" ) 1378 | set( ANDROID_SO_UNDEFINED ${ANDROID_SO_UNDEFINED} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) 1379 | set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) 1380 | set( ANDROID_GOLD_LINKER ${ANDROID_GOLD_LINKER} CACHE BOOL "Enables gold linker (only avaialble for NDK r8b for ARM and x86 architectures on linux-86 and darwin-x86 hosts)" ) 1381 | set( ANDROID_NOEXECSTACK ${ANDROID_NOEXECSTACK} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) 1382 | set( ANDROID_RELRO ${ANDROID_RELRO} CACHE BOOL "Enables RELRO - a memory corruption mitigation technique" ) 1383 | mark_as_advanced( ANDROID_NO_UNDEFINED ANDROID_SO_UNDEFINED ANDROID_FUNCTION_LEVEL_LINKING ANDROID_GOLD_LINKER ANDROID_NOEXECSTACK ANDROID_RELRO ) 1384 | 1385 | # linker flags 1386 | set( ANDROID_LINKER_FLAGS "" ) 1387 | 1388 | if( ARMEABI_V7A ) 1389 | # this is *required* to use the following linker flags that routes around 1390 | # a CPU bug in some Cortex-A8 implementations: 1391 | set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--fix-cortex-a8" ) 1392 | endif() 1393 | 1394 | if( ANDROID_NO_UNDEFINED ) 1395 | if( MIPS ) 1396 | # there is some sysroot-related problem in mips linker... 1397 | if( NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) 1398 | set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined -Wl,-rpath-link,${ANDROID_SYSROOT}/usr/lib" ) 1399 | endif() 1400 | else() 1401 | set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined" ) 1402 | endif() 1403 | endif() 1404 | 1405 | if( ANDROID_SO_UNDEFINED ) 1406 | set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-allow-shlib-undefined" ) 1407 | endif() 1408 | 1409 | if( ANDROID_FUNCTION_LEVEL_LINKING ) 1410 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fdata-sections -ffunction-sections" ) 1411 | set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--gc-sections" ) 1412 | endif() 1413 | 1414 | if( ANDROID_COMPILER_VERSION VERSION_EQUAL "4.6" ) 1415 | if( ANDROID_GOLD_LINKER AND (CMAKE_HOST_UNIX OR ANDROID_NDK_RELEASE STRGREATER "r8b") AND (ARMEABI OR ARMEABI_V7A OR X86) ) 1416 | set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=gold" ) 1417 | elseif( ANDROID_NDK_RELEASE STRGREATER "r8b") 1418 | set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=bfd" ) 1419 | elseif( ANDROID_NDK_RELEASE STREQUAL "r8b" AND ARMEABI AND NOT _CMAKE_IN_TRY_COMPILE ) 1420 | message( WARNING "The default bfd linker from arm GCC 4.6 toolchain can fail with 'unresolvable R_ARM_THM_CALL relocation' error message. See https://code.google.com/p/android/issues/detail?id=35342 1421 | On Linux and OS X host platform you can workaround this problem using gold linker (default). 1422 | Rerun cmake with -DANDROID_GOLD_LINKER=ON option in case of problems. 1423 | " ) 1424 | endif() 1425 | endif() # version 4.6 1426 | 1427 | if( ANDROID_NOEXECSTACK ) 1428 | if( ANDROID_COMPILER_IS_CLANG ) 1429 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Xclang -mnoexecstack" ) 1430 | else() 1431 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Wa,--noexecstack" ) 1432 | endif() 1433 | set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,noexecstack" ) 1434 | endif() 1435 | 1436 | if( ANDROID_RELRO ) 1437 | set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now" ) 1438 | endif() 1439 | 1440 | if( ANDROID_COMPILER_IS_CLANG ) 1441 | set( ANDROID_CXX_FLAGS "-Qunused-arguments ${ANDROID_CXX_FLAGS}" ) 1442 | if( ARMEABI_V7A AND NOT ANDROID_FORCE_ARM_BUILD ) 1443 | set( ANDROID_CXX_FLAGS_RELEASE "-target thumbv7-none-linux-androideabi ${ANDROID_CXX_FLAGS_RELEASE}" ) 1444 | set( ANDROID_CXX_FLAGS_DEBUG "-target ${ANDROID_LLVM_TRIPLE} ${ANDROID_CXX_FLAGS_DEBUG}" ) 1445 | else() 1446 | set( ANDROID_CXX_FLAGS "-target ${ANDROID_LLVM_TRIPLE} ${ANDROID_CXX_FLAGS}" ) 1447 | endif() 1448 | if( BUILD_WITH_ANDROID_NDK ) 1449 | set( ANDROID_CXX_FLAGS "-gcc-toolchain ${ANDROID_TOOLCHAIN_ROOT} ${ANDROID_CXX_FLAGS}" ) 1450 | endif() 1451 | endif() 1452 | 1453 | # cache flags 1454 | set( CMAKE_CXX_FLAGS "" CACHE STRING "c++ flags" ) 1455 | set( CMAKE_C_FLAGS "" CACHE STRING "c flags" ) 1456 | set( CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c++ Release flags" ) 1457 | set( CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c Release flags" ) 1458 | set( CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c++ Debug flags" ) 1459 | set( CMAKE_C_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c Debug flags" ) 1460 | set( CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "shared linker flags" ) 1461 | set( CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "module linker flags" ) 1462 | set( CMAKE_EXE_LINKER_FLAGS "-Wl,-z,nocopyreloc" CACHE STRING "executable linker flags" ) 1463 | 1464 | # put flags to cache (for debug purpose only) 1465 | set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS}" CACHE INTERNAL "Android specific c/c++ flags" ) 1466 | set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE}" CACHE INTERNAL "Android specific c/c++ Release flags" ) 1467 | set( ANDROID_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG}" CACHE INTERNAL "Android specific c/c++ Debug flags" ) 1468 | set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}" CACHE INTERNAL "Android specific c/c++ linker flags" ) 1469 | 1470 | # finish flags 1471 | set( CMAKE_CXX_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" ) 1472 | set( CMAKE_C_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_C_FLAGS}" ) 1473 | set( CMAKE_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_CXX_FLAGS_RELEASE}" ) 1474 | set( CMAKE_C_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_C_FLAGS_RELEASE}" ) 1475 | set( CMAKE_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_CXX_FLAGS_DEBUG}" ) 1476 | set( CMAKE_C_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_C_FLAGS_DEBUG}" ) 1477 | set( CMAKE_SHARED_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}" ) 1478 | set( CMAKE_MODULE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}" ) 1479 | set( CMAKE_EXE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" ) 1480 | 1481 | if( MIPS AND BUILD_WITH_ANDROID_NDK AND ANDROID_NDK_RELEASE STREQUAL "r8" ) 1482 | set( CMAKE_SHARED_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_SHARED_LINKER_FLAGS}" ) 1483 | set( CMAKE_MODULE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_MODULE_LINKER_FLAGS}" ) 1484 | set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" ) 1485 | endif() 1486 | 1487 | # configure rtti 1488 | if( DEFINED ANDROID_RTTI AND ANDROID_STL_FORCE_FEATURES ) 1489 | if( ANDROID_RTTI ) 1490 | set( CMAKE_CXX_FLAGS "-frtti ${CMAKE_CXX_FLAGS}" ) 1491 | else() 1492 | set( CMAKE_CXX_FLAGS "-fno-rtti ${CMAKE_CXX_FLAGS}" ) 1493 | endif() 1494 | endif() 1495 | 1496 | # configure exceptios 1497 | if( DEFINED ANDROID_EXCEPTIONS AND ANDROID_STL_FORCE_FEATURES ) 1498 | if( ANDROID_EXCEPTIONS ) 1499 | set( CMAKE_CXX_FLAGS "-fexceptions ${CMAKE_CXX_FLAGS}" ) 1500 | set( CMAKE_C_FLAGS "-fexceptions ${CMAKE_C_FLAGS}" ) 1501 | else() 1502 | set( CMAKE_CXX_FLAGS "-fno-exceptions ${CMAKE_CXX_FLAGS}" ) 1503 | set( CMAKE_C_FLAGS "-fno-exceptions ${CMAKE_C_FLAGS}" ) 1504 | endif() 1505 | endif() 1506 | 1507 | # global includes and link directories 1508 | include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} ) 1509 | get_filename_component(__android_install_path "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ABSOLUTE) # avoid CMP0015 policy warning 1510 | link_directories( "${__android_install_path}" ) 1511 | 1512 | # detect if need link crtbegin_so.o explicitly 1513 | if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK ) 1514 | set( __cmd "${CMAKE_CXX_CREATE_SHARED_LIBRARY}" ) 1515 | string( REPLACE "" "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" __cmd "${__cmd}" ) 1516 | string( REPLACE "" "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}" __cmd "${__cmd}" ) 1517 | string( REPLACE "" "${CMAKE_CXX_FLAGS}" __cmd "${__cmd}" ) 1518 | string( REPLACE "" "" __cmd "${__cmd}" ) 1519 | string( REPLACE "" "${CMAKE_SHARED_LINKER_FLAGS}" __cmd "${__cmd}" ) 1520 | string( REPLACE "" "-shared" __cmd "${__cmd}" ) 1521 | string( REPLACE "" "" __cmd "${__cmd}" ) 1522 | string( REPLACE "" "" __cmd "${__cmd}" ) 1523 | string( REPLACE "" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain_crtlink_test.so" __cmd "${__cmd}" ) 1524 | string( REPLACE "" "\"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" __cmd "${__cmd}" ) 1525 | string( REPLACE "" "" __cmd "${__cmd}" ) 1526 | separate_arguments( __cmd ) 1527 | foreach( __var ANDROID_NDK ANDROID_NDK_TOOLCHAINS_PATH ANDROID_STANDALONE_TOOLCHAIN ) 1528 | if( ${__var} ) 1529 | set( __tmp "${${__var}}" ) 1530 | separate_arguments( __tmp ) 1531 | string( REPLACE "${__tmp}" "${${__var}}" __cmd "${__cmd}") 1532 | endif() 1533 | endforeach() 1534 | string( REPLACE "'" "" __cmd "${__cmd}" ) 1535 | string( REPLACE "\"" "" __cmd "${__cmd}" ) 1536 | execute_process( COMMAND ${__cmd} RESULT_VARIABLE __cmd_result OUTPUT_QUIET ERROR_QUIET ) 1537 | if( __cmd_result EQUAL 0 ) 1538 | set( ANDROID_EXPLICIT_CRT_LINK ON ) 1539 | else() 1540 | set( ANDROID_EXPLICIT_CRT_LINK OFF ) 1541 | endif() 1542 | endif() 1543 | 1544 | if( ANDROID_EXPLICIT_CRT_LINK ) 1545 | set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) 1546 | set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) 1547 | endif() 1548 | 1549 | # setup output directories 1550 | set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "root for library output, set this to change where android libs are installed to" ) 1551 | set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" ) 1552 | 1553 | if(NOT _CMAKE_IN_TRY_COMPILE) 1554 | if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" ) 1555 | set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" ) 1556 | else() 1557 | set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" ) 1558 | endif() 1559 | set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "path for android libs" ) 1560 | endif() 1561 | 1562 | # copy shaed stl library to build directory 1563 | if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" ) 1564 | get_filename_component( __libstlname "${__libstl}" NAME ) 1565 | execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess ) 1566 | if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}") 1567 | message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" ) 1568 | endif() 1569 | unset( __fileCopyProcess ) 1570 | unset( __libstlname ) 1571 | endif() 1572 | 1573 | 1574 | # set these global flags for cmake client scripts to change behavior 1575 | set( ANDROID True ) 1576 | set( BUILD_ANDROID True ) 1577 | 1578 | # where is the target environment 1579 | set( CMAKE_FIND_ROOT_PATH "${ANDROID_TOOLCHAIN_ROOT}/bin" "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" "${ANDROID_SYSROOT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share" ) 1580 | 1581 | # only search for libraries and includes in the ndk toolchain 1582 | set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) 1583 | set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) 1584 | set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) 1585 | 1586 | 1587 | # macro to find packages on the host OS 1588 | macro( find_host_package ) 1589 | set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) 1590 | set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) 1591 | set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) 1592 | if( CMAKE_HOST_WIN32 ) 1593 | SET( WIN32 1 ) 1594 | SET( UNIX ) 1595 | elseif( CMAKE_HOST_APPLE ) 1596 | SET( APPLE 1 ) 1597 | SET( UNIX ) 1598 | endif() 1599 | find_package( ${ARGN} ) 1600 | SET( WIN32 ) 1601 | SET( APPLE ) 1602 | SET( UNIX 1 ) 1603 | set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) 1604 | set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) 1605 | set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) 1606 | endmacro() 1607 | 1608 | 1609 | # macro to find programs on the host OS 1610 | macro( find_host_program ) 1611 | set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) 1612 | set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) 1613 | set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) 1614 | if( CMAKE_HOST_WIN32 ) 1615 | SET( WIN32 1 ) 1616 | SET( UNIX ) 1617 | elseif( CMAKE_HOST_APPLE ) 1618 | SET( APPLE 1 ) 1619 | SET( UNIX ) 1620 | endif() 1621 | find_program( ${ARGN} ) 1622 | SET( WIN32 ) 1623 | SET( APPLE ) 1624 | SET( UNIX 1 ) 1625 | set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) 1626 | set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) 1627 | set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) 1628 | endmacro() 1629 | 1630 | 1631 | macro( ANDROID_GET_ABI_RAWNAME TOOLCHAIN_FLAG VAR ) 1632 | if( "${TOOLCHAIN_FLAG}" STREQUAL "ARMEABI" ) 1633 | set( ${VAR} "armeabi" ) 1634 | elseif( "${TOOLCHAIN_FLAG}" STREQUAL "ARMEABI_V7A" ) 1635 | set( ${VAR} "armeabi-v7a" ) 1636 | elseif( "${TOOLCHAIN_FLAG}" STREQUAL "X86" ) 1637 | set( ${VAR} "x86" ) 1638 | elseif( "${TOOLCHAIN_FLAG}" STREQUAL "MIPS" ) 1639 | set( ${VAR} "mips" ) 1640 | else() 1641 | set( ${VAR} "unknown" ) 1642 | endif() 1643 | endmacro() 1644 | 1645 | 1646 | # export toolchain settings for the try_compile() command 1647 | if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" ) 1648 | set( __toolchain_config "") 1649 | foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN ANDROID_SET_OBSOLETE_VARIABLES 1650 | ANDROID_NDK_HOST_X64 1651 | ANDROID_NDK 1652 | ANDROID_NDK_LAYOUT 1653 | ANDROID_STANDALONE_TOOLCHAIN 1654 | ANDROID_TOOLCHAIN_NAME 1655 | ANDROID_ABI 1656 | ANDROID_NATIVE_API_LEVEL 1657 | ANDROID_STL 1658 | ANDROID_STL_FORCE_FEATURES 1659 | ANDROID_FORCE_ARM_BUILD 1660 | ANDROID_NO_UNDEFINED 1661 | ANDROID_SO_UNDEFINED 1662 | ANDROID_FUNCTION_LEVEL_LINKING 1663 | ANDROID_GOLD_LINKER 1664 | ANDROID_NOEXECSTACK 1665 | ANDROID_RELRO 1666 | ANDROID_LIBM_PATH 1667 | ANDROID_EXPLICIT_CRT_LINK 1668 | ) 1669 | if( DEFINED ${__var} ) 1670 | if( "${__var}" MATCHES " ") 1671 | set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" CACHE INTERNAL \"\" )\n" ) 1672 | else() 1673 | set( __toolchain_config "${__toolchain_config}set( ${__var} ${${__var}} CACHE INTERNAL \"\" )\n" ) 1674 | endif() 1675 | endif() 1676 | endforeach() 1677 | file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android.toolchain.config.cmake" "${__toolchain_config}" ) 1678 | unset( __toolchain_config ) 1679 | endif() 1680 | 1681 | 1682 | # force cmake to produce / instead of \ in build commands for Ninja generator 1683 | if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 ) 1684 | # it is a bad hack after all 1685 | # CMake generates Ninja makefiles with UNIX paths only if it thinks that we are going to build with MinGW 1686 | set( CMAKE_COMPILER_IS_MINGW TRUE ) # tell CMake that we are MinGW 1687 | set( CMAKE_CROSSCOMPILING TRUE ) # stop recursion 1688 | enable_language( C ) 1689 | enable_language( CXX ) 1690 | # unset( CMAKE_COMPILER_IS_MINGW ) # can't unset because CMake does not convert back-slashes in response files without it 1691 | unset( MINGW ) 1692 | endif() 1693 | 1694 | 1695 | # set some obsolete variables for backward compatibility 1696 | set( ANDROID_SET_OBSOLETE_VARIABLES ON CACHE BOOL "Define obsolete Andrid-specific cmake variables" ) 1697 | mark_as_advanced( ANDROID_SET_OBSOLETE_VARIABLES ) 1698 | if( ANDROID_SET_OBSOLETE_VARIABLES ) 1699 | set( ANDROID_API_LEVEL ${ANDROID_NATIVE_API_LEVEL} ) 1700 | set( ARM_TARGET "${ANDROID_ABI}" ) 1701 | set( ARMEABI_NDK_NAME "${ANDROID_NDK_ABI_NAME}" ) 1702 | endif() 1703 | 1704 | 1705 | # Variables controlling behavior or set by cmake toolchain: 1706 | # ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "x86", "mips" 1707 | # ANDROID_NATIVE_API_LEVEL : 3,4,5,8,9,14 (depends on NDK version) 1708 | # ANDROID_STL : gnustl_static/gnustl_shared/stlport_static/stlport_shared/gabi++_static/gabi++_shared/system_re/system/none 1709 | # ANDROID_FORBID_SYGWIN : ON/OFF 1710 | # ANDROID_NO_UNDEFINED : ON/OFF 1711 | # ANDROID_SO_UNDEFINED : OFF/ON (default depends on NDK version) 1712 | # ANDROID_FUNCTION_LEVEL_LINKING : ON/OFF 1713 | # ANDROID_GOLD_LINKER : ON/OFF 1714 | # ANDROID_NOEXECSTACK : ON/OFF 1715 | # ANDROID_RELRO : ON/OFF 1716 | # ANDROID_FORCE_ARM_BUILD : ON/OFF 1717 | # ANDROID_STL_FORCE_FEATURES : ON/OFF 1718 | # ANDROID_SET_OBSOLETE_VARIABLES : ON/OFF 1719 | # Can be set only at the first run: 1720 | # ANDROID_NDK 1721 | # ANDROID_STANDALONE_TOOLCHAIN 1722 | # ANDROID_TOOLCHAIN_NAME : the NDK name of compiler toolchain 1723 | # ANDROID_NDK_HOST_X64 : try to use x86_64 toolchain (default for x64 host systems) 1724 | # ANDROID_NDK_LAYOUT : the inner NDK structure (RELEASE, LINARO, ANDROID) 1725 | # LIBRARY_OUTPUT_PATH_ROOT : 1726 | # NDK_CCACHE : 1727 | # Obsolete: 1728 | # ANDROID_API_LEVEL : superseded by ANDROID_NATIVE_API_LEVEL 1729 | # ARM_TARGET : superseded by ANDROID_ABI 1730 | # ARM_TARGETS : superseded by ANDROID_ABI (can be set only) 1731 | # ANDROID_NDK_TOOLCHAIN_ROOT : superseded by ANDROID_STANDALONE_TOOLCHAIN (can be set only) 1732 | # ANDROID_USE_STLPORT : superseded by ANDROID_STL=stlport_static 1733 | # ANDROID_LEVEL : superseded by ANDROID_NATIVE_API_LEVEL (completely removed) 1734 | # 1735 | # Primary read-only variables: 1736 | # ANDROID : always TRUE 1737 | # ARMEABI : TRUE for arm v6 and older devices 1738 | # ARMEABI_V6 : TRUE for arm v6 1739 | # ARMEABI_V7A : TRUE for arm v7a 1740 | # NEON : TRUE if NEON unit is enabled 1741 | # VFPV3 : TRUE if VFP version 3 is enabled 1742 | # X86 : TRUE if configured for x86 1743 | # MIPS : TRUE if configured for mips 1744 | # BUILD_ANDROID : always TRUE 1745 | # BUILD_WITH_ANDROID_NDK : TRUE if NDK is used 1746 | # BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used 1747 | # ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform 1748 | # ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86" or "mips" depending on ANDROID_ABI 1749 | # ANDROID_NDK_RELEASE : one of r5, r5b, r5c, r6, r6b, r7, r7b, r7c, r8, r8b, r8c, r8d, r8e, r9, r9b, r9c, r9d; set only for NDK 1750 | # ANDROID_ARCH_NAME : "arm" or "x86" or "mips" depending on ANDROID_ABI 1751 | # ANDROID_SYSROOT : path to the compiler sysroot 1752 | # TOOL_OS_SUFFIX : "" or ".exe" depending on host platform 1753 | # ANDROID_COMPILER_IS_CLANG : TRUE if clang compiler is used 1754 | # Obsolete: 1755 | # ARMEABI_NDK_NAME : superseded by ANDROID_NDK_ABI_NAME 1756 | # 1757 | # Secondary (less stable) read-only variables: 1758 | # ANDROID_COMPILER_VERSION : GCC version used 1759 | # ANDROID_CXX_FLAGS : C/C++ compiler flags required by Android platform 1760 | # ANDROID_SUPPORTED_ABIS : list of currently allowed values for ANDROID_ABI 1761 | # ANDROID_TOOLCHAIN_MACHINE_NAME : "arm-linux-androideabi", "arm-eabi" or "i686-android-linux" 1762 | # ANDROID_TOOLCHAIN_ROOT : path to the top level of toolchain (standalone or placed inside NDK) 1763 | # ANDROID_CLANG_TOOLCHAIN_ROOT : path to clang tools 1764 | # ANDROID_SUPPORTED_NATIVE_API_LEVELS : list of native API levels found inside NDK 1765 | # ANDROID_STL_INCLUDE_DIRS : stl include paths 1766 | # ANDROID_RTTI : if rtti is enabled by the runtime 1767 | # ANDROID_EXCEPTIONS : if exceptions are enabled by the runtime 1768 | # ANDROID_GCC_TOOLCHAIN_NAME : read-only, differs from ANDROID_TOOLCHAIN_NAME only if clang is used 1769 | # ANDROID_CLANG_VERSION : version of clang compiler if clang is used 1770 | # ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product//obj/lib/libm.so) to workaround unresolved `sincos` 1771 | # 1772 | # Defaults: 1773 | # ANDROID_DEFAULT_NDK_API_LEVEL 1774 | # ANDROID_DEFAULT_NDK_API_LEVEL_${ARCH} 1775 | # ANDROID_NDK_SEARCH_PATHS 1776 | # ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH 1777 | # ANDROID_SUPPORTED_ABIS_${ARCH} 1778 | # ANDROID_SUPPORTED_NDK_VERSIONS 1779 | 1780 | -------------------------------------------------------------------------------- /toolchain/ios.cmake: -------------------------------------------------------------------------------- 1 | # This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake 2 | # files which are included with CMake 2.8.4 3 | # It has been altered for iOS development 4 | 5 | # Options: 6 | # 7 | # IOS_PLATFORM = OS (default) or SIMULATOR 8 | # This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders 9 | # OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch. 10 | # SIMULATOR - used to build for the Simulator platforms, which have an x86 arch. 11 | # 12 | # CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder 13 | # By default this location is automatcially chosen based on the IOS_PLATFORM value above. 14 | # If set manually, it will override the default location and force the user of a particular Developer Platform 15 | # 16 | # CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder 17 | # By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value. 18 | # In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path. 19 | # If set manually, this will force the use of a specific SDK version 20 | 21 | # Macros: 22 | # 23 | # set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE) 24 | # A convenience macro for setting xcode specific properties on targets 25 | # example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1") 26 | # 27 | # find_host_package (PROGRAM ARGS) 28 | # A macro used to find executable programs on the host system, not within the iOS environment. 29 | # Thanks to the android-cmake project for providing the command 30 | 31 | # Standard settings 32 | set (CMAKE_SYSTEM_NAME Darwin) 33 | set (CMAKE_SYSTEM_VERSION 1) 34 | set (UNIX True) 35 | set (APPLE True) 36 | set (IOS True) 37 | 38 | # Required as of cmake 2.8.10 39 | set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE) 40 | 41 | # Determine the cmake host system version so we know where to find the iOS SDKs 42 | find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin) 43 | if (CMAKE_UNAME) 44 | exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION) 45 | string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}") 46 | endif (CMAKE_UNAME) 47 | 48 | # Force the compilers to gcc for iOS 49 | include (CMakeForceCompiler) 50 | CMAKE_FORCE_C_COMPILER (/usr/bin/clang Apple) 51 | CMAKE_FORCE_CXX_COMPILER (/usr/bin/clang++ Apple) 52 | set(CMAKE_AR ar CACHE FILEPATH "" FORCE) 53 | 54 | # Skip the platform compiler checks for cross compiling 55 | set (CMAKE_CXX_COMPILER_WORKS TRUE) 56 | set (CMAKE_C_COMPILER_WORKS TRUE) 57 | 58 | # All iOS/Darwin specific settings - some may be redundant 59 | set (CMAKE_SHARED_LIBRARY_PREFIX "lib") 60 | set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") 61 | set (CMAKE_SHARED_MODULE_PREFIX "lib") 62 | set (CMAKE_SHARED_MODULE_SUFFIX ".so") 63 | set (CMAKE_MODULE_EXISTS 1) 64 | set (CMAKE_DL_LIBS "") 65 | 66 | set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") 67 | set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") 68 | set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") 69 | set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") 70 | 71 | # Hidden visibilty is required for cxx on iOS 72 | set (CMAKE_C_FLAGS_INIT "") 73 | set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden -isysroot ${CMAKE_OSX_SYSROOT}") 74 | 75 | set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}") 76 | set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}") 77 | 78 | set (CMAKE_PLATFORM_HAS_INSTALLNAME 1) 79 | set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names") 80 | set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names") 81 | set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") 82 | set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") 83 | set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a") 84 | 85 | # hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree 86 | # (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache 87 | # and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun) 88 | # hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex 89 | if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) 90 | find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool) 91 | endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) 92 | 93 | # Setup iOS platform unless specified manually with IOS_PLATFORM 94 | if (NOT DEFINED IOS_PLATFORM) 95 | set (IOS_PLATFORM "OS") 96 | endif (NOT DEFINED IOS_PLATFORM) 97 | set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform") 98 | 99 | # Check the platform selection and setup for developer root 100 | if (${IOS_PLATFORM} STREQUAL "OS") 101 | set (IOS_PLATFORM_LOCATION "iPhoneOS.platform") 102 | 103 | # This causes the installers to properly locate the output libraries 104 | set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos") 105 | elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") 106 | set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") 107 | 108 | # This causes the installers to properly locate the output libraries 109 | set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") 110 | elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR64") 111 | set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") 112 | 113 | # This causes the installers to properly locate the output libraries 114 | set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") 115 | else (${IOS_PLATFORM} STREQUAL "OS") 116 | message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR") 117 | endif (${IOS_PLATFORM} STREQUAL "OS") 118 | 119 | # Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT 120 | # Note Xcode 4.3 changed the installation location, choose the most recent one available 121 | set (XCODE_POST_43_ROOT "/Applications/Xcode.app/Contents/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") 122 | set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") 123 | if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) 124 | if (EXISTS ${XCODE_POST_43_ROOT}) 125 | set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT}) 126 | elseif(EXISTS ${XCODE_PRE_43_ROOT}) 127 | set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT}) 128 | endif (EXISTS ${XCODE_POST_43_ROOT}) 129 | endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) 130 | set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform") 131 | 132 | # Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT 133 | if (NOT DEFINED CMAKE_IOS_SDK_ROOT) 134 | file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*") 135 | if (_CMAKE_IOS_SDKS) 136 | list (SORT _CMAKE_IOS_SDKS) 137 | list (REVERSE _CMAKE_IOS_SDKS) 138 | list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT) 139 | else (_CMAKE_IOS_SDKS) 140 | message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.") 141 | endif (_CMAKE_IOS_SDKS) 142 | message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}") 143 | endif (NOT DEFINED CMAKE_IOS_SDK_ROOT) 144 | set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK") 145 | 146 | # Set the sysroot default to the most recent SDK 147 | set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support") 148 | 149 | # set the architecture for iOS 150 | # NOTE: Currently both ARCHS_STANDARD_32_BIT and ARCHS_UNIVERSAL_IPHONE_OS set armv7 only, so set both manually 151 | if (${IOS_PLATFORM} STREQUAL "OS") 152 | set (IOS_ARCH armv7 armv7s arm64) 153 | elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") 154 | set (IOS_ARCH i386) 155 | elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR64") 156 | set (IOS_ARCH x86_64) 157 | endif (${IOS_PLATFORM} STREQUAL "OS") 158 | 159 | set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS") 160 | 161 | # Set the find root to the iOS developer roots and to user defined paths 162 | set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root") 163 | 164 | # default to searching for frameworks first 165 | set (CMAKE_FIND_FRAMEWORK FIRST) 166 | 167 | # set up the default search directories for frameworks 168 | set (CMAKE_SYSTEM_FRAMEWORK_PATH 169 | ${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks 170 | ${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks 171 | ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks 172 | ) 173 | 174 | # only search the iOS sdks, not the remainder of the host filesystem 175 | set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) 176 | set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 177 | set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 178 | 179 | 180 | # This little macro lets you set any XCode specific property 181 | macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE) 182 | set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE}) 183 | endmacro (set_xcode_property) 184 | 185 | 186 | # This macro lets you find executable programs on the host system 187 | macro (find_host_package) 188 | set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 189 | set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) 190 | set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) 191 | set (IOS FALSE) 192 | 193 | find_package(${ARGN}) 194 | 195 | set (IOS TRUE) 196 | set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) 197 | set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 198 | set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 199 | endmacro (find_host_package) 200 | 201 | --------------------------------------------------------------------------------