前言:最近安卓上面集成ffmpeg库,需要使用CMakeLists,之前VSCode中写过,时间有点长,忘记了,现记录下。
一、简介
cmake 是一个跨平台、开源的构建系统。它是一个集软件构建、测试、打包于一身的软件。它使用与平台和编译器独立的配置文件来对软件编译过程进行控制。
二、语法介绍
2.1 基本变量
CMAKE_SOURCE_DIR:CMakeLists.txt所在目录
比如:src/main/cpp/CMakeLists.txt
PROJECT_SOURCE_DIR:工程源文件目录,
比如..app/src/main/cpp
CMAKE_CXX_FLAGS: 用户配置的编译器参数
ANDROID_ABI:对应的ABI架构,
比如arm64-v8a文件夹下该值为arm64-v8a
PROJECT_SOURCE_DIR:工程根目录
CMAKE_CURRENT_SOURCE_DIR:当前处理的CMakeLists.txt文件所在路径
2.2 set
设置正常变量、缓存变量或环境变量的值
set(arg value)
自定义变量,arg是变量名,value是变量值,
引用变量方式${arg}
2.3 message
message(STATUS "打印的数据")
打印信息,存在于build_output.txt日志文件中,
一般测试变量、路径是否正确,类似于Java代码中的print方法
2.4 add_library、set_target_properties
用法1
原型:add_library(< name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[source1] [source2 …])
参数:
name:被构建库目标名称
[STATIC | SHARED ..:被构建库的类型,STATIC为静态库,生成的库 以libname.a形式存在,SHARED 为动态库,生成的库以libname.so形式存在;
EXCLUDE_FROM_ALL:对应的一些属性会在目标被创建时被设置;
[source1] [source2 ...]:指定源文件,多个文件由一个空格隔开;
作用:添加一个库
实例: add_library(LameMp3 SHARED src/main/cpp/LameMp3.c ${SRC_LIST})
用法2原型:add_library(< name> <SHARED|STATIC|MODULE|OBJECT|UNKNOWN> IMPORTED
[GLOBAL])
参数:
name:导入已知库的名称;
SHARED|STATIC|IMPORTED..:通常为SHARED IMPORTED;
作用:导入一个已经存在的库。注:导入库一般配合set_target_properties使用
实例: add_library(libswscale-4 SHARED IMPORTED )
find_library
原型:find_library (<VAR> name1 [path1 path2 …])
参数:
name1 :
作用:在path1查找相关库,并将其路径保存到指定变量name中
实例:find_library( log-lib log )
原型:set_target_properties(target1 target2 …
PROPERTIES prop1 value1
prop2 value2 …)
参数:
target1 target2 ...:目标名称;
prop1 prop2 ...:代表属性,取值为INCLUDE_DIRECTORIES、IMPORTED_LOCATION、LINK_DIRECTORIES等;
value1 value2 ...:被设置的属性值;
作用:设置目标属性值
实例:set_target_properties(libavcodec-57 PROPERTIES IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libavcodec-57.so")
add_library
1、添加源代码生成.a或.so库(注意此处会生成新的库文件)
add_library(HELLO [STATIC/SHARED] hello.cpp) ,
若 [STATIC/SHARED]不填写,据测试默认为STATIC
2、添加已有的或者第三方提供的.so或.a库(注意此处是已有的库文件)
add_library(faac [STATIC/SHARED] IMPORTED) ,IMPORTED告知CMake:
faac是第三方导入的库,按路径去找,
这个功能会和set_target_properties()一起使用
set_target_properties()
设置目标属性如:
1.指定导入库路径
set_target_properties(
HELLO
PROPERTIES IMPORTED_LOCATION //CMake中的关键字
import-lib/src/${ANDROID_ABI}/libHELLO.so//指定你要导入库的路径.
)
2.指定生成的库名称为hell0z注意生成的为libhell0z.so
set_target_properties(
HELLO PROPERTIES OUTPUT_NAME "hell0"
)
2.5 include_directories
原型:include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 …])
参数:
AFTER|BEFORE:指定源文件目录后,通常会被附加到编译的当前目录列表中,但也可以通过AFTER或BEFORE来改变这种行为方式;
SYSTEM:如果给出SYSTEM选项,编译器将被告知该目录是系统包含目录。
dir1:源文件目录路径,可多个,用一个空格隔开;
作用:导入给定源文件目录
实例:include_directories(src/main/cpp/lame)
这个命令不建议使用了,但是在我们的项目中顶级目录并没有定义任何 target,因此也没有想到更好的办法。
include_directories(includeDir1 includeDir2...)
指定原生或第三方库的头文件,为了CMake在编译阶段定位我们的头文件
2.6 target_link_libraries
原型:target_link_libraries(< target> … < item>… …)
参数:
target:目标库
item:被连接的库
作用:将若干库链接到目标库文件,需要注意的是链接的顺序应该符合gcc链接的顺序规则,即被链接的库放在依赖它的库的后面,比如lib1依赖于lib2,lib2依赖于lib3,那么target_link_libraries(name lib1 lib2 lib3)。
实例:target_link_libraries(LameMp3 ${log-lib} )
如果 target 是一个 library,该命令可以用来指定依赖本仓库的 target 还需要链接另外的仓库,用于解决循环依赖。
target_link_libraries(mylib INTERFACE anotherlib)
如果 target 是可执行文件,则该命令用于指定其需要链接的库。
list(APPEND EXTRA_LIBS gcov mylib)
target_link_libraries(mymain ${EXTRA_LIBS})
target_link_libraries(obj lib1 lib2 lib3...)
将预构建或第三方库 lib1 lib2 lib3链接到obj中,对应预处理-编译=汇编-链接过程中的链接阶段,
那么obj中就可以正常调用库里的函数,obj即可以是可执行文件也可以是库
2.7 target_link_directories
指定链接路径,该命令在3.12以下版本没有,笔者在项目中使用如下命令设置库的路径,其实更好的方法是用find_library.
# bad way
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_CURRENT_SOURCE_DIR}/../dependentLibs"
# good way
find_library(mylib ../dependentLibs)
2.8 file
file的用法很多,这里仅说明如何使用它来查找C文件
file(GLOB_RECURSE SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.c")
2.9 add_subdirectory
添加一个子目录到构建,该目录下必须有CMakeLists.txt文件
三、实例
#这个没什么可说的,就是指定cmake构建的最小版本号,
#因为随着版本更新有些语法、命令可能变了,所以这里需要设置下版本
cmake_minimum_required(VERSION 3.4.1)
#设置项目的名称,这个是可选的,
#如果设置了,会自动给你定义两个变量:demo_SOURCE_DIR,demo_BINARY_DIR。其中demo是你设置的#peoject名
#不过不指定的话默认有PROJECT_SOURCE__DIR ,PROJECT_BINARY_DIR,
#分别代表项目的源文件目录,项目编译后生成的二进制目录。
project("demo")
set(CMAKE_VERBOSE_MAKEFILE on)
# 设置so输出路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})
# 赋值变量libs
#第一个参数:libs是变量名,第二个是变量值
set(libs "${CMAKE_SOURCE_DIR}/src/main/jniLibs")
# 导入ffmpeg相关头文件
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include)
#-----------------------------导入ffmpeg库--------------------------------------
add_library(libavcodec-57 SHARED IMPORTED )
set_target_properties(libavcodec-57 PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libavcodec-57.so")
add_library(libavdevice-57 SHARED IMPORTED )
set_target_properties(libavdevice-57 PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libavdevice-57.so")
add_library(libavfilter-6 SHARED IMPORTED )
set_target_properties(libavfilter-6 PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libavfilter-6.so")
add_library(libavformat-57 SHARED IMPORTED )
set_target_properties(libavformat-57 PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libavformat-57.so")
add_library(libavutil-55 SHARED IMPORTED )
set_target_properties(libavutil-55 PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libavutil-55.so")
add_library(libpostproc-54 SHARED IMPORTED )
set_target_properties(libpostproc-54 PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libpostproc-54.so")
add_library(libswresample-2 SHARED IMPORTED )
set_target_properties(libswresample-2 PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libswresample-2.so")
add_library(libswscale-4 SHARED IMPORTED )
set_target_properties(libswscale-4 PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libswscale-4.so")
#------------------------------配置、链接动态库--------------------------------
#设置变量CMAKE_CXX_FLAGG修改编译选项[只针对c和c++编译器]
#这里使cmkae编译带有c++11特性,其中-std用于指定c/c++标准;
# -fexceptions用于开启编译器异常捕获机制;-frtti用于支持RTTI,配合异常处理
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -fexceptions -frtti")
#指定自定义构建库信息
add_library( # 库名称
decstream
# 库类型为动态库
SHARED
# 将被编译的源文件
src/main/cpp/nativesurface.cpp
src/main/cpp/vdecode.cpp
src/main/cpp/util.cpp
src/main/cpp/openstream.cpp)
#查找NDK中原生库log-lib
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)
#将ffmpeg库、原生库android、log链接到自定义库decstream
target_link_libraries(decstream android log
libavcodec-57
libavdevice-57
libavfilter-6
libavformat-57
libavutil-55
libpostproc-54
libswresample-2
libswscale-4
${log-lib}
)
四、总结
如果在使用时有什么不对的,很大的可能是语法和路径问题,慢慢排查就可以。
五、引用文献
3、Android NDK开发之旅(5):Android Studio中使用CMake进行NDK/JNI开发(高级)_无名之辈FTER的博客-CSDN博客