Cmake介绍及使用问题记录

2022-07-02  本文已影响0人  神迹12

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.png

DPlayer.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

上一篇下一篇

猜你喜欢

热点阅读