Cmake学习记录(九)--使用Cmake交叉编译Android .so库

本文介绍了如何在不使用AndroidStudio的情况下,利用CMake和NDK编译适用于Android平台的SO库。文章详细讲述了两种方法:一是直接使用NDK进行编译,二是通过交叉工具链进行编译,并提供了相关代码示例。整个过程强调了在不同操作系统上生成正确格式的库文件的必要性,以及CMake配置中的关键设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

注意:本教程没有关于JNI接口的写法,只是把C代码编译成适合android平台的so库,想查看完整代码可以参考文末的第9条参考链接
目前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或者交叉工具链。不管使用NDK或者交叉工具链哪种方式都需要跟NDK进行关联,没有脱离NDK就编译处.so的可能

二、使用NDK进行编译的相关代码

开发工具为CLion,需要注意的是Android Studio和CLion都采用了ninja构建系统,如果使用其他构建系统需要进行修改,不过文中代码已经有该代码,到时候改下路径即可
整体项目结构如下:
在这里插入图片描述
这其中的核心代码为:
需要注意的是该代码中的set部分需要写在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)

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")

aux_source_directory(. SRC_LIST) #把当前目录(.)下所有源代码文件和头文件加入变量SRC_LIST
#ADD_EXECUTABLE(hello ${SRC_LIST}) #生成应用程序 hello (在windows下会自动生成hello.exe)

# 将相关文件添加到SqrtLibrary库 ,最终编译成共享库 .so
add_library(SqrtLibrary SHARED
        ${SRC_LIST}
        )

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)

五、参考链接

  1. Android 官网的CMake介绍
  2. 深入理解使用CMake编译 NDK 程序
  3. cmake-toolchains(7)
  4. android/ndk-samples
  5. CMAKE 在Linux下 构建android 编译、打包、发布环境
  6. android 交叉编译常用库(cmake
  7. 10、NDK交叉编译小记
  8. cmake : add_library详解
  9. MAC环境编译Android环境下的FFmpeg6.0版本
<think>好的,我现在需要帮助用户在Android Studio中配置和交叉编译CMakeLists.txt的C++工程。用户可能不太熟悉整个流程,所以我要一步步解释清楚,同时结合提供的引用内容,确保信息准确。 首先,用户提到了交叉编译,所以需要明确在Android环境下如何使用CMake。根据引用[2],Android Studio通过CMake实现交叉编译生成动态so文件,步骤包括创建cpp目录、配置CMakeLists.txt,以及修改build.gradle。我需要详细说明这些步骤。 接下来,引用[3]提到NDK编译脚本可以是CMakeLists.txt,并且在build.gradle中配置externalNativeBuild。这说明用户需要在Gradle脚本中设置CMake路径和参数,这也是关键点之一。 然后,引用[4]提到在工程中放入C++,这可能涉及到如何组织项目结构,比如将源代码放在src/main/cpp目录下,确保CMake正确找到源文件。 我需要整理出具体的步骤,可能包括: 1. 创建C++源代码目录。 2. 编写CMakeLists.txt,配置编译选项和文件。 3. 修改build.gradle文件,链接CMake并传递参数。 4. 可能的NDK配置,如指定ABI和工具链。 同时,要检查是否有遗漏的部分,比如NDK的安装和配置,是否需要在CMakeLists.txt中设置交叉编译工具链,或者依赖Android.toolchain.cmake。根据引用[3],可能需要使用externalNativeBuild块来配置CMake参数,比如abiFilters。 还需要注意用户是否需要生成动态so文件)或静态,以及如何处理依赖项。例如,在CMakeLists.txt中使用add_library和target_link_libraries。 最后,生成相关问题,可能涉及优化编译速度、处理依赖、调试方法等,这些都是用户后续可能遇到的。</think>### 在 Android Studio 中配置和交叉编译 C++ 工程的步骤 #### 1. **创建 C++ 源代码目录** - 在 `src/main/` 下新建 `cpp` 目录,将 C++ 源代码文件(`.cpp`、`.h`)放入此目录[^2]。 #### 2. **配置 CMakeLists.txt 文件** - 在项目根目录或 `app` 模块目录下创建 `CMakeLists.txt`,并配置以下内容: ```cmake cmake_minimum_required(VERSION 3.10.2) project("MyCppProject") # 添加源代码文件 add_library( mylib # 生成的名称 SHARED # 生成动态.so) src/main/cpp/main.cpp # 源代码路径 ) # 链接其他(如log) target_link_libraries(mylib android log) ``` - 若需交叉编译,需指定 Android NDK 工具链。通常 Android Studio 会自动处理,但可手动配置: ```cmake set(CMAKE_TOOLCHAIN_FILE ${ANDROID_NDK}/build/cmake/android.toolchain.cmake) ``` #### 3. **修改 build.gradle 配置** - 在 `app/build.gradle` 中添加 CMake 路径和编译参数: ```groovy android { defaultConfig { externalNativeBuild { cmake { cppFlags "-std=c++17" # 设置 C++ 标准 arguments "-DANDROID_STL=c++_shared" # 指定 STL } } ndk { abiFilters "armeabi-v7a", "arm64-v8a" # 指定目标 ABI } } externalNativeBuild { cmake { path "CMakeLists.txt" # 指定 CMake 文件路径 } } } ``` #### 4. **同步并构建项目** - 点击 Android Studio 的 **Sync Project** 按钮,确保配置无误。 - 通过 **Build > Make Project** 编译生成 `.so` 文件,输出路径为 `build/intermediates/cmake/`。 #### 5. **关键注意事项** - **NDK 版本兼容性**:需在 `local.properties` 中指定 `ndk.dir`,或通过 SDK Manager 安装对应版本。 - **ABI 过滤**:在 `ndk.abiFilters` 中仅保留需要的架构以减少体积。 - **STL 选择**:若使用 C++ 标准特性,需在 CMake 中配置 `ANDROID_STL`[^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值