AndroidStudio项目CMakeLists解析
# 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)
# 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.
add_library( # Sets 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 )
# 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.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
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} )
上面的完成的有注释的内容,但其中最核心的也就几句,下面分别做介绍:
cmake_minimum_required(VERSION 3.4.1)
用来设置在编译本地库时我们需要的最小的cmake版本,AndroidStudio自动生成,我们几乎不需要自己管。
add_library( # Sets 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 )
add_library
用来设置编译生成的本地库的名字为native-lib
,SHARED
表示编译生成的是动态链接库
(这个概念前面已经提到过了),src/main/cpp/native-lib.cpp
表示参与编译的文件的路径,这里面可以写多个文件的路径。
find_library
是用来添加一些我们在编译我们的本地库的时候需要依赖的一些库,由于cmake已经知道系统库的路径,所以我们这里只是指定使用log
库,然后给log
库起别名为log-lib
便于我们后面引用,此处的log
库是我们后面调试时需要用来打log日志的库,是NDK为我们提供的。
target_link_libraries
是为了关联我们自己的库和一些第三方库或者系统库,这里把我们把自己的库native-lib
库和log
库关联起来。
NDK自定义配置
1 . 添加多个参与编译的C/C++文件
首先,我们发现我们上面的例子都是涉及到一个C++文件,那么我们实际的项目不可能只有一个C++文件,所以我们首先要改变CMakeLists.txt
文件,如下 :
add_library( HelloNDK
SHARED
src/main/cpp/HelloNDK.c
src/main/cpp/HelloJNI.c)
简单吧,简单明了,但是这里要注意的是,你在写路径的时候一定要注意当前的CMakeLists.txt
在项目中的位置,上面的路径是相对于CMakeLists.txt
写的。
2 . 我们想编译出多个so库
大家会发现,我们上面这样写,由于只有一个CMakeLists.txt
文件,所以我们会把所有的C/C++文件编译成一个so库,这是很不合适的,这里我们就试着学学怎么编译出多个so库。
先放上我的项目文件夹结构图:
然后看看我们每个CMakeLists.txt
文件是怎么写的:
one文件夹内的CMakeLists.txt
文件的内容:
ADD_LIBRARY(one-lib SHARED one-lib.c)
target_link_libraries(one-lib log)
two文件夹内的CMakeLists.txt
文件的内容:
ADD_LIBRARY(two-lib SHARED two-lib.c)
target_link_libraries(two-lib log)
app目录下的CMakeLists.txt
文件的内容
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
add_library( HelloNDK
SHARED
src/main/cpp/HelloNDK.c
src/main/cpp/HelloJNI.c)
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(HelloNDK log)
ADD_SUBDIRECTORY(src/main/cpp/one)
ADD_SUBDIRECTORY(src/main/cpp/two)
通过以上的配置我们可以看出CMakeLists.txt
文件的配置是支持继承的,所以我们在子配置文件中只是写了不同的特殊配置项的配置,最后在最上层的文件中配置子配置文件的路径即可,现在编译项目,我们会在 <项目目录>\app\build\intermediates\cmake\debug\obj\armeabi 下面就可以看到生成的动态链接库。而且是三个动态链接库
3 . 更改动态链接库生成的目录
我们是不是发现上面的so库的路径太深了,不好找,没事,可以配置,我们只需要在顶层的CMakeLists.txt
文件中加入下面这句就可以了
#设置生成的so动态库最后输出的路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})
然后我们就可以在app/src/main下看到jniLibs
目录,在其中看到我们的动态链接库的文件夹和文件(这里直接配置到了系统默认的路径,如果配置到其他路径需要在gradle文件中使用jinLibs.srcDirs = ['newDir']
进行指定)。
NDK错误调试
在开发的过程中,难免会遇到bug,那怎么办,打log啊,下面我们就谈谈打log和看log的姿势。
1 . 在C/C++文件中打log
(1) 在C/C++文件中添加头文件
#include <android/log.h>
- 1
上面是打印日志的头文件,必须添加
(2) 添加打印日志的宏定义和TAG
//log定义
#define LOG "JNILOG" // 这个是自定义的LOG的TAG
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG,__VA_ARGS__) // 定义LOGF类型
上面的日志级别和Android中的log是对应的。
(3) 经过上面两步,我们就可以打印日志啦
int len = 5;
LOGE("我是log %d", len);
现在我们就可以在logcat中看到我们打印的日志啦。
2 . 查看报错信息
首先我们先手动写一个错误,我们在上面的C文件中找一个函数,里面写入如下代码:
int * p = NULL;
*p = 100;
上面是一个空指针异常,我们运行程序,发现崩溃了,然后查看控制台,只有下面一行信息:
libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 17481
完全看不懂上面的信息好吧,这个也太不明显了,下面我们就学习一下如何将上面的信息变得清楚明了
我们需要用到是ndk-stack
工具,它在我们的ndk根目录下,它可以帮助我们把上面的信息转化为更为易懂更详细的报错信息,下面看看怎么做:
(1) 打开AndroidStudio中的命令行,输入adb logcat > log.txt
上面这句我们是使用adb命令捕获log日志并写入log.txt文件,然后我们就可以在项目根目录下看到log.txt文件
(2) 将log.txt打开看到报错信息,如下:
F/libc (17481): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 17481 (dekong.ndkdemo1)
I/DEBUG ( 67): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG ( 67): Build fingerprint: 'generic/vbox86p/vbox86p:5.0/LRX21M/genymotion08251046:userdebug/test-keys'
I/DEBUG ( 67): Revision: '0'
I/DEBUG ( 67): ABI: 'x86'
I/DEBUG ( 67): pid: 17481, tid: 17481, name: dekong.ndkdemo1 >>> com.codekong.ndkdemo1 <<<
I/DEBUG ( 67): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
I/DEBUG ( 67): eax 00000000 ebx f3494fcc ecx ffa881a0 edx 00000000
I/DEBUG ( 67): esi f434e2b0 edi 00000000
I/DEBUG ( 67): xcs 00000023 xds 0000002b xes 0000002b xfs 00000007 xss 0000002b
I/DEBUG ( 67): eip f3492a06 ebp ffa88318 esp ffa88280 flags 00210246
I/DEBUG ( 67):
I/DEBUG ( 67): backtrace:
I/DEBUG ( 67): #00 pc 00000a06 /data/app/com.codekong.ndkdemo1-2/lib/x86/libHelloNDK.so (Java_com_codekong_ndkdemo1_MainActivity_updateFile+150)
I/DEBUG ( 67): #01 pc 0026e27b /data/dalvik-cache/x86/data@app@com.codekong.ndkdemo1-2@base.apk@classes.dex
I/DEBUG ( 67): #02 pc 9770ee7d <unknown>
I/DEBUG ( 67): #03 pc a4016838 <unknown>
I/DEBUG ( 67):
I/DEBUG ( 67): Tombstone written to: /data/tombstones/tombstone_05
现在的报错信息还是看不懂,所以我们需要使用ndk-stack
转化一下:
(3) 继续在AndroidStudio中的命令行中输入如下命令(在这之前,我们必须要将ndk-stack的路径添加到环境变量,以便于我们在命令行中直接使用它)
ndk-stack -sym app/build/intermediates/cmake/debug/obj/x86 -dump ./log.txt
上面的-sym
后面的参数为你的对应平台(我是Genymotion模拟器,x86平台)的路径,如果你按照上面的步骤改了路径,那就需要写改过的路径,-dump
后面的参数就是我们上一步得出的log.txt文件,执行结果如下:
********** Crash dump: **********
Build fingerprint: 'generic/vbox86p/vbox86p:5.0/LRX21M/genymotion08251046:userdebug/test-keys'
pid: 17481, tid: 17481, name: dekong.ndkdemo1 >>> com.codekong.ndkdemo1 <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
Stack frame I/DEBUG ( 67): #00 pc 00000a06 /data/app/com.codekong.ndkdemo1-2/lib/x86/libHelloNDK.so (Java_com_codekon
g_ndkdemo1_MainActivity_updateFile+150): Routine Java_com_codekong_ndkdemo1_MainActivity_updateFile at F:\AndroidFirstCode\NDK
Demo1\app\src\main\cpp/HelloJNI.c:32
Stack frame I/DEBUG ( 67): #01 pc 0026e27b /data/dalvik-cache/x86/data@app@com.codekong.ndkdemo1-2@base.apk@classes.d
ex
Stack frame I/DEBUG ( 67): #02 pc 9770ee7d <unknown>: Unable to open symbol file app/build/intermediates/cmake/debug/
obj/x86/<unknown>. Error (22): Invalid argument
Stack frame I/DEBUG ( 67): #03 pc a4016838 <unknown>: Unable to open symbol file app/build/intermediates/cmake/debug/
obj/x86/<unknown>. Error (22): Invalid argument
Crash dump is completed
尤其是上面的一句:
g_ndkdemo1_MainActivity_updateFile+150): Routine Java_com_codekong_ndkdemo1_MainActivity_updateFile at F:\AndroidFirstCode\NDK
Demo1\app\src\main\cpp/HelloJNI.c:32
准确指出了发生错误的行数
AndroidStudio项目CMakeLists解析的更多相关文章
- Windows下AndroidStudio 中使用Git(AndroidStudio项目于GitHub关联)
前提条件 : 1. 安装 Git 客户端 下载链接 2. 有 GitHub 账号 (假设你已经有了一些git基础, 如果还一点都不会, 请去找其他加成学习) AndroidStudio项目发布到Git ...
- .NET大型B2C开源项目nopcommerce解析——项目结构
.NET大型B2C开源项目nopcommerce解析——项目结构 编写本文档是为了向程序员说明nopcommerce的解决方案结构,亦是程序员开发nopcommerce的居家必备良书.首先nopcom ...
- Androidstudio项目分享到Git@OSC托管
Androidstudio项目分享到Git@OSC托管. 一.在OSC创建仓库 例如,创建一个AndroidStudy仓库,创建步骤如下: 输入仓库名称 点击创建按钮,就可以完成仓库的创建,如下图所示 ...
- ionic项目结构解析
ionic项目结构解析 原始结构 创建一个IonicDemo项目 'ionic start IonicDemo sidemenu' 这种结构多模块开发比较麻烦,因为view跟controller分开路 ...
- AngularJS进阶(三十九)基于项目实战解析ng启动加载过程
基于项目实战解析ng启动加载过程 前言 在AngularJS项目开发过程中,自己将遇到的问题进行了整理.回过头来总结一下angular的启动过程. 下面以实际项目为例进行简要讲解. 1.载入ng库 2 ...
- androidstudio项目如何使用git版本回退
使用android studio 编写代码错误,有时可能会需要将项目版本回退到以前的某个版本上,这对于很多刚使用git的网友来说操作可能不是很懂,下面为大家整理了android studio 回退已经 ...
- AndroidStudio项目制作倒计时模块
前言 大家好,给大家带来AndroidStudio项目制作倒计时模块的概述,希望你们喜欢 项目难度 AndroidStudio项目制作倒计时模块的难度,不是很大,就是主要用了Timer和TimerTa ...
- 带你玩转Eclipse项目转成AndroidStudio项目
随着Android对Eclipse开发工具的淘汰,越来越多的公司使用AndroidStudio进行相应的Android开发工作.如此,原来用Eclipse开发的项目,怎么导入到AndroidStudi ...
- AndroidStudio项目打包成jar
AndroidStudio项目打包成jar 前言:在eclipse中我们知道如何将一个项目导出为jar包,现在普遍AndroidStuido开发,这里一步一步详加介绍AS项目打包成jar,jar和ar ...
随机推荐
- centos6 或者 centos7 重置遗忘的root密码
centos7 1.重启服务器. 2.在出现如下界面时,按“e”键,进入内核边界页面,如下图: 3.进入后,在“linux16”这行参数最后添加“rd.break”参数,输入完后,同时安装“ctrl” ...
- css3基础篇一
CSS3 选择器 选择器 例子 例子描述 CSS .class .intro 选择 class="intro" 的所有元素. 1 #id #firstname 选择 id=&quo ...
- structure vs class in swift language
Both class and structure can do: Define properties to store values Define methods to provide functio ...
- spring boot注解
一.注解(annotations)列表 @SpringBootApplication:包含了@ComponentScan.@Configuration和@EnableAutoConfiguration ...
- tomcat配置SSH加密
[root@tomcat2 ~]# keytool -genkeypair -alias tomcat -keyalg RSA -keystore /usr/local/tomcat7/keystor ...
- java8方式日期比较
static ZoneId ZONEID_BJ = ZoneId.of("GMT+08:00"); private boolean sameDate(Date d1, Date d ...
- [jzoj 5781]【NOIP提高A组模拟2018.8.8】秘密通道 (最短路)
传送门 Description 有一副nm的地图,有nm块地,每块是下列四种中的一种: 墙:用#表示,墙有4个面,分别是前面,后面,左面,右面. 起点:用C表示,为主角的起点,是一片空地. 终点:用F ...
- [POJ2404]Jogging Trails
我太弱了. 我们可以知道一个结论就是对于一个图的话假如所有点的度数都是偶数,那么只需要走一波欧拉回路. 所以我们就把奇点补成偶点. 将两个奇点补充到偶点的最佳方法是选择任意两个奇点连最短路径为权的边 ...
- Linux之浅谈VIM常见用法及原理图
本次归纳以强大的VIM文本处理工具常见用法去展开论述. 文本编辑种类: 行编辑器:sed 全屏编辑器:nano,vi vim - Vi改进 其他编辑器: ...
- 【ownCloud】添加信任域
如果在安装ownCloud后,更换了访问方式,比如刚开始是http://127.0.0.1/owncloud,变成了http://1.1.1.1/owncloud,那么在访问时可能得到这样的页面: 您 ...