设为首页 加入收藏

TOP

CMake个人理解和使用(四)
2023-07-23 13:27:43 】 浏览:90
Tags:CMake 解和使
文件是x86的架构。那么就需要在jniLibs目录下新建x86的目录下,然后再把libsum.a放到该目录下。至此,静态库的构建工作就算结束了。

使用静态库

把静态库放到合适的位置后,我们需要配置app目录下的build.gradlecpp目录下的CMakeLists.txt文件,完成静态库的引入。

配置Gradle

首先说build.gradle,该文件主要涉及到修改ABI的问题,因为不指定的话,Gradle默认生成的ABI可能找不到对应的静态库文件来链接,从而导致链接失败。该文件主要的修改如下

android {
    defaultConfig {
        externalNativeBuild {
                cmake {
                    cppFlags ""
                    abiFilters "x86"
                }
            }
    }
}

也就是把abiFilters的值指定为刚才构建的静态库相同的值。

配置CMake

CMakeLists.txt文件就复杂一些了,它需要完成两个工作,找到静态库和静态库的头文件,链接静态库。

找到头文件

在文章的第二部分我们已经知道了让CMake找到头文件的include_directories命令,把参数设置为3rd目录就行了。值得注意的是,CMake是以当前的CMakeLists.txt文件为工作目录的,所以,要指定到3rd文件,我们需要一直回退目录到根项目,最终就有了include_directories(../../../../../3rd)这样的配置。尽量使用相对路径,可以在多人协同的情况下,不用修改配置。

找到静态库

下一步要让CMake找到我们的静态库。说到库,都是和add_library相关的,不同的只是参数。使用源码添加库的时候,我们需要指定库的名称和源码位置,而引用第三方库,则是需要指定库的名称和类型,外加一个IMPORTED的指示参数,告诉CMake这个库是导入的。所以就有了add_library(addSum STATIC IMPORTED)这样的配置。

但是,这里我们只告诉了CMake库的名字,库存储在哪里,还不知道,所以我们还需要另一个命令告诉CMake库的存储位置。涉及到配置参数的,通常就是set_target_properties命令了,可以多次调用这个命令设置多种配置。set_target_properties(addSum PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libsum.a),第一个参数和上一条的第一个参数是一一对应的,可以随便取。其实add_library相当于生成了一种目标产物,用第一个参数来指代这种产物,所以才让我们的set_target_properties找得到合适的目标设置属性。第二个参数则是配置属性的标准写法,第三个代表属性变量,第四个是属性值,配置库路径的变量就是IMPORTED_LOCATION,而值这里就有个坑了,Android下的CMake限定值必须是绝对路径,不能是相对路径。而这与使用CMake的初衷背道而驰,幸好,我们有几个预设值可以用,CMAKE_CURRENT_SOURCE_DIR就是其中之一,它代表着当前这个CMakeLIsts.txt文件的绝对路径,有了这个,再加上目录的回退功能,我们就能找到任何合适的目录了。至此,又出现了第二个问题,当有多个架构的静态库需要配置时,我们引入的目录是不一样的,而且会出现很多重复的配置。还好有ANDROID_ABI的帮助,它指代了当前编译的某个架构,随着编译的进行,这个值会被设置为合适的值,并且是和正在编译的架构是一一对应的。所以,尽管它们有点奇怪,但是这给我带来了灵活和简单。

链接静态库

现在头文件有了,库也有了,但是C++的编译是分成两步的,目前为止,我们的工作只做完了编译的事情,还没涉及到链接的事情,当然,相比前面的配置,这就简单多了,无疑就是在target_link_libraries命令里添加一个参数就可,如

target_link_libraries( 
                       native-lib
                       ${log-lib}
                       addSum
        )

只需哟注意名字和add_library时配置的名字一一对应就可。

在源码中使用

经过漫长的等待,现在我们终于能在native-lib.cpp文件中引入addsum的头文件,并且使用里面的函数完成工作了。我打算让函数返回一个包含加法运算结果的字符串。最终实现如下

#include <jni.h>
#include <string>
#include <lib.h>

extern "C" JNIEXPORT jstring JNICALL
Java_me_hongui_cmakesum_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = std::to_string(sum(1,1));
    return env->NewStringUTF(hello.c_str());
}

至此,点击工具栏上的run按钮,我们终于可以在Android的模拟器上看到我们的静态库工作的成果啦。

扩展

其实除了引用静态库的方式之外,我们还可以直接通过配置CMakeLists.txt文件来引用源码,这样可以随时随地对源码进行定制,但是也降低了编译速度,而且可能会增加CMakeLists.txt的复杂度。所以我还是推荐直接使用静态库的方式。

总结

CMake其实还有很多很多命令,我们这里涉及到的只是很少的一部分。但是,我觉得理解CMake有这些内容差不多就可以了,后续有需要再针对性学习就行了。学习一门技术,切忌不能贪多,贪细。先要抓住主干,理清脉络,后面的细节就是水到渠成的事。对于CMake,我觉得就是以C++代码编译为二进制的过程为主干就够了。源码从哪里来,头文件在那里,库文件在哪里,怎么组织编译,参与链接的库有哪些,生成什么产物,还有一些完成这些工作的通用操作,复制文件啊,目录信息啊等,这些操作的集合就构成了CMake的主体。另外,CMake其实只是一种构建工具,它本身不是编译器和链接器,有些问题可能不仅仅会涉及到cmake,还可能会涉及到编译器和连接器。当然,这些都是后面深入了解之后才可能碰到的问题了。

首页 上一页 1 2 3 4 下一页 尾页 4/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++基础知识总结 下一篇驱动开发:内核ShellCode线程注入

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目