• CMake简介


    一、CMake简介

    • CMake是一个跨平台的编译工具,能够输出各种各样的makefile或者project文件。
    • CMake并不直接构建出最终的软件,而是生成标准的Makefile文件或者VisualStudio项目文件,然后再使用Make或者VisualStudio进行编译。
    • CMake在Windows平台上生成VisualStudio项目文件,在Linux和Unix平台上生成Makefile文件。

    二、CMake典型示例

    源代码 demo.cpp

    int main()
    {
        return 0;
    }
    

    cmake脚本 CMakeLists.txt

    # CMake 最低版本号要求
    cmake_minimum_required (VERSION 2.8)
    # 项目信息
    project (demo)
    # 指定生成目标
    add_executable(demo demo.cpp)
    

    编译流程

    • Windows

      1. 创建build文件夹
      2. 在build文件夹中执行 cmake .. 命令
      3. 用Visual Studio打开生成的demo.sln,然后编译
    • Linux

    mkdir build
    cd build
    cmake ..
    make
    

    三、CMake常用命令

    CMake中常用的语法包含三类:

    • 命令
    • 变量
    • 属性

    常用命令介绍

    设置编译目标类型

    • add_executable 生成可执行文件
    • add_library 生成库文件

    比如:

    add_executable(demo demo.cpp)
    add_library(common util.cpp)
    

    add_library默认生成静态库,可以显式的控制生成的库的类型

    add_library(common STATIC util.cpp) #生成静态库
    add_library(common SHARED util.cpp) #生成动态库或共享库
    

    通过以上命令生成文件名字,在Windows下是:

    demo.exe
    common.lib
    common.dll
    

    在Linux下是:

    demo
    libcommon.a
    libcommon.so
    

    指定编译包含的源文件

    1. 明确指定包含的源文件
    add_executable(demo demo.cpp test.cpp util.cpp)
    
    1. 搜索所有的cpp文件
    aux_source_directory(. SRC_LIST) #搜索当前目录下的所有.cpp文件
    add_executable(demo ${SRC_LIST})
    
    1. 自定义搜索规则
    file(GLOB SRC_LIST "*.cpp" "*.cc")
    add_executable(demo ${SRC_LIST})
    
    1. 包含多个文件夹的文件
    file(GLOB SRC_LIST "*.cpp" "protocol/*.cpp")
    add_executable(demo ${SRC_LIST})
    # 或者
    file(GLOB SRC_LIST "*.cpp")
    file(GLOB SRC_PROTOCOL_LIST "protocol/*.cpp")
    add_executable(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
    # 或者
    aux_source_directory(. SRC_LIST)
    aux_source_directory(protocol SRC_PROTOCOL_LIST)
    add_executable(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
    
    1. 通过模糊搜索的方式包含源文件,当添加新的源文件后,需要通过cmake命令重新生成Makefile或者VS项目文件

    设置包含目录

    include_directories(
        ${CMAKE_CURRENT_SOURCE_DIR}
        ${CMAKE_CURRENT_BINARY_DIR}
        ${CMAKE_CURRENT_SOURCE_DIR}/include
    )
    

    Linux下还可以通过如下方式设置包含目录

    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}")
    

    设置链接库搜索目录

    link_directories(
        ${CMAKE_CURRENT_SOURCE_DIR}/libs64
    )
    

    Linux下还可以通过如下方式设置包含目录

    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_CURRENT_SOURCE_DIR}/libs64")
    

    设置需要链接的库

    根据链接库目录搜索

    target_link_libraries(demo Math)
    
    • 在Windows下,会根据链接库目录,搜索Math.lib文件
    • 在Linux下,会根据链接库目录搜索如下文件:
    libMath.so
    libMath.a
    

    默认优先链接动态库,可以在链接时指定动态库或者静态库如:

    target_link_libraries(demo Math.a)  # 链接libMath.a
    target_link_libraries(demo Math.so) # 链接libMath.so
    

    指定全路径

    target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs64/libMath.a)
    target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs64/libMath.so)
    

    指定多个链接库

    target_link_libraries(demo 
        ${CMAKE_CURRENT_SOURCE_DIR}/libs64/libMath.a 
        boost_system.a 
        boost_thread 
        pthread)
    

    设置变量

    1. set 直接设置变量的值
    set(SRC_LIST main.cpp test.cpp)
    add_executable(demo ${SRC_LIST})
    
    1. set 追加变量的值
    set(SRC_LIST main.cpp)
    set(SRC_LIST ${SRC_LIST} test.cpp)
    add_executable(demo ${SRC_LIST})
    
    1. list 追加或者删除变量的值
    set(SRC_LIST main.cpp)
    list(APPEND SRC_LIST test.cpp)
    list(REMOVE_ITEM SRC_LIST main.cpp)
    add_executable(demo ${SRC_LIST})
    

    条件控制

    • if else elseif endif
    if(MSVC)
        set(LINK_LIBS common)
    else()
        set(boost_thread boost_log.a boost_system.a)
    endif()
    
    target_link_libraries(demo ${LINK_LIBS})
    
    # 或者
    if(UNIX)
       set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fpermissive -g")
    else()
        add_definitions(-D_SCL_SECURE_NO_WARNINGS 
        -D_CRT_SECURE_NO_WARNINGS 
        -D_WIN32_WINNT=0x601 
        -D_WINSOCK_DEPRECATED_NO_WARNINGS)
    endif()
    
    if(${CMAKE_BUILD_TYPE} MATCHES "debug")
        ...
    else()
        ...
    endif()
    
    • while break continue foreach end_while end_foreach

    其他常用命令

    • message 显示一些消息
    message(${MY_VAR})
    message("build with debug mode")
    message(WARNING "this is warnning message")
    message(FATAL_ERROR "this build has many error") # 会导致生成失败
    
    • source_group 在Windows下起作用,设置源文件在项目中的目录结构
    file(GLOB PROTOCOL_FILES "protocol/*.cpp")
    source_group("协议" FILES ${PROTOCOL_FILES})
    
    • set_target_properties 设置项目属性
    • set_property 设置全局属性、项目属性等
    set_property(GLOBAL PROPERTY USE_FOLDERS ON)
    #设置项目在解决方案中的目录结构,只在Windows下生效
    set_target_properties(ServerManager PROPERTIES FOLDER "manager")
    
    • include 包含其他cmake文件
    include(./common.cmake) #指定包含文件的全路径
    include(def) #在搜索路径中搜索def.cmake文件
    set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) #设置include的搜索路径
    

    四、复杂项目示例

    多个目录,多个源文件,多个项目

    项目目录结构如下:

    ./demo
        |
        +--- main.cc
        |
        +--- math/
              |
              +--- MathFunctions.cc
              |
              +--- MathFunctions.h
    

    这种情况还可以通过add_subdirectory的方式添加子目录

    添加cmake脚本后的目录结构如下:

    ./demo
        |
        +--- CMakeLists.txt
        |
        +--- main.cc
        |
        +--- math/
              |
              +--- CMakeLists.txt
              |
              +--- MathFunctions.cc
              |
              +--- MathFunctions.h
    
    

    demo下的CMakeLists.txt文件如下:

    cmake_minimum_required (VERSION 2.8)
    project(demo)
    aux_source_directory(. DIR_SRCS)
    
    # 添加math子目录
    add_subdirectory(math)
    
    # 指定生成目标
    add_executable(demo ${DIR_SRCS})
    
    # 添加链接库
    target_link_libraries(demo MathFunctions)
    

    math目录中的CMakeLists.txt:

    aux_source_directory(. DIR_LIB_SRCS)
    # 生成链接库
    add_library(MathFunctions ${DIR_LIB_SRCS})
    

    五、常用变量

    构建类型

    cmake默认支持多种构建类型(build type),每种构建类型都有专门的编译参数变量,详情见下表

    CMAKE_BUILD_TYPE 对应的c编译选项变量 对应的c++编译选项变量
    None CMAKE_C_FLAGS CMAKE_CXX_FLAGS
    Debug CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG
    Release CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE
    RelWithDebInfo CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_RELWITHDEBINFO
    MinSizeRel CMAKE_C_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_MINSIZEREL

    指定构建类型

    1. Windows的VS项目属于多配置型,可以在VS中选择生成的配置
    2. 生成后的项目默认包含四种配置
    3. 改变默认的配置
    set(CMAKE_CONFIGURATION_TYPES "Debug;RelWithDebInfo")
    
    1. 默认生成的平台类型为Win32,如果需要x64类型,则需要按如下命令执行
    cmake -G "Visual Studio 14 2015 Win64" ..
    
    1. Linux下的Makefile属于单配置型,需要指定生成配置
    2. 默认执行 cmake ..,会生成None配置
    3. 可以通过命令行指定配置
    cmake -DCMAKE_BUILD_TYPE=Debug ..
    
    1. 可以在CMake文件中指定配置
    set(CMAKE_BUILD_TYPE DEBUG)
    

    变量

    • 变量的引用方式是使用“${}”,在if命令中,不需要使用这种方式,直接使用变量名即可
    • 自定义变量使用SET(OBJ_NAME xxxx),使用时${OBJ_NAME}

    常用变量

    • CMAKE_BINARY_DIR,PROJECT_BINARY_DIR,_BINARY_DIR:
      这三个变量内容一致,如果是内部编译,就指的是工程的顶级目录,如果是外部编译,指的就是工程编译发生的目录。

    • CMAKE_SOURCE_DIR,PROJECT_SOURCE_DIR,_SOURCE_DIR:
      这三个变量内容一致,都指的是工程的顶级目录。

    • CMAKE_CURRENT_BINARY_DIR:外部编译时,指的是target目录,内部编译时,指的是顶级目录

    • CMAKE_CURRENT_SOURCE_DIR:CMakeList.txt所在的目录

    • CMAKE_CURRENT_LIST_DIR:CMakeList.txt的完整路径

    • CMAKE_CURRENT_LIST_LINE:当前所在的行

    • CMAKE_MODULE_PATH:如果工程复杂,可能需要编写一些cmake模块-,这里通过SET指定这个变量

    • LIBRARY_OUTPUT_DIR,BINARY_OUTPUT_DIR:库和可执行的最终存放目录

    环境变量

    • 使用环境变量:$ENV{Name}
    • 写入环境变量:set(ENV{Name} value) #这里没有“$”符号

    系统信息

    • CMAKE_MAJOR_VERSION,CMAKE 主版本号,比如2.4.6 中的2
    • CMAKE_MINOR_VERSION,CMAKE 次版本号,比如2.4.6 中的4
    • CMAKE_PATCH_VERSION,CMAKE 补丁等级,比如2.4.6 中的6
    • CMAKE_SYSTEM ,系统名称,比如Linux-2.6.22
    • CMAKE_SYSTEM_NAME ,不包含版本的系统名,比如Linux
    • CMAKE_SYSTEM_VERSION ,系统版本,比如2.6.22
    • CMAKE_SYSTEM_PROCESSOR,处理器名称,比如i686
    • UNIX ,在所有的类UNIX平台为TRUE,包括OS X 和cygwin
    • WIN32 ,在所有的win32 平台为TRUE,包括cygwin

    主要开关选项

    • BUILD_SHARED_LIBS, 这个开关用来控制默认的库编译方式,如果不进行设置,使用add_library 并没有指定库类型的情况下,默认编译生成的库都是静态库。如果set(BUILD_SHARED_LIBS ON) 后,默认生成的为动态库
    • CMAKE_C_FLAGS 设置C编译选项,也可以通过指令add_definitions() 添加
    • CMAKE_CXX_FLAGS 设置C++ 编译选项,也可以通过指令add_definitions() 添加

    六、参考资料

  • 相关阅读:
    Java的审计项目导入---基于现有的微服务项目上再加个xmsj
    vo中对date格式的时间格式的处理,方便到前台展示
    Java的Maven项目的导入
    [2020-05]测试短信发送记录
    那些年总是记不住的前端写法!
    【HTML+CSS】比较清淡的一个表格。
    C# 里这么写 busiDate.replace('-', ' ').trim(),可以把2020-04-01转为 20200401;java里这么些只能转为2020 04 01……
    radType条件没有用?
    我的程序里面出现了下面的警告:Unreachable code请问是什么原因?该怎么解决呢?
    ubuntu18.04安装Charles及问题
  • 原文地址:https://www.cnblogs.com/hbccdf/p/introduction_of_cmake.html
Copyright © 2020-2023  润新知