Android Studio上Cmake的搭建与使用—以生成动态/静态库

1、什么是Cmake?

​ C/C++ 的编译文件在不同平台是不一样的。Unix 下使用 makefile 文件编译,Windows 下使用 project 文件编译。而 CMake 则是一个跨平台的编译工具,它并不会直接编译出对象,而是根据自定义的语言规则(CMakeLists.txt)生成 对应 makefile 或 project 文件,然后再调用底层的编译.

​ 谷歌从AndroidStudio2.2以上就添加了Cmake方式来编译NDK代码,相较之前复杂的NDK-BUILDE方式,Cmake则简单很多。

2、什么是NDK?

​ NDK全名Native Develop Kit,andriod本地开发工具,是Google开发的一套方便开发者在Android 平台上开发Native 代码的工具;

​ 使用NDK自带的工具,可快速对C/C++代码进行构建、编译和打包,最终生成动态/静态库供开发者使用,且不容易被反编译;

3、如何导入NDK与Cmake环境?

3.1在Setting的Android SDK中勾选以下配置;

在这里插入图片描述

3.2 因为Cmake要用到NDK,所以Android NDK location需要指定本地NDK路径;

在这里插入图片描述

4、如何在已有AS项目中导入Cmake?

4.1导入Cmake相关文件;

​ 路径可以自定义,这里选择的是"app/src/main/cpp/",其中CMakeLists.txt是Cmake的执行脚本, test-jni.c是Jni文件,用于编译生成so库;
在这里插入图片描述

4.2. app工程关联Cmake

​ 打开app目录下的build.gradle(见上图红框),添加以下语句,使AS工程关联上Cmake用于编译;

​ 参考网址: https://www.cnblogs.com/qcjd/p/9324903.html

 android{
 	...
     defaultConfig {
     	...
         externalNativeBuild {
            cmake {
                cppFlags ""
       			
			  // Passes optional arguments to CMake.//编译选项,与makefile类似
	           //arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"

			  // Sets optional flags for the C compiler.预置C的宏
			  //cFlags "-D_EXAMPLE_C_FLAG1", "-D_EXAMPLE_C_FLAG2"

			  // Sets a flag to enable format macro constants for the C++ compiler.预置C++的宏
			  //cppFlags "-D__STDC_FORMAT_MACROS"
            }
        }
        ndk {//编译生成哪个CPU平台的库
            abiFilters 'armeabi-v7a','x86_64'
            //    ARMv5——armeabi
            //    ARMv7 ——armeabi-v7a
            //    ARMv8——arm64- v8a
            //    x86——x86
            //    MIPS ——mips
            //    MIPS64——mips64
            //    x86_64——x86_64
        }
    }
    ...
    externalNativeBuild {
        cmake {
            path file('src/main/cpp/CMakeLists.txt')  //CMakeLists.txt存放路径
            version "3.10.2"
        }
   }
   ...
}

5、Cmake常用语法介绍

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

project(NDK)
###############参考网址:https://www.cnblogs.com/qcjd/p/9324903.html


# ==========================================语法知识(start)=====================================
# 0==================<多文件编译生成库>=============================
#1、 设置多文件目录---方法1: (常用)
#1.1查找src/main/cpp目录下所有以*./c *.cpp文件并保存到DIR_SRCS变量里
file(GLOB DIR_SRCS “src/main/cpp/*.c” “src/main/cpp/*.cpp”)

#1.2不同级目录下的指定
file(GLOB DIR_SRCS “../src2/main/cpp/*.c” “../src3/main/cpp/*.cpp”)

#1.3如果cpp目录下还有别的子目录,但又不想每个子目录路径都制定过来,则可以用到递归查找
file(GLOB_RECURSE SRC_FILES "src/hello*")#注意:这里的目录不能有特殊字符,例如:<SerialPort_c>

#2、设置多文件目录---方法2:指定当前目录下的源文件,保存到<DIR_SRCS>变量中
aux_source_directory(. DIR_SRCS)

#3、关联1或2中的DIR_SRCS变量,生成库
# # SHARED: 动态库  STATIC:静态库、
add_library(hello-jni SHARED ${DIR_SRCS})

# 制定生成目标(可忽略)
add_executable(mathPowerDemo2 ${ALL_SRCS})

# ==================<引入已有预编译好的静态库/动态库>=========================
# 1.1、引入已有的预编译好的静态库
# StaticTest 可以随便起名字(原名:libStaticTest.a)
# IMPORTED: 表示静态库是以导入的形式添加进来(预编译静态库)
add_library(StaticTest STATIC IMPORTED)

# 1.2、引入已有的预编译好的动态库
# SharedTest 可以随便起名字(原名:libSharedTest.so)
# IMPORTED: 表示静态库是以导入的形式添加进来(预编译静态库)
add_library(SharedTest SHARED IMPORTED)

# 2.1、设置1.1/1.2中指定的动态库/静态库的导入路径
# 下面CMAKE_SOURCE_DIR 是系统预定义好的变量,代表当前CMakeLists.txt所在的目录
set_target_properties(StaticTest PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/static/armeabi-v7a/libStaticTest.a)

#下面${ANDROID_ABI}中的ANDROID_ABI应该指各个ABI版本的目录
# othermodule为库名称
set_target_properties(othermodule  PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libothermodule.so)

#    各个ABI版本
#    ARMv5——armeabi
#    ARMv7 ——armeabi-v7a
#    ARMv8——arm64- v8a
#    x86——x86
#    MIPS ——mips
#    MIPS64——mips64
#    x86_64——x86_64

# 2.2、设置动态库的导入路径
# 下面CMAKE_SOURCE_DIR 是系统预定义好的变量,代表当前CMakeLists.txt所在的目录
set_target_properties(StaticTest PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/static/armeabi-v7a/libSharedTest.so)


# 3.1 额外头文件查找路径设置 相当于makefile中的-I
include_directories(src/main/include)//本地或者外部库需要的头文件路径指定

# 3.2 使用其余CMakeLists.txt配置
# 额外引入src/main/subcmakelist目录的cmakelist
add_subdirectory(src/main/subcmakelist)

# 3.3 增加指定的宏定义 相当于-D
add_definitions(-D_LINUX -D_ANDROID)

     

# 4、配置动态库链接,生成native-lib动态库需要用到StaticTest log动态或者静态库
target_link_libraries( # Specifies the target library.
                        native-lib
                        # libTest.so 可以去掉lib与.so
                        StaticTest
                        SharedTest
                        log )

# 动态库这样引入没有版本差异,如果像上面那样引入会有版本问题
# CMAKE_CXX_FLAGS 会传给c++编译器
# CMAKE_C_FLAGS 会传给c编译器
# CMAKE_SOURCE_DIR 的值是当前CMakelist.txt所在目录
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a")
# ===========================================语法知识(end)========================================



# ===========================================使用范本========================================
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

# 配置so库信息
add_library( # Sets the name of the library.
            # 生成的so库名称,此处生成的so文件名称是libnative-lib.so
             native-lib

             # Sets the library as a shared library.
             # STATIC:静态库,是目标文件的归档文件,在链接其它目标的时候使用
             # SHARED:动态库,会被动态链接,在运行时被加载
             # MODULE:模块库,是不会被链接到其它目标中的插件,但是可能会在运行时使用dlopen-系列的函数动态链接
             SHARED

             # Provides a relative path to your source file(s).
             # 资源文件,可以多个,
             # 资源路径是相对路径,相对于本CMakeLists.txt所在目录
             src/maind/jni/XJni.c)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

# 从系统查找依赖库
find_library( # Sets the name of the path variable.
              # android系统每个类型的库会存放一个特定的位置,而log库存放在log-lib中
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              # android系统在c环境下打log到logcat的库
              log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

# 配置库的链接(依赖关系)
target_link_libraries( # Specifies the target library.

                       # 目标库
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       # 依赖于
                       ${log-lib} )

6、简单写个JNI验证目标库是否生成可用

6.1在cpp目录下简单写个jni

在这里插入图片描述

6.2 点击make project(Ctrl+F9)后查看目标库是否生成

在这里插入图片描述

6.3 更多技术文章可关注本人公众号

在这里插入图片描述

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
好的,针对你的问题,我可以给你提供一个示例Android CMake构建脚本,用于生成动态库并应用第三方动态库和静态库。请注意,以下示例假设你已经具备一定的Android CMake构建经验,了解如何编写CMakeLists.txt文件,并且已经安装并配置好了必要的工具链。 首先,我们需要在CMakeLists.txt文件中添加以下内容,以指定要构建的动态库和相关的第三方库: ``` # 指定要构建的动态库名称 set(TARGET_LIB my_dynamic_lib) # 添加动态库源文件 add_library(${TARGET_LIB} SHARED src/main/cpp/my_dynamic_lib.cpp ) # 添加第三方动态库 add_library(third_party_lib SHARED IMPORTED) set_target_properties(third_party_lib PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libthird_party_lib.so) # 添加第三方静态库 add_library(third_party_static_lib STATIC IMPORTED) set_target_properties(third_party_static_lib PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libthird_party_static_lib.a) # 链接动态库及第三方库 target_link_libraries(${TARGET_LIB} third_party_lib third_party_static_lib) ``` 上述代码中,我们首先定义了要构建的动态库名称为`my_dynamic_lib`。然后,我们添加了动态库的源文件`src/main/cpp/my_dynamic_lib.cpp`。接着,我们添加了第三方动态库`libthird_party_lib.so`和第三方静态库`libthird_party_static_lib.a`。其中,我们通过`set_target_properties`命令设置了这两个库的路径,这里假设这两个库已经被放置在了`src/main/jniLibs/${ANDROID_ABI}/`目录下。 最后,我们通过`target_link_libraries`命令将动态库和第三方库链接起来。 希望这个示例能够帮助到你。如果你还有其他问题或疑问,请随时提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慢慢Coding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值