美文网首页
Cmake介绍及使用问题记录

Cmake介绍及使用问题记录

作者: 神迹12 | 来源:发表于2022-07-02 13:50 被阅读0次

    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

    相关文章

      网友评论

          本文标题:Cmake介绍及使用问题记录

          本文链接:https://www.haomeiwen.com/subject/djxkbrtx.html