CMake 是一个跨平台的安装(编译)工具。
Make工具有很多种,比如 GNU Make ,QT 的 qmake ,微软的 MS nmake,BSD Make(pmake)等等。这些 Make 工具遵循着不同的规范和标准,所执行的 Makefile 格式也千差万别。要想跨平台,每一种标准都要写一次Makefile。
CMake是一套伪代码,执行编译的不是 CMake,可能是 gcc 也可能是 clang 等等。CMake允许开发者编写一种平台无关的 CMakeList.txt 文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件。
一、android下使用CMake简单示例
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
#设置项目的名称,并将其存储在变量project_name中
project(appfp-native)
#设置依赖的so库目录
set(jnilibs ${CMAKE_SOURCE_DIR}/../jniLibs)
set(libname learn-ffmpeg)
#头文件包含目录
include_directories(
include)
#指定链接目录
link_directories(
${jnilibs}/${ANDROID_ABI})
#查找所有源文件,保存到GLOB变量中
file(GLOB src-files
${CMAKE_SOURCE_DIR}/*.cpp
)
#或者替换为使用aux_source_directory
//aux_source_directory(${CMAKE_SOURCE_DIR} src-files)
#生成库文件
add_library( # Sets the name of the library.
${libname}
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
${src-files}
)
#将编译依赖的三方库保存到thrid-party-libs变量中
set(third-party-libs
avformat
avcodec
avfilter
swresample
swscale
avutil
crypto
ssl
)
#将编译依赖的系统库保存到native-lib是变量中
set(native-libs
android
log
m
z
)
find_library(log-lib log)
target_link_libraries( # Specifies the target library.
${libname}
# Links the target library to the log library
# included in the NDK.
${log-lib}
${third-party-libs}
${native-libs}
)
二、如何查看哪些源文件参与了编译
image.png image.png image.png image.pngDPlayer.cpp未通过CmakeLists.txt文件引入,所以调用其startPlay()函数报undefined reference 错误。而在.cxx目录下,可以看到也只有app_native.cpp.o一个.o文件,即只有app_native.cpp一个源文件参与了编译。修改后如下:
image.png
三、target_llink_libraries 链接静态库顺序
target_llink_libraries 指令的作用为将目标文件与库文件进行链接。但是如果链接的是.a静态库,则有可能会遇到类似“error: undefined reference to···”错误。
例如:
target_link_libraries(${PROJECT_NAME} ${log-lib}
...
ssl crypto curl
)
ssl、crypto、curl均是.a静态库。正确顺序为curl、ssl、crypto。curl链接依赖ssl。
image.png
静态库链接库顺序和gcc是一致的,即被链接的库放到后面。在链接静态库时,如果多个静态库之间存在依赖关系,则有依赖关系的静态库之间存在顺序问题,这个在使用静态库时需要注意,否则会报符号找不到问题。
target_link_libraries(native_lib
libA.a
libB.a
libC.a
)
编译native_lib依赖libA 编译libA依赖libB 编译libB依赖libC。
C/C++程序的许多同学被静态库的依赖折腾,因为默认情况下要求被依赖的库放在依赖它的库后面,当一个程序或共享库依赖的静态库较多时,可能会陷入解决链接问题的坑中。
但也可以偷懒,不关心静态库的顺序问题,ld为此提供了start-group和end-group两个选项,让包含在这两者间的静态库顺序可以随意。
可以采用如下的写法去掉静态库链接顺序影响:
target_link_libraries(native_lib
-Wl,--start-group
libB.a
libA.a
libC.a
-Wl,--end-group
)
这样可以完全不用关心顺序。start-group和end-group是ld的选项,是链接选项,不是gcc/g++的编译选项。
四、add_definitions
add_definitions的功能和C/C++中的#define是一样的
比如我有如下两个文件,一个源文件main.cpp,一个CMakeLists.txt
源文件main.cpp
#include <iostream>
int main()
{
#ifdef TEST_IT_CMAKE
std::cout<<"in ifdef"<<std::endl;
#endif
std::cout<<"not in ifdef"<<std::endl;
}
cmake文件CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(optiontest)
add_executable(optiontest main.cpp)
option(TEST_IT_CMAKE "test" ON)
message(${TEST_IT_CMAKE})
if(TEST_IT_CMAKE)
message("itis" ${TEST_IT_CMAKE})
add_definitions(-DTEST_IT_CMAKE)
endif()
通过option设置一个变量,并通过add_definitions将其转换为#define TEST_IT_CMAKE
当变量为ON时
option(TEST_IT_CMAKE "test" ON)
该程序的输出是
in ifdef
not in ifdef
当变量为OFF时
option(TEST_IT_CMAKE "test" OFF)
该程序的输出为
not in ifdef
五、 aux_source_directory
aux_source_directory(< dir > < variable >)
搜集所有在指定路径下的源文件的文件名,将输出结果列表储存在指定的变量中。
查找指定目录下的源文件并保存到相应的变量中,需要注意的是使用aux_source_directory不会递归查找目录,会且只会查找指定目录下的源文件。
aux_source_directory不能递归包含源文件。
参考
https://blog.csdn.net/qq_35699473/article/details/115837708
https://blog.csdn.net/fb_941219/article/details/107376017
https://www.csdn.net/tags/MtTaMg3sNDMzMjE2LWJsb2cO0O0O.htmlhttps://www.csdn.net/tags/MtTaMg3sNDMzMjE2LWJsb2cO0O0O.html
https://www.cnblogs.com/aquester/p/10084070.html
https://www.jianshu.com/p/f196a6433c30
https://www.cnblogs.com/lidabo/p/13802537.html
网友评论