美文网首页
CMake教程——基础使用

CMake教程——基础使用

作者: 生活简单些 | 来源:发表于2020-04-12 21:20 被阅读0次

      所有CMake项目跟目录下都会有个CMakeList.txt文件,它描述里项目编译入口,cmake项目编译建议创建一个额外目录放编译过程产物,比如在项目根目录创建“build”文件夹,然后输入命令:

    $: cmake ..
    -- The C compiler identification is AppleClang 11.0.0.11000033
    -- The CXX compiler identification is AppleClang 11.0.0.11000033
    -- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc
    -- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc -- works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Detecting C compile features
    -- Detecting C compile features - done
    -- Check for working CXX compiler: /Library/Developer/CommandLineTools/usr/bin/c++
    -- Check for working CXX compiler: /Library/Developer/CommandLineTools/usr/bin/c++ -- works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Detecting CXX compile features
    -- Detecting CXX compile features - done
    -- Looking for pthread.h
    -- Looking for pthread.h - found
    -- Performing Test CMAKE_HAVE_LIBC_PTHREAD
    -- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
    -- Found Threads: TRUE  
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /Users/xxx/App/build
    

      这一步是通过cmake将项目转为makefile,随后可以再敲入命令编译生成可执行文件或库文件:

    $: make
    Scanning dependencies of target smt-logger
    [ 25%] Building CXX object library/CMakeFiles/App.dir/App.cpp.o
    [ 50%] Linking CXX shared library ../lib/App.so
    [ 50%] Built target App
    Scanning dependencies of target tests
    [ 75%] Building CXX object tests/CMakeFiles/tests.dir/testcase.cpp.o
    [100%] Linking CXX executable ../bin/tests
    [100%] Built target tests
    

    1. 如何用cmake组织项目——最基础模版

    项目结构:

    ├── CMakeLists.txt
    └── main.cpp
    

    CMakeList.txt:

    # VERSION 没必要设置最高版本,不然得要求所有人跟你用一样的最高版本
    cmake_minimum_required(VERSION 3.0.0)
    
    # 设置项目名称
    project(App)
    
    # 很多IDE默认c++是11以下,需要支持更高版本需要自行设置
    set(CMAKE_CXX_STANDARD 14)
    
    # 将main.cpp编译到App里并生成可执行文件,可执行文件名为App(windows环境为App.exe)
    add_executable(App main.cpp)
    

    2. 如何用cmake组织项目——同时编译项目中多个文件

    2.1 手动一个一个加入

    项目结构:

    ├── CMakeLists.txt
    ├── main.cpp
    ├── main1.cpp
    ├── main2.cpp
    └── main3.cpp
    

    CMakeList.txt:

    cmake_minimum_required(VERSION 3.0.0)
    project(App)
    set(CMAKE_CXX_STANDARD 14)
    
    add_executable(App main.cpp \
                       main2.cpp \
                       main3.cpp)
    

    2.2:按目录加入

    cmake_minimum_required(VERSION 3.0.0)
    project(App)
    set(CMAKE_CXX_STANDARD 14)
    
    # 假设所有cpp文件都在当前目录,扫描当前目录
    # 下所有cpp文件并存储到变量DIR_SRCS里
    aux_source_directory(. DIR_SRCS)
    
    # 编译多个cpp文件为可执行文件,cpp文件名来自DIR_SRCS
    add_executable(App ${DIR_SRCS})
    

    当然一个项目有多个目录存放cpp文件情况,最简单办法是使用多个aux_source_directory()创建多个变量,每个变量对应它目录下都cpp文件集合:

    aux_source_directory(. DIR_SRCS1)
    aux_source_directory(. DIR_SRCS2)
    aux_source_directory(. DIR_SRCS3)
    
    add_executable(App ${DIR_SRCS1} ${DIR_SRCS2} ${DIR_SRCS3})
    

    不过这是一种取巧做法,这种做法会导致项目编译时候会编译所有代码,导致编译时间较长,更好的推荐做法是给每个目录都创建一个CMakeList.txt, 其实不用担心创建多个CMakeList.txt会带来很多额外工作量,当然额外工作量是有的,但是非常少,结构更清晰!

    3. 下面以live555(一个开源的rtps server项目)为例介绍如何用cmake组织项目

    live555本来并非cmake项目,我将此改为cmake构建的项目,live555本身就以文件划分了模块,因此我只要在每个目录里增加CMakeList.txt并在其中描述编译当前模块的cmake脚本即可,最后在项目的跟目录下也创建一个CMakeList.txt并将所有的模块都汇集起来就能编译整个项目了。

    ├── CMakeLists.txt
    ├── BasicUsageEnvironment
    │   └── CMakeLists.txt
    │   └── BasicHashTable.cpp
    │   └── xxx.cpp
    │   └── include
    │       └── BasicHashTable.hh
    │       └── xxx.hh
    ├── groupsock
    │   └── CMakeLists.txt
    │   └── GroupEId.cpp
    │   └── xxx.cpp
    │   └── include
    │       └── GroupEId.hh
    │       └── xxx.hh
    ├── liveMedia
    │   └── CMakeLists.txt
    │   └── AC3AudioRTPSink.cpp
    │   └── xxx.cpp
    │   └── include
    │       └── GroupEId.hh
    │       └── xxx.hh
    ├── mediaServer
    │   └── CMakeLists.txt
    │   └── DynamicRTSPServer.cpp
    │   └── xxx.cpp
    └── UsageEnvironment
        └── CMakeLists.txt
        └── HashTable.cpp
        └── xxx.cpp
        └── include
            └── Boolean.hh
            └── xxx.hh
    

    3.1 跟目录下的CMakeList.txt

    cmake_minimum_required(VERSION 3.15)
    project(live555)
    set(CMAKE_CXX_STANDARD 14)
    
    if (UNIX)
      add_definitions(-Wall -g -O2 -DSOCKLEN_T=socklen_t -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64)
    endif(UNIX)
    
    # add subdirectory means add all sub modules
    ADD_SUBDIRECTORY(UsageEnvironment)
    ADD_SUBDIRECTORY(BasicUsageEnvironment)
    ADD_SUBDIRECTORY(groupsock)
    ADD_SUBDIRECTORY(liveMedia)
    ADD_SUBDIRECTORY(mediaServer)
    

    3.2 BasicUsageEnvironment 目录下的CMakeList.txt

    # 这里指定当前模块名,这里推荐用文件名作为模块名
    project(BasicUsageEnvironment)
    
    # 因为当前模块cpp里使用里其他模块的头文件,因此需要把它们include进来
    include_directories(../UsageEnvironment/include)
    include_directories(../groupsock/include)
    
    # 当前模块的头文件肯定要include进来
    include_directories(include)
    
    # 当前模块下的cpp跟CMakeList.txt在同级目录
    aux_source_directory(. SRC_LIST)
    
    # 当前只是模块,最终需要把所有的模块合并构建,因此当前需要指定编译对象为STATIC
    # ${PROJECT_NAME}的值即为当前模块名,需要注意的是不能用${CMAKE_PROJECT_NAME},因为那是跟目录下CMakeList.txt指定的名字,那是整个项目的名字:live555
    add_library(${PROJECT_NAME} STATIC ${SRC_LIST})
    

    注意:add_library()可以指定构建STATIC,还可以指定是SHARED和MODULE,但MODULE只能作用在特定系统,使用不常见。

    其他模块除了mediaServer的CMakeList.txt内部组织都如此。

    3.3 mediaServer(main模块)目录下的CMakeList.txt

    project(mediaServer)
    
    include_directories(../UsageEnvironment/include)
    include_directories(../groupsock/include)
    include_directories(../liveMedia/include)
    include_directories(../BasicUsageEnvironment/include)
    
    aux_source_directory(. SRC_LIST)
    
    # 当前模块是main入口,最终目标是编译出live555的可执行文件,因此不再用add_library()
    add_executable(${PROJECT_NAME} ${SRC_LIST})
    
    # 链接所有其他模块到当前模块
    target_link_libraries(${PROJECT_NAME} liveMedia groupsock BasicUsageEnvironment UsageEnvironment)   
    

    大功告成,所有的模块就这样串起来了,但需要注意的是include_directories()是一种较老的写法,更新的是用target_include_directories(), 后面文章再介绍。

    相关文章

      网友评论

          本文标题:CMake教程——基础使用

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