# 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)