• 欢迎访问吴爸爸的技术小木屋

cmake编写

编译方法 [email protected] 5年前 (2020-06-10) 1447次浏览 0个评论

1. 入门实战

1.1. 什么是CMake

我们或许听过好几种Make工具, 例如GNU Make, QT的qmake, 微软的MS nmake, BSD Make(pmake), Makepp, 等等. 这些Make工具遵循着不通的规范和标准, 所执行的Makefile格式也是千差万别. 不mail.yahoo.com.cn就带来了一个严峻的问题: 如果软件想跨平台, 必须保证能够在不同平台编译. 而如果使用上面的Make工具, 就得为每一种标准写一次Makefile, 着将是一件让人抓狂的工作.

CMake就是针对上面问题所设计的工具: 它首先允许开发者编写一种平台无关的CMakeList.txt文件来定制整个编译流程, 然后再根据目标用户的平台进一步生成所需的本地化Makefile和工程文件, 如Unix的Makefile或者Window的Visual Studio工程. 从而遭到"Write once, run everywhere". 显然, CMake是一个比上述几种make更高级的编译配置工具. 一些使用CMake作为项目架构系统的知名开源项目有VTK,ITK,KDE,OpenCV, OSG等.

1.2. 在linux平台下使用CMake生成Makefile并编译的流程如下

  1. 编写CMake配置文件CMakeLists.txt
  2. 执行命令cmake PATH或者ccmake PATH生成Makefile. 其中PATHCMakeList.txt所在的目录
  3. 使用make命令进行编译
  4. 之后的步骤就是使用makefile一样的步骤了

1.3. 入门案例: 单个源文件

  • 示例

    • 示例文件 main.cpp
    #include 
    
    using namespace std;
    
    int main(void)
    {
        cout << "hello world" << endl;
        return 0;
    }
    • CMakeLists.txt
    # 指定运行此配置文件所需要的CMake的最低版本
    cmake_minimum_required(VERSION 3.5) # 根据cmake --version获得
    
    # 表示项目的名称是DEMO1
    project (DEMO1)
    
    # 将名为main.cpp的源文件编译成一个名称为Demo的可执行文件
    add_executable(Demo main.cpp)
    • 生成makefile
    1. main.cpp和CMakeLists.txt放到同一目录下

    2. CMakeLists.txt同一目录下执行

      cmake .
    3. 然后执行make

    4. 从第三步开始和makefile操作相同

1.4. 多个源文件

1.4.1. 同一目录, 多个源文件

  • 示例

    • 创建一个main.cpp
    #include "my_printf.h"
    
    int main(int argc, char const *argv[])
    {
        wtj_printf();
        return 0;
    }
    • 创建一个my_printf.h
    #ifndef __MY_PRINTF_H
    #define __MY_PRINTF_H
    
    void wtj_printf(void);
    
    #endif
    • 创建一个my_printf.cpp
    #include "my_printf.h"
    #include 
    
    using namespace std;
    
    void wtj_printf(void)
    {
        cout << "hello world" << endl;
    }
    • 创建CMakeLists.txt
    # CMake version
    cmake_minimum_required(VERSION 3.5)
    
    # project info
    project (DEMO2)
    
    # 查找当前目录下的所有源文件, 并将名称保存到DIR_SRCS 变量
    aux_source_directory(. DIR_SRCS)
    
    # 指定生成目标
    add_executable(Demo ${DIR_SRCS})
    • 编译执行cmake .

    • 直接执行make, 然后运行可执行程序

1.4.2. 多个目录, 多个源文件

  • 将上面的my_printf.h和my_printf.cpp放到test_a目录下

  • main.cpp放在根目录(必须的)

  • CMakeLists.txt保持不变, 还是在根目录中

    # CMake version
    cmake_minimum_required(VERSION 3.5)
    
    # project info
    project (DEMO2)
    
    # 查找当前目录下的所有源文件, 并将名称保存到DIR_SRCS 变量
    aux_source_directory(. DIR_SRCS)
    
    # Add header file include directories
    include_directories(./ ./test_a)
    
    # Add block directories
    add_subdirectory(test_a)
    
    # 指定生成目标
    add_executable(Demo ${DIR_SRCS})
    target_link_libraries(Demo test_a)
  • test_a目录下的CMakeLists.txt

    aux_source_directory(. DIR_test_a_SRCS)
    add_library(test_a ${DIR_test_a_SRCS})

2. 源外编译(干货)

  • 示例

    # 在项目根目录下创建一个build文件夹
    mkdir build
    
    # 进入build
    cd build
    
    # 使用cmake到根目录下
    cmake ..
    
    # 在build目录下使用make编译项目
    make
    
    ## 之后所有生成的东西都在build目录下, 想删除编译可以直接删除build, 或者build下的所有文件
    • 要点:
      1. 所有的目录下都有CMakeLists.txt(build文件夹除外), 但是都没有编译过, 每一个要生成的目录下都不能有内部编译的方式进行编译出来的任何文件
      2. 使用cmake ..进行编译

3. 个人使用的cmake文件(重点)

  1. 工程根目录下创建一个build文件夹

  2. 将main.cpp放在工程根目录下

  3. 工程根目录下放置CMakeLists.txt

    # CMake version
    cmake_minimum_required(VERSION 3.5)
    
    # get current folder name 
    get_filename_component(CURRENT_FOLDER_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
    string(REPLACE " " "_" CURRENT_FOLDER_NAME ${CURRENT_FOLDER_NAME})
    project(${CURRENT_FOLDER_NAME})
    
    # print variable name
    message(${CURRENT_FOLDER_NAME})
    
    # project name 
    project (DEMO2)
    
    SET(ROOT_DIR ${PROJECT_SOURCE_DIR})
    message("$PROJECT_SOURCE_DIR")
    
    # 查找当前目录下的所有源文件, 并将名称保存到DIR_SRCS 变量
    aux_source_directory(. DIR_SRCS)
    
    # Add header file include directories
    include_directories(./ ./test_a ./test_b) # this should be changed
    
    # Add block directories
    add_subdirectory(test_a)# this should be changed 
    add_subdirectory(test_b)# this should be changed
    
    # 指定生成目标为Demo
    add_executable(Demo ${DIR_SRCS})
    target_link_libraries(Demo test_a test_b) # this should be changed
  4. 在其它有源文件的目录下放置一面的CMakeLists.txt

    # get current file name
    get_filename_component(CURRENT_FOLDER_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
    string(REPLACE " " "_" CURRENT_FOLDER_NAME ${CURRENT_FOLDER_NAME})
    
    # project named current folder name
    project(${CURRENT_FOLDER_NAME})
    
    # print current folder name
    message(${CURRENT_FOLDER_NAME})
    
    # 获得源文件
    aux_source_directory(. DIR_${CURRENT_FOLDER_NAME}_SRCS)
    
    # 将这些源文件编译成名为"当前文件夹名"的"库文件"
    add_library(${CURRENT_FOLDER_NAME} ${DIR_${CURRENT_FOLDER_NAME}_SRCS})

4. 优化的版本

# CMake version
cmake_minimum_required(VERSION 3.5)

# 设置c++ -std=c++11
set(CMAKE_CXX_STANDARD 11)

# 设置工程名
project (DEMO)

# 获取当前目录下的源文件, 并保存到DIR_SRCS中
aux_source_directory(. DIR_SRCS)

# 添加头文件的路径
include_directories(/usr/include/spinnaker ./)

# 设置输出可执行文件路径, PROJECT_SOURCE_DIR是工程根目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)

add_executable(Demo ${DIR_SRCS})
target_link_libraries(Demo Spinnaker) # 链接到spinnaker这个库, 这个是在环境变量中

# 添加pthread, 否则无法编译, 主要是多线程上用的, 用线程就必须用
# target_link_libraries(Demo pthread) 

5. 优化的版本2(使用当前目录下的库)

# CMake version
cmake_minimum_required(VERSION 3.5)

# 设置c++ -std=c++11
set(CMAKE_CXX_STANDARD 11)

# 设置工程名
project (DEMO)

# 获取当前目录下的源文件, 并保存到DIR_SRCS中
aux_source_directory(. DIR_SRCS)

# 添加头文件的路径
include_directories(./)

# 设置输出可执行文件路径, PROJECT_SOURCE_DIR是工程根目录
# set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)

link_directories(${PROJECT_SOURCE_DIR}/lib) # 添加当前目录下的lib, 主要要把对应的头文件也要放到这个源文件下

add_executable(Demo ${DIR_SRCS})
target_link_libraries(Demo -lmodbus) # 链接到spinnaker这个库, 这个是在环境变量中

# 添加pthread, 否则无法编译, 主要是多线程上用的, 用线程就必须用
# target_link_libraries(Demo pthread) 

6. 优化的版本3(英文注释, 使用当前目录下的库)

# CMake version
cmake_minimum_required(VERSION 3.5)

# set c++ -std=c++11
set(CMAKE_CXX_STANDARD 11)

# set project name
project (DEMO)

# add .cpp dir
aux_source_directory(. DIR_SRCS)

# add .h dir
include_directories(./)

# add a custom lib under the current project
link_directories(${PROJECT_SOURCE_DIR}/lib)

# complie all .cpp file
add_executable(Demo ${DIR_SRCS})

# target link a custom lib modbus 
target_link_libraries(Demo -lmodbus)

6.1. 优化的版本4(适合qtcreator创建工程)

# CMake version
cmake_minimum_required(VERSION 3.5)

# set c++ -std=c++11
set(CMAKE_CXX_STANDARD 11)

# set project name
project (DEMO)

# add .h dir
file (GLOB HEADERS "./*.h")

# add .cpp dir
aux_source_directory(. DIR_SRCS )

# put source and header files in a macro, SRC_LIST
SET(SRC_LIST ${SRC_LIST} ${HEADERS} ${DIR_SRCS})

# add a custom lib under the current project
#link_directories(${PROJECT_SOURCE_DIR}/lib)

# complie all .cpp file
add_executable(Demo ${SRC_LIST})
message("${DIR_SRCS}")

# target link a custom lib modbus 
#target_link_libraries(Demo -lmodbus)

6.2. 优化的版本5(适合ros)

# get all .h file
include_directories(include ${catkin_INCLUDE_DIRS})

# get all .cppfile
aux_source_directory(src DIR_SRCS)

add_executable(
  to_usun_node                                              # node name, and the add the source file
  ${DIR_SRCS}                                               # .cpp file
  )
target_link_libraries(to_usun_node ${catkin_LIBRARIES} glog) # add glog
add_dependencies(to_usun_node to_usun_node_generate_messages_cpp) 

6.3. 优化的版本6

#CMake version
cmake_minimum_required(VERSION 3.5)

#set c++ -std=c++11
set(CMAKE_CXX_STANDARD 11)

#set project name
project (DEMO)

#add .cpp dir
aux_source_directory(./src DIR_SRCS) # 这个是存放源文件的文件夹, 并保存到DIR_SRCS

#add .h dir
include_directories(./include) # 这个是存放头文件文件夹

#add a custom lib under the current project
link_directories(${PROJECT_SOURCE_DIR}/lib) # 这个是存放.so文件的文件夹

#complie all .cpp file
add_executable(Demo ${DIR_SRCS}) # 这个是编译所有的源文件的位置

#target link a custom lib modbus 
target_link_libraries(Demo -lpthread)
target_link_libraries(Demo -lcontrolcan) # 添加对应的.so文件的lib库

7. 如何使用

touch CMakeLists.txt
mkdir build
cd build
cmake .. && make

吴爸爸的技术小木屋 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:cmake编写
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址