Bootstrap

CMake学习

Cmake

  • 工具链

    • 预处理器(宏替换)->编译器->汇编器(二进制文件.obj&&.0)->链接器->变成.exe
  • 单源文件可以直接命令生成.exe

    • 解决1:源文件多时要编写makefile,但编写makefile文件很麻烦
    • 解决2:使用cmake,跨平台,可以直接生成makefile
  • 命令行直接编译源文件

    • g++ *.cpp -o app
    • 会生成一个app.exe
    • ./app
  • 编写CMakelist.txt

    • # ======================================================================================
      # 指定cmake的最低版本
      cmake_minimum_required(VERSION 3.0.0)  
      # 指定工程名
      project(CALC) 
      # 生成可执行文件名app: add_executable(可执行程序名 源文件名称) 后面的源文件用空格or;
      # add_executable(app add.c div.c main.c mult.c sub.c) 
      # ======================================================================================
      # 设置变量值: set(变量名, 变量值) 后面的变量值用空格隔开  
      set(SRC_LIST add.c div.c main.c mult.c sub.c)
      # 取变量值
      add_executable(app ${SRC_LIST})
      # 设置c++版本为c++11
      set(CMAKE_CXX_STANDARD 11)
      # 设置app.exe的输出路径
      set(HOME /home/fyq/...)
      set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin)
      # ======================================================================================
      # 搜索文件 
      # aux_source_directory(${PROJECT_SOURSE_DIR} SRC_LIST)
      # file(GLOB/GLOB_RECURSE SRC ${CMAKE_CURRENT_SOURSE_DIR}/*.cpp)
      # ======================================================================================
      
    • 执行cmake命令,cmake后面跟的目录是CMakelist.txt所在的目录,会生成一系列文件,一般是在build文件夹中执行,生成Makefile文件后执行make命令即可生成可执行文件

    • set命令

      • 设置变量值
        • set(SRC_LIST add.c div.c main.c mult.c sub.c):设置SRC_LIST的值为add.c ...
        • add_executable(app ${SRC_LIST}):取变量值用${}
      • 设置指定的c++版本: c++11c++14c++17默认是c++98
        • 方法一:g++ *.cpp -std=c++11 -o app
        • 方法二:在CMakelist.txt文件中指定 ,加入set(CMAKE_CXX_STANDARD 11)
      • 设置可执行文件的输出路径 建议使用绝对路径
        • set(HOME /home/fyq/...)
        • set(EXECUTABLE_OUTPUT PATH ${HOME}/bin)
    • set命令需要找到所有的文件,仍然很麻烦,因此有搜索文件命令

      • 方法一:aux_source_directory ${PROJECT_SOURSE_DIR}:CMakelist.txt所在目录路径
        • aux_source_directory(${PROJECT_SOURSE_DIR} SRC_LIST):找到源文件目录下的所有文件,并赋值给SRC_LIST
        • add_executable(app ${SRC_LIST})
      • 方法二:file命令 ${CMAKE_CURRENT_SOURSE_DIR}:CMakelist.txt所在目录路径
        • file(GLOB/GLOB_RECURSE SRC ${CMAKE_CURRENT_SOURSE_DIR}/*.cpp):递归搜索某目录文件搜索所有.cpp文件,将值赋给SRC变量
    • 指定头文件所在路径

      • include_directories(${CMAKE_CURRENT_SOURSE_DIR}/include)head.h/include目录下
    • 动态库和静态库

      • 注意:静态库会被加到生成文件中,因此应该在生成可执行文件即add_exectable()命令前运行,但是动态库不会被加,因此需要在生成可执行文件后执行,一般就是放在文件最末尾
      • 都由lib_xxx.xxx组成,第二个是xxx是后缀
        • 若是动态库 有可执行权限
          • windowslib_xxx.dll
          • linuxlib_xxx.so
        • 若是静态库 无可执行权限
          • windowslib_xxx.lib
          • linuxlib_xxx.a
      • 制作静态库:例如制作一个计算器,只需要add.c div.c ...不需要main.c
        • add_library(库名称 STATIC 源文件1 源文件2...)add_library(calc STATIC ${SRC})
      • 制作动态库
        • add_library(库名称 SHARED 源文件1 源文件2...):``add_library(calc SHARED ${SRC})`
      • 指定输出库的路径 设置宏${LIBRARY_OUTPUT_PATH}
        • set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURSE_DIR}/lib)
    • 有了静态库和动态库之后,之前的div.c add.c...就不需要了,只需要使用库文件就行

      • 链接静态库库文件
        • link_libraries(静态库名字1 名字2...)link_libraries(calc)
      • 对于自定义的库文件,还需要指定路径
        • link_directories(path)link_directories(${CMAKE_CURRENT_SOURSE_DIR}/lib)
      • 链接动态库文件 注意:链接动态库需要写在生成可执行文件之后(add_executable(…))
        • target_link_libraries(动态库名称)target_link_libraries(app calc) app是可执行文件,表示app要链接动态库,后面的calc是被链接的动态库名称
    • 日志

      • message(重要程度 消息):message(STATUS "message status") 默认重要
        • STATUS:非重要
        • WARNING:警告,继续执行
        • SEND_ERROR:继续执行,但是跳过所有生成步骤
        • FATAL_ERROR:cmake错误,终止所有
    • 变量操作

      • 字符串拼接:
        • list(APPEND 变量名 [子字符串])list(APPEND ${SRC} ${TEMP})TEMP的值追加到SRC
        • set(变量名 字符串1 字符串2 ..)set(tmp ${tmp1} ${tmp2})tmp1tmp2的内容拼接,放到tmp
      • 字符串删除:
        • list(REMOVE_ITEM 变量名 [子字符串])list(REMOVE_ITEM ${SRC} main.cpp)
      • list其他功能 list底层存储了很多的字符串,每个字符串通过;相隔
        • 获取长度:list(LENGTH 列表名字 输出变量)
        • 获取索引处值:list(GET 列表名字 索引位置)
          • 索引位置-1表示最后一个元素
        • 将列表中的元素连接成新字符串:list(JOIN 列表名字 指定连接字符串 输出变量)
        • 列表中是否存在指定元素:list(FINO 列表名字 搜索元素 输出变量)
          • 存在则返回索引,否则返回-1
        • 插入元素在指定位置:list(INSERT 列表名字 索引 插入元素1 插入元素2...)
        • 移除最后元素:list(POP_BACK 列表名字 存储弹出元素的变量:可省略)
        • 将指定索引删除:list(REMOVE_AT 列表名字 索引)
        • 删除重复元素:list(REMOVE_DUPLICATED 列表名字)
        • 列表反转:list(REVERSE 列表名字)
        • 列表排序:list(SORT 列表名字 COMPARE:... CASE:... ORDER:...)
          • COMPARE:指定排序方法
            • STRING:字母顺序,默认
            • FILE_BASENAME:若是一系列路径名,会使用basename排序
            • NATURAL:使用自然数顺序排序
          • CASE:是否大小写敏感
            • SENSITIVE:大小写敏感,默认
            • INSENSITIVE:大小写不敏感
          • ORDER:指定排序顺序
            • ASCENDING:升序排列,默认
            • DESCENDING:降序排序
    • 自定义宏 用来控制日志是否输出

      • add_definitions(-D宏名称)add_definitions(-DDEBUG) 定义了一个DEBUG宏
    • Cmake嵌套

      • 子节点可以使用父节点的变量值

      • $ tree
        .
        ├── build
        ├── calc
        │   ├── add.cpp
        │   ├── CMakeLists.txt
        │   ├── div.cpp
        │   ├── mult.cpp
        │   └── sub.cpp
        ├── CMakeLists.txt
        ├── include
        │   ├── calc.h
        │   └── sort.h
        ├── sort
        │   ├── CMakeLists.txt
        │   ├── insert.cpp
        │   └── select.cpp
        ├── test1
        │   ├── calc.cpp
        │   └── CMakeLists.txt
        └── test2
            ├── CMakeLists.txt
            └── sort.cpp
        
      • 假如目录结构如上图所示,其中

        • include是头文件目录
        • calc对应加减乘除
        • sort对应两种排序
        • test1test2是计算器和排序的测试程序
      • 为了让test1test2能使用计算器和排序,因此需要将calcsort里的内容生成库文件,若源文件多,则生成动态库,否则生成静态库,因为生成静态库会将库文件放在输出的文件夹中

      • 添加子目录

        • add_subdirectory(子目录名)add_subdirectory(calc)
      • 示例

        • 根目录CMakelist.txt

          • # 最小版本
            cmake_minimum_required(VERSION 3.0)
            # 可执行文件名
            peoject(test)
            # 静态库输出路径
            set(LIBPATH ${CMAKE_CURRENT_SOURSE_DIR}/lib)
            # 头文件目录路径
            set(HEADPATH ${CMAKE_CURRENT_SOURSE_DIR}/lib)
            # 生成库文件名称
            set(CALCLIB calc)
            set(SORTLIB sort)
            # 可执行文件程序名
            set(APPNAME1 app1)
            set(APPNAME2 app2)
            
            # 给当前目录添加子节点
            add_subdirectory(calc)
            add_subdirectory(sort)
            add_subdirectory(test1)
            add_subdirectory(test2)
            
        • calc目录CMakelist.txt sort目录下的同理

          • # 最小版本
            cmake_minimum_required(VERSION 3.0)
            # 可执行文件名
            peoject(calc)
            # 搜索源文件 在./下搜索所有文件,放到SRC中
            aux_sourse_directory(./ SRC)
            # 添加头文件 因为calc用到了calc.h 
            include_directories(${HEADPATH}) # 子节点可以使用父节点的变量
            # 设置库文件输出位置	LIBRARY_OUTPUT_PATH是系统定义的宏
            set(LIBRARY_OUTPUT_PATH ${LIBPATH})
            # 生成静态库文件
            add_library(${CALCLIB} STATIC ${SRC})
            
        • test1目录CMakelist.txt test2目录同理

          • # 最小版本
            cmake_minimum_required(VERSION 3.0)
            # 可执行文件名
            peoject(test1)
            # 搜索文件
            aux_sourse_directory(./ SRC)
            # 添加头文件
            include_directories(${HEADPATH})
            # 指定静态库文件地址
            link_directories(${LIBPATH})
            # 链接静态库
            link_libraries(CALCLIB)
            # 设置可执行文件生成路径 EXECUTABLE_OUTPUT_PATH是系统定义的宏
            set(EXECUTABLE_OUTPUT_PATH ${EXECPATH})
            # 生成可执行文件
            add_executable(${APPNAME1} ${SRC})
            
    • 在静态库中链接静态库

      • 一样使用link_directorieslink_libraries
    • find_package():查找依赖包

;