文章目录
- 一、前言
- 二、使用NDK进行编译的相关代码
- 四、使用交叉工具链进行编译
- 四、参考链接
一、前言
目前Android编译.so的话使用Android Studio比较简单,但是有时候时候Android Studio的话还需要创建一个Android的项目,这里记录下脱离Android Studio单纯使用Cmake和C++开发工具Clion(或者其他的开发工具也行,这些开发工具和Android Studio不一样,哪一种工具都行)。
实际上编译.so还有比较简单的方式。比如直接在linux环境下面使用cmake编译c++项目即可,这时候出现的就是.so库。但是如果开发环境是Mac或者Windows的话,就会生成dylib或者exe文件,不是我们想要的文件,所以就需要使用交叉编译的技术。
Cmake对于编译Android的.so文件提供了两种方式: NDK或者交叉工具链。由于本人从事Android开发,有现成的NDK依赖,而交叉编译链需要下载。所以就使用NDK进行编译,不过根据此进行修改,大概也是可以的。后续有空会记录使用交叉工具链的编译方式。
项目比较乱,后面再做整理
不过不管使用NDK或者交叉工具链哪种方式都需要跟NDK进行关联,不会出现脱离NDK就编译处.so的问题
二、使用NDK进行编译的相关代码
开发工具为CLion,需要注意的是Android Studio和CLion都采用了ninja构建系统,如果使用其他构建系统需要进行修改,不过文中代码已经有该代码,到时候改下路径即可
整体项目结构如下:
这其中的核心代码为:
需要注意的是该代码需要写在project(untitled VERSION 1.0)
函数调用之前
# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_VERSION 21) # API level
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)
set(CMAKE_ANDROID_NDK /Users/c/Documents/sdk/android/ndk/25.1.8937393)
#set(CMAKE_TOOLCHAIN_FILE /Users/c/Documents/sdk/android/ndk/25.1.8937393/build/cmake/android.toolchain.cmake)
set(CMAKE_MAKE_PROGRAM /Users/c/Documents/sdk/android/cmake/3.22.1/bin/ninja)
#set(CMAKE_ANDROID_STL_TYPE gnustl_static) # 需要注意的是NDK不支持这个属性,可能是NDK版本原因,所以使用c++_shared,
set(CMAKE_ANDROID_STL_TYPE c++_shared)
set(CMAKE_EXPORT_COMPILE_COMMANDS NO)
CMakeLists.txt
cmake_minimum_required(VERSION 3.23) # 这是Cmake版本
#======这一段来自Android开发者平台:https://developer.android.google.cn/ndk/guides/cmake?hl=zh-cn#using_prebuilt_libraries
#-DCMAKE_FIND_ROOT_PATH=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/.cxx/cmake/universalDebug/prefab/armeabi-v7a/prefab
#-DCMAKE_BUILD_TYPE=Debug
#-DCMAKE_TOOLCHAIN_FILE=${HOME}/Android/Sdk/ndk/22.1.7171670/build/cmake/android.toolchain.cmake
#-DANDROID_ABI=armeabi-v7a
#-DANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
#-DANDROID_PLATFORM=android-23
#-DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a
#-DCMAKE_ANDROID_NDK=${HOME}/Android/Sdk/ndk/22.1.7171670
#-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
#-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
#-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${HOME}/Dev/github-projects/googlesamples/ndk-samples/hello-jni/app/build/intermediates/cmake/universalDebug/obj/armeabi-v7a
#-DCMAKE_MAKE_PROGRAM=${HOME}/Android/Sdk/cmake/3.10.2.4988404/bin/ninja
#-DCMAKE_SYSTEM_NAME=Android
#-DCMAKE_SYSTEM_VERSION=23
#====== end ======
# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_VERSION 21) # API level
set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)
set(CMAKE_ANDROID_NDK /Users/c/Documents/sdk/android/ndk/25.1.8937393)
set(CMAKE_MAKE_PROGRAM /Users/c/Documents/sdk/android/cmake/3.22.1/bin/ninja)
#set(CMAKE_ANDROID_STL_TYPE gnustl_static) # 需要注意的是NDK不支持这个属性,可能是NDK版本原因,所以使用c++_shared,
set(CMAKE_ANDROID_STL_TYPE c++_shared)
set(CMAKE_EXPORT_COMPILE_COMMANDS NO)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
project(untitled VERSION 1.0)
add_subdirectory(libscanner)
configure_file(square.h.in square.h)
# specify the C++ standard
add_library(tutorial_compiler_flags INTERFACE)
target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
# 通过BUILD_SHARED_LIBS 创建共享库,后面值需要设置为ON,
# 这个属性写到这里,如果libscanner使用这个值的话有时候会报找不到的错误,如果经过反复Build后无法解决,将该属性写到相关的libscanner的CMakeLists.txt。但是这样的话最终rebuld后只会生成libscanner的.so。不过这也是预想的情况本身顶层目录也没有要求生成.so文件
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
add_executable(untitled square_main.cpp)
target_link_libraries(untitled PUBLIC scanner tutorial_compiler_flags)
target_include_directories(untitled PUBLIC
"${PROJECT_BINARY_DIR}"
"${PROJECT_SOURCE_DIR}/libscanner"
)
# 打印日志
message("---PROJECT_BINARY_DIR--${PROJECT_BINARY_DIR}")
message("---PROJECT_SOURCE_DIR--${PROJECT_SOURCE_DIR}")
message("---libscanner头文件--${PROJECT_SOURCE_DIR}/libscanner")
libscanner/CMakeLists.txt
add_library(scanner scanner.cpp) # 默认编译成静态库
# state that anybody linking to us needs to include the current source dir
# to find MathFunctions.h, while we don't.
target_include_directories(scanner
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
#add_executable(MakeTable scanner.cpp)
#target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags)
aux_source_directory(. SRC_LIST) #把当前目录(.)下所有源代码文件和头文件加入变量SRC_LIST
#ADD_EXECUTABLE(hello ${SRC_LIST}) #生成应用程序 hello (在windows下会自动生成hello.exe)
# 将相关文件添加到SqrtLibrary库
add_library(SqrtLibrary SHARED
${SRC_LIST}
)
# 文件应该去哪个路径下面查找
target_include_directories(SqrtLibrary PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
)
# 将tutorial_compiler_flags库链接到SqrtLibrary
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
# 将SqrtLibrary库链接到libscanner
target_link_libraries(scanner PRIVATE SqrtLibrary)
# 将tutorial_compiler_flags库链接到libscanner
target_link_libraries(scanner PUBLIC tutorial_compiler_flags)
message("YM--->${BUILD_SHARED_LIBS}")
# state that SqrtLibrary need PIC when the default is shared libraries
set_target_properties(SqrtLibrary PROPERTIES
POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
)
写完后重新ReBuild后即可在build文件夹下找到生成的.so库
四、使用交叉工具链进行编译
如果使用交叉工具链的话,编译跟上述方式相比只需要更改一行代码,由于NDK 新版r-19之后的改动,所以使用起来会更加简单。只要指定CMAKE_TOOLCHAIN_FILE属性即可
#set(CMAKE_ANDROID_NDK /Users/c/Documents/sdk/android/ndk/25.1.8937393)
set(CMAKE_TOOLCHAIN_FILE /Users/c/Documents/sdk/android/ndk/25.1.8937393/build/cmake/android.toolchain.cmake)
四、参考链接
- Android 官网的CMake介绍
- 深入理解使用CMake编译 NDK 程序
- cmake-toolchains(7)
- android/ndk-samples
- CMAKE 在Linux下 构建android 编译、打包、发布环境
- android 交叉编译常用库(cmake