Cmake文件

使用AndroidStudio3.4创建一个C/C++Support的项目,默认在app/src/main目录下会生成cpp目录,里面包含CMakeList.txt和native-lib.cpp。下面代码为CMakeList.txt去掉英文注释格式化后的内容。

#指定cmake最小支持版本
cmake_minimum_required(VERSION 3.4.1)

#添加一个库,根据native-lib.cpp源文件编译一个native-lib的动态库
add_library(
        native-lib
        SHARED
        native-lib.cpp)

#查找系统库,这里查找的是日志库,赋值给log-lib
#ndk路径\platforms\android-21\arch-arm\usr\lib下查找系统库
find_library(
        log-lib
        log)

#设置依赖的库 (第一个参数必须为目标模块, 顺序不能换)
target_link_libraries(
        native-lib
        ${log-lib})

CMakeList中的常用命令:

cmake_minimum_required
cmake_minimum_required(VERSION 3.4.1)

指定最低支持的版本,可选,可不写,如果我们使用了一些高版本特有的命令,那就需要指明最低支持版本

aux_ source_ directory
#.表示当前目录
aux_source_directory(.DIR_SRCS)

查找当前目录所有源文件并将源文件名称列表保存到DIR_SRCS变量
不能查找子目录

add_library

添加一个库或者导入预编译库

添加一个库

添加一个库文件,名为<name>。指定STATIC,SHARED,MODULE参数来指定库的类型。
STATIC: 静态库;
SHARED: 动态库;
MODULE:使用dyld的系统有效,若不支持dyld,等同于SHARED
EXCLUDE_FROM_ALL: 表示该库不会被默认构建。
source1 source2... sourceN:用来指定库的源文件

格式:

add_ library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_ FROM_ ALL] source1 source2 ...sourceN)

导入预编译库

添加一个已存在的预编译库,名为<name>。
一般配合set_target_properties使用
格式:
add library (<name>
<SHARED | STATIC | MODULE | UNKNOWN> IMPORTED)

示例:

add library(test SHARED IMPORTED)
set_target_properties (
test #指明目标库名
PROPERTIES IMPORTED_ LOCATION #指明要设置的参数
库路径/${ANDROID_ ABI}/libtest.so #导入库的路径
)
set命令

set用于设置Cmake的变量,常用举例:

#设置可执行文件的输出路径( EXCUTABLE_OUTPUT_PATH是全局变量)
set ( EXECUTABLE_OUTPUT_PATH [output_path])
#设置库文件的输出路径 (LIBRARY OUTPUT PATH是全局变量 )
set (LIBRARY_OUTPUT_PATH [output_path])
#设置C++编译参数(CMAKE_CXX_FLAGS是全局变量)
set(CMAKE CXX_FLAGS "-Wall std=c++11" )
#设置源文件集合( SOURCE_FILES是本地变量即自定义变量)
set ( SOURCE_FILES main. cpp test.cpp ... )
include_directories

设置头文件目录
相当于g++选项中的-I参数

#可以用相对或绝对路径, 也可以用自定义的变量值
include_directories(./include ${MY_INCLUDE})
add_executable

用于添加可执行文件

#第一个参数是文件名,第二个参数是源文件
add_executable(<name> ${SRC_LIST})
target_link_libraries

将若干库链接到目标库文件
链接的顺序应当符合gcc链接顺序规则,被链接的库放在依赖它的库的后面,即如果下面的命令中,lib1依赖于lib2, lib2又依赖于lib3,则在.上面命令中必须严格按照(lib1
lib2 lib3的顺序排列,否则会报错

target_link_libraries(<name> lib1 lib2 lib3)
#如果出现互相依赖的静态库,CMake会允许依赖图中包含循环依赖,如:
add library(A STATIC a.c)
add_library(B STATIC b.c)
target_link_libraries(A B)
target_link_libraries(B A)
add_executable(main main.c )
target_tink_libraries (main A)
add_definitions

通常用于添加编译参数:

#为当前路径以及子目录的源文件加入由-D引入的define flag
add definitions( -DF00  -DDEBUG ...)
add_subdirectory

如果当前目录下还有子目录时可以使用add_subdirectory, 子目录中也需要包含有
CMakeLists.txt

# sub_dir指定包含CMakeLists.txt和源码文件的子目录位置
# binary_dir是输出路径,一般可以不指定 
add_subdirecroty(sub_dir [binary_dir])
file

文件操作命令,常见用法
使用者中方式添加文件,需要注意,在没有改动CMakeLists.txt文件的情况下,重新编译会报错,需要改动CMakeLists.txt文件,使其重新编译,比如添加一个空格,然后在编译就会重新生成makefile文件

#将message写入filename文件中,会覆盖文件原有内容
file(WRITE filename "message" )
#将message写入filename文件中,会追加在文件末尾
file (APPEND filename "message" )
#从filename文件中读取内容并存储到var变量中,如果指定了numBytes和offset,
#则从offset处开始最多读numBytes个字节,另外如果指定了HEX参数,则内容会以十六进制形式存储在var变量中
file (READ filename var [LIMIT numBytes] [OFFSET offset] [HEX] )
#重命名文件
file (RENAME <oldname> <newname> )
#删除文件,等于rm命令
file(REMOVE [file ...])
#递归的执行删除文件命令,等于rm -r
file(REMOVE RECURSE [filel ...])
#根据指定的url下载文件
# timeout超时时间; 下载的状态会保存到status中; 下载日志会被保存到log; sum指定所下载文件预期的MD5值, 如果指定会自动进行比对,
#如果不一致,则返回一个错误; SHOW_PROGRESS, 进度信息会以状态信息的形式被打印出来
file(DOWNLOAD url file [TIMEOUT timeout] [STATUS status] [LOG log] [EXPECTED_MD5 sum] [SHOW_PROGRESS])
#创建目录
file(MAKE_DIRECTORY [dir1 dir2 ...])
#会把path转换为以unix的/开头的cmake风格路径,保存在result中
file(TO_CMAKE_PATH path result)
#它会把cmake风格的路径转换为本地路径风格: windows 下用"\",而unix下用”/"
file(TO_NATIVE_PATH path result )
#将会为所有匹配查询表达式的文件生成个文件list, 并将该list存储进变量variable里,如果一个 表达式指定了RELATIVE,返回的结果
#将会是相对于给定路径的相对路径,查询表达式例子: *.cxx, *.vt?
# NOTE: 按照官方文档的说法,不建议使用file的GL0B指令来收集1程的源文件
file(GLOB variable [RELATIVE path] [globbing expressions]... )
set_directory_properties

设置某个路径的一种属性
prop1, prop2代表属性,取值为:INCLUDE_DIRECTORIES
LINK_DIRECTORIES
INCLUDE_REGUL AR_EXPRESSION
ADDITIONAL_MAKE_CLEAN_FILES

set_directory_properties (PROPERTIES prop1 value1 prop2 value2)
set_property

在给定的作用域内设置一个命名的属性
PROPERTY参数是必须的
第一个参数决定了属性可以影响的作用域:
GLOBAL:全局作用域
DIRECTORY:默认当前路径,也可以用[dir]指定路径(可使用相对路径/绝对路径指定)
TARGET:目标作用域,可以是0个或多个已有目标
SOURCE:源文件作用域,可以是0个或多个源文件(源文件属性只对同目录下的CMakeLists中的目标可见)
TEST:测试作用域,可以是0个或多个已有的测试
CACHE:必须指定0个或多个cache中已有的条目

set_property (<GL0BAL 
| DIRECTORY [dir] 
| TARGET [target ...] 
| SOURCE [src1...]
| TEST [test1...]  
| CACHE [entry1 ...] >
[APPEND]
PROPERTY <name> [value ...]
多个源文件处理

如果源文件很多,把所有文件一个个加入很麻烦,可以使用aux_source_directory命令或file命令,会查找指定目录下的所有源文件,然后将结果存进指定变量名。

cmake_minimum_required (VERSION 3.4.1)
#查找当前目录所有源文件并将名称保存到DIR_SRCS 变量
#不能查找子目录
aux_source_directory(. DIR_SRCS)
#也可以使用
# file(GLOB DIR_ SRCS *.c *.cpp )
add_Library(
native-lib
SHARED
${DIR_SRCS})
多目录多源文件处理
  1. 主目录中的CMakeLists.txt中添加add_subdirectory(child)命令,指明本项目包含一个子项目child。并在target_link_libraries指明本项目需要链接一个名为child的库。
  2. 子目录child中创建CMakeLists.txt,这里child编译为共享库。
cmake_minimum_required (VERSION 3.4.1)
aux_source_directory(. DIR_SRCS)
#添加 child 子目录下的cmakelist
add_subdirectory(child)

add_library(
native-lib
SHARED
${DIR_SRCS} )
target_link_libraries (native-lib child)
#-----------------------------------------
#child目录下的CMakeLists.txt:
cmake_ minimum_required (VERSION 3.4.1)
aux_ source_ directory(. DIR_LIB_SRCS)
add_library(
child
SHARED
${DIR_LIB_SRCS})

添加预编译库(Android6.0版本以前)

  1. 假设我们本地项目引用了libimported-lib.so。
  2. 添加add_library命令, 第一个参数是模块名,第二个参数SHARED表示动态库,STATIC表示静态库,第三个参数IMPORTED表示以导入的形式添加。
  3. 添加set_target_properties命令设置导入路径属性。
    4.将import-lib添加到target_link_libraries命令参数中,表示native-lib需要链接imported-lib模块
cmake_minimum_required(VERSION 3.4.1)
#使用IMPORTED 标志告知CMake 只希望将库导入到项目中
#如果是静态库则将shared改为static
add_library( imported-lib
  SHARED
  IMPORTED )
#参数分别为:库、属性、导入地址、库所在地址
set_target_properties(
  imported-lib 
  PROPERTIES
  IMPORTED_LOCATION
  <路径>/libimported-lib. so)
aux_source_directory(. DIR_SRCS)

add_library(
  native-lib
  SHARED
  ${DIR_SRCS} )

target_link_libraries (native-lib imported-lib)

添加预编译库(Android6.0版本以后)

在Android 6.0及以上版本,如果使用上述的方法添加预编译动态库的话,会有问题。我们可以使用另外种方式来配置。

# set命令定义一个变量
# CMAKE_C_FLAGS: c的参数,会传递给编译器
#如果是c++文件,需要用CMAKE_CXX FLAGS
# -L: 库的查找路径
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -L [SO所在目录]")

添加头文件目录

为了确保CMake可以在编译时定位头文件,使用include_directories, 相当于g++选项中的-l参数。这样就可以使用#include<xx.h>,否则需要使用 #include"path/xx.h"

cmake_minimum_required(VERSION 3. 4.1)
#设置头文件目录
include_directories(<文件目录>)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -L [SO所在目录]")
aux_source_directory(. DIR_SRCS)
add_library(
  native-lib
  SHARED
  ${DIR_ SRCS})
target_link_libraries (native-lib imported-lib)

Build.gradle配置

可以在gradle中使用arguments设置一些配置

android{
    defaultConfig{
        cmake{
            // 使用的编译器clang/gcc
            // cmake默认就是 gnustl_static
            arguments "-DANDROID_TOOLCHAIN=clang","-DANDROID_STL=gnustl_static"
            // 指定cflags和cppflags,效果和cmakelist使用一样
            cFlags ""
            cppFlags ""
            // 指定需要编译的cpu架构
            abiFilters "armeabi-v7a"
        }
    }
    externalNativeBuild{
        cmake{
            // 指定CMakeLists.txt文件相对当前build.gradle的路径
            path "xxx/CMakeLists.txt"
        }
    }
}

集成fomd为例

官网:https://www.fmod.com/
SDK下载页面:https://www.fmod.com/download(需要注册登录才能下载)

第一步: 集成头文件,so文件
将下载的fmodstudioapi20000android.tar.gz 解压,找到 api/core目录下的inc文件夹,其中fmod的头文件,lib是fmod预编译好的so和jar文件。将inc整个文件夹copy到项目的cpp文件夹下:

inc

然后在CMakeLists文件中,设置头文件目录如下:

#设置头文件路径
#这里通过Cmake预置变量CMAKE_SOURCE_DIR拿到CMakeLists当前路径
#这里就是src/main/cpp
include_directories(${CMAKE_SOURCE_DIR}/inc)

然后在项目的main文件夹下,新建文件夹jniLibs,将 api/core/lib下的所有文件夹都copy到jniLibs下:

jniLibs

修改module的build.gradle文件中的defaultConfig:

 defaultConfig {
        applicationId "com.code.cmakedemo"
        minSdkVersion 14
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
                abiFilters "x86" //本地库的cpu架构 (模拟器所以选了x86)
            }
        }
        ndk{
            abiFilters "x86" //三方so库的cpu架构 (模拟器所以选了x86)
        }
    }

然后修改CMakeLists文件,将libfomd.solibfomdL.so添加到依赖库里:

#设置第三方so库的路径
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}}")

#设置依赖的库 (第一个参数必须为目标模块, 顺序不能换)
target_link_libraries(
        native-lib
        fmod
        fmodL
        ${log-lib})

这样就配置完成了,然后可以在native-lib.cpp中导入和使用fmod

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352