# CMake筆記 ## Configure CMake CMakeLists.txt是CMake用來build C/C++ libraries所使用的build script NDK底下有兩種方式可以build C/C++ libraries,ndk-build和CMake ndk-build是for Android特化的方式,CMake則是跨平台使用 Android Developers對CMake build的說明(https://developer.android.com/studio/projects/configure-cmake) CMake Documentation and Community (https://cmake.org/documentation/) ## 基本內容 從Android Developer - Configure-cmake的範例來看,基本如下 會build出libnative-lib為名的so檔 ``` # Sets the minimum version of CMake required to build your native library. # This ensures that a certain set of CMake features is available to # your build. cmake_minimum_required(VERSION 3.4.1) # Specifies a library name, specifies whether the library is STATIC or # SHARED, and provides relative paths to the source code. You can # define multiple libraries by adding multiple add_library() commands, # and CMake builds them for you. When you build your app, Gradle # automatically packages shared libraries with your APK. add_library( # Specifies the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). src/main/cpp/native-lib.cpp ) # Specifies a path to native header files. include_directories(src/main/cpp/include/) ``` 若是需要加入NDK library之類的,可用find_library ``` find_library( # Defines the name of the path variable that stores the # location of the NDK library. log-lib # Specifies the name of the NDK library that # CMake needs to locate. log ) ``` 上面找到log這個library後,便可以用target_link_libraries來連結其它library ``` # Links your native library against one or more other native libraries. target_link_libraries( # Specifies the target library. native-lib # Links the log library to the target library. ${log-lib} ) ``` 如果是加入在別的地方已build好的非NDK library,會改為使用add_library並以IMPORTED的方式註明 import進來的library如果只是要打包在一起而非有build-time dependency的話,就不需要加進target_link_libraries ``` add_library( imported-lib SHARED IMPORTED ) ``` ## 以正在使用的libbitxxx.so為例 ``` cmake_minimum_required(VERSION 3.4.1) project(bitxxxxxxxxx) add_library( # Sets the name of the library. bitxxx # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). JniBitxxxxxxxxx.cpp verxxxx.c) set(include-headers-bitxxxxxxxxx inc) include_directories( ${include-headers-bitxxxxxxxxx} ) find_library( # Sets the name of the path variable. log-lib # Specifies the name of the NDK library that # you want CMake to locate. log) target_link_libraries( # Specifies the target library. bitxxx jnigraphics # Bitmap library, link to libjnigraphics, #include <android/bitmap.h> # Links the target library to the log library # included in the NDK. ${log-lib}) ``` ## 遇到的問題 ### linker類型 其實不確定問題的原因,原makefile中有設定 ``` LOCAL_LDFLAGS += -fuse-ld=gold ``` 下下面兩段error的部份是一起出現的,__bss_start等等的都是跟linker有關的部份 [How can I add linker flag for libraries with CMake? - Stack Overflow](https://stackoverflow.com/questions/24532853/how-can-i-add-linker-flag-for-libraries-with-cmake) 目前已知下面這個方式是能build過的方式 有看過-fuse-ld=gold,這是google設計的linker,但會build error 應該就是import的so不是用gold所以出錯 ``` set (CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=lld") ``` 主要是shared linker的設定格式 之前試好久都失敗是因為看到錯誤的寫法 ``` set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=lld") ``` ``` > Task :app:buildCMakeRelWithDebInfo[arm64-v8a] C/C++: ninja: Entering directory `C:\Users\vincent3_chen\AndroidStudioProjects\AsusCamera2\app\.cxx\RelWithDebInfo\1z6h4n4e\arm64-v8a' C/C++: ld: error: found local symbol '__bss_start' in global part of symbol table in file C:/Users/vincent3_chen/AndroidStudioProjects/AsusCamera2/app/src/main/jniSrcs/feature_dit_light_art/jni/lib/arm64-v8a/libxditk_LightArt.so C/C++: ld: error: found local symbol '_end' in global part of symbol table in file C:/Users/vincent3_chen/AndroidStudioProjects/AsusCamera2/app/src/main/jniSrcs/feature_dit_light_art/jni/lib/arm64-v8a/libxditk_LightArt.so C/C++: ld: error: found local symbol '_edata' in global part of symbol table in file C:/Users/vincent3_chen/AndroidStudioProjects/AsusCamera2/app/src/main/jniSrcs/feature_dit_light_art/jni/lib/arm64-v8a/libxditk_LightArt.so C/C++: clang++: error: linker command failed with exit code 1 (use -v to see invocation) ld: error: found local symbol '__bss_start' in global part of symbol table in file C:/Users/vincent3_chen/AndroidStudioProjects/AsusCamera2/app/src/main/jniSrcs/feature_dit_light_art/jni/lib/arm64-v8a/libxditk_LightArt.so ld: error: found local symbol '_end' in global part of symbol table in file C:/Users/vincent3_chen/AndroidStudioProjects/AsusCamera2/app/src/main/jniSrcs/feature_dit_light_art/jni/lib/arm64-v8a/libxditk_LightArt.so ld: error: found local symbol '_edata' in global part of symbol table in file C:/Users/vincent3_chen/AndroidStudioProjects/AsusCamera2/app/src/main/jniSrcs/feature_dit_light_art/jni/lib/arm64-v8a/libxditk_LightArt.so > Task :app:buildCMakeRelWithDebInfo[arm64-v8a] FAILED ``` ``` Execution failed for task ':app:buildCMakeRelWithDebInfo[arm64-v8a]'. > com.android.ide.common.process.ProcessException: ninja: Entering directory C:\Users\vincent3_chen\AndroidStudioProjects\AsusCamera2\app\.cxx\RelWithDebInfo\1z6h4n4e\arm64-v8a' [1/2] Building CXX object feature_dit_light_art/jni/CMakeFiles/ditlightart.dir/JniDITLightArt.cpp.o [2/2] Linking CXX shared library C:\Users\vincent3_chen\AndroidStudioProjects\AsusCamera2\app\build\intermediates\cxx\RelWithDebInfo\1z6h4n4e\obj\arm64-v8a\libditlightart.so FAILED: C:/Users/vincent3_chen/AndroidStudioProjects/AsusCamera2/app/build/intermediates/cxx/RelWithDebInfo/1z6h4n4e/obj/arm64-v8a/libditlightart.so cmd.exe /C "cd . && C:\Users\vincent3_chen\AppData\Local\Android\Sdk\ndk\23.1.7779620\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=aarch64-none-linux-android28 --sysroot=C:/Users/vincent3_chen/AppData/Local/Android/Sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/windows-x86_64/sysroot -fPIC -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fexceptions -frtti -stdlib=libc++ -O2 -g -DNDEBUG -Wl,--build-id=sha1 -Wl,--no-rosegment -Wl,--fatal-warnings -Qunused-arguments -Wl,--no-undefined -shared -Wl,-soname,libditlightart.so -o C:\Users\vincent3_chen\AndroidStudioProjects\AsusCamera2\app\build\intermediates\cxx\RelWithDebInfo\1z6h4n4e\obj\arm64-v8a\libditlightart.so feature_dit_light_art/jni/CMakeFiles/ditlightart.dir/JniDITLightArt.cpp.o C:/Users/vincent3_chen/AndroidStudioProjects/AsusCamera2/app/src/main/jniSrcs/feature_dit_light_art/jni/lib/arm64-v8a/libxditk_LightArt.so C:/Users/vincent3_chen/AppData/Local/Android/Sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/lib/aarch64-linux-android/28/liblog.so -static-libstdc++ -latomic -lm && cd ." ld: error: found local symbol '__bss_start' in global part of symbol table in file C:/Users/vincent3_chen/AndroidStudioProjects/AsusCamera2/app/src/main/jniSrcs/feature_dit_light_art/jni/lib/arm64-v8a/libxditk_LightArt.so ld: error: found local symbol '_end' in global part of symbol table in file C:/Users/vincent3_chen/AndroidStudioProjects/AsusCamera2/app/src/main/jniSrcs/feature_dit_light_art/jni/lib/arm64-v8a/libxditk_LightArt.so ld: error: found local symbol '_edata' in global part of symbol table in file C:/Users/vincent3_chen/AndroidStudioProjects/AsusCamera2/app/src/main/jniSrcs/feature_dit_light_art/jni/lib/arm64-v8a/libxditk_LightArt.so clang++: error: linker command failed with exit code 1 (use -v to see invocation) ninja: build stopped: subcommand failed. ``` ### C flags android makefile會有像LOCAL_C_FLAGS/LOCAL_CPP_FLAGS之類的 雖然有google到在CMake可以使用add_compile_options來添加 ``` add_compile_options(-ffast-math -O3) ``` 後來有看到另一種方式 ``` set(CMAKE_C_FLAGS "-ffast-math -O3") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffast-math -O3") ``` 跟AI詢問過後,上面是override,下面會append到現有的flags上 ${CMAKE_C_FLAGS}代表當前的flags 最後用message的方式印出${CMAKE_C_FLAGS} 在Build window中有看到add_compile_option沒效,可能沒有正確使用 set的方式有正確設定flags 看起來是適用的對象和使用方式不一樣,也不是檢查CMAKE_C_FLAGS [add_compile_options加入某些编译选项(-pg)无效](https://www.cnblogs.com/bluettt/p/12952543.html) AI建議這樣檢查,但我還沒試 ``` # Define your target add_executable(MyApp main.cpp) # replace with your source files # Set any desired compile options add_compile_options(-ffast-math -O3) # Diagnostic command to print out the compile options get_target_property(TARGET_COMPILE_OPTIONS MyApp COMPILE_OPTIONS) message(STATUS "Compile options for MyApp: ${TARGET_COMPILE_OPTIONS}") ``` ## reference from other note 參考自 [Android NDK 開發](https://hackmd.io/NOzQJQo4R0i5iVAD9tVyxw?view) CMake 常用命令 * CMake **常用命令** | 命令 | 功能 | | ---------------------- | ---- | | set(<代號> <來源>) | 可為後方來源建立一個代號,之後使用 ${代號} 及可 `set(DIR "C:/File/main.c")`| | set(<功能> <on/off/other>) | 開啟 or 關閉某些功能,或指定參數 set(CMAKE_CXX_STANDARD 14)| | project(<項目名稱> LANGUAGES C) | Android 中可以不用指定 | | cmake_minimum_required | CMake 最低版本 **(衝突時以 gradle 中 externalNativeBuild 設定為準)** | | include_directories(路徑) | **指定 ==++原生代碼++ or ++so 庫++的路徑==** | | add_library(<庫名稱> <形式> <庫路徑(可多個)>) | **添加原 (Source) 文件、自己寫的程式** | | find_library | 添加 NDK API,也就是 Android NDK 提供的庫 | | set_target_properties | **指定特定庫的路徑 or ++指定生成的目標庫導出路徑++** | | target_link_library | 將 預編譯庫 **連接** 到自己的庫 | | aux_source_directory | 找在特定路徑下的文件,**可統整多個文件在一起** | | file(<區域> <代號> <路徑>) | 編譯原文件 | # Reference Android Developes各種說明 [Configure CMake  |  Android Studio  |  Android Developers](https://developer.android.com/studio/projects/configure-cmake) [CMake  |  Android NDK  |  Android Developers](https://developer.android.com/ndk/guides/cmake) [Install and configure the NDK and CMake  |  Android Studio  |  Android Developers](https://developer.android.com/studio/projects/install-ndk) [CmakeFlags  |  Android Developers](https://developer.android.com/reference/tools/gradle-api/8.1/com/android/build/api/dsl/CmakeFlags) [CMake Documentation and Community](https://cmake.org/documentation/) [How can I add linker flag for libraries with CMake?](https://stackoverflow.com/questions/24532853/how-can-i-add-linker-flag-for-libraries-with-cmake) [Android NDK 開發](https://hackmd.io/NOzQJQo4R0i5iVAD9tVyxw?view)