• 【CMake基础】一文带你CMake从0到-1


    I、CMake介绍

    没有CMake时:
    在这里插入图片描述

    一份cpp文件,想要被工程使用,WINDOWS下用VS,MAC下用Xcode,linux下用Makefile很多,每个系统分平台都要分别构建,非常的麻烦.

    有CMake之后
    开发者先写一个CMakeLists.txt,然后通过cmake命令去生成不同平台的项目工程,一步到位.
    假如有需要修改的文件,只需要修改CMakeLists.txt一步即可到位.

    在这里插入图片描述

    • CMake是一个跨平台的编译,安装工具,可以用简单的语句来实现所有平台的安装(编译过程)

    1. CMake语法特性

    • 基本语法格式:指令(参数1 参数2 …)
      • 参数使用()括起来
      • 参数之间使用空格分号分开
    • 变量使用${}方式取值,但在IF控制语句中是直接使用变量名
    • 指令是大小写无关的, 参数和变量是大小写相关的
    set(TEST   test.cpp)
    add_executable(test   main.cpp   test.cpp)
    ADD_EXECUTABLE(test   main.cpp   ${TEST})
    
    • 1
    • 2
    • 3

    2. CMake重要指令

    • cmake_minimum_required- 指定CMake的最小版本要求
      • 语法:cmake_minimum_required(VERSION visionNumber [FATAL_ERROR])
      • #CMake最小版本要求为2.8.3,中括号内为可选项
        cmake_minimum_required(VERSION 2.8.3)


    • project-定义工程名称,并可制定工程支持的语言
      • 语法:project(projectname [CXX] [C] [Java])
      • #指定工程名为HELLOWORLD
        project(HELLOWORLD)


    • set- 显式的定义变量

      • 语法:set(VAR [VALUE] [CACHE TUPE DOCSTRING [FORCE]])
      • #定义SRC变量,其值为main.cpp hello.cpp
        set(SRC main.cpp hello.cpp)


    • include_directories- 向工程添加多个特定的头文件搜索路径 —>相当于指定g++编译器的-l参数

      • 语法:include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)
      • #将/usr/include/myincludefolder 和 ./include 添加到头文件搜索路径
        include_directories(/usr/include/myincludefolder ./include)


    • link_directories- 向工程添加多个特定的库文件搜索路径 —>相当于指定g++编译器的-L参数

      • 语法:link_directories(dir1 dir2 ...)
      • #将/usr/include/mylibfolder 和 ./lib 添加到头文件搜索路径
        link_directories(/usr/include/mylibfolder ./lib)


    • add_library- 生成库文件

      • 语法:add_library(libname [SHARED | STATIC | MODULE] [EXCLUDE_FROM_ALL] source1 source2 ... sourceN),其中shared代表动态库,static代表静态库
      • #通过SRC生成libhello.so共享库
        add_library(hello SHARED ${SRC})


    • ```add_compile_options``- 添加编译参数

      • 语法:add_compile_options(
      • #添加编译参数 -Wall -std=c++11 优化代码
        add_compile_options(-Wall -std=c++11 -O2)


    • add_executable- 生成可执行文件
      • 语法:add_executable(exename source1 source2 ...sourceN)
      • #编译main.cpp生成可执行文件main
        add_executable(main main.cpp)


    • target_link_libraries- 为target添加需要链接的共享库 —>相当于指定g++的编译器-I参数
      • 语法:target_link_libraries(target libtaty1 library2...)
      • #将hello动态库文件链接到可执行文件main
        target_link_libraries(main hello)


    • aux_source_directory- 发现一个目录下所有源码文件并将列表存放在一个变量中,这个指令被临时用来自动构建源文件列表
      • 语法:aux_source_directory(dir VARIABLE)
      • #定义SRC变量,其值为当前目录下所有的源码文件
        aux_source_directory(. SRC)
        #编译SRC变量所代表的源码文件,生成main可执行文件
        add_executable(main ${SRC})


    3. CMake常用变量

    • CMAKE_C_FLAGS—gcc编译选项
    • CMAKE_CXX_FLAGS—g++编译选项
      • #在CMAKE_CXX_FLAGS编译选项后追加-std=c++11
        set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11"})


    • CMAKE_BUILD_TYPE—编译类型(debug, release)
      • #设定编译类型为debug, 调试时选择debug
        set(CMAKE_BUILD_TYPE Debug)
        #设定编译类型为release, 调试时选择release
        set(CMAKE_BUILD_TYPE Release)


    • CMAKE_BINARY_DIRPROJECT_BINARY_DIR<工程名>_BINARY_DIR
    1. 这三个变量指代的内容一致
    2. 如果是in source build,值得就是工程顶层目录
    3. 如果是out-of-source编译,指的是工程编译发生的目录
    4. PROJECT_BINARY_DIR和它们略有不同

    • CMAKE_C_COMPILER:指定C编译器
    • CMAKE_CXX_COMPILER:指定C++编译器
    • EXECUTABLE_OUTPUT_PATH:可执行文件输出的存放路径
    • LIBRARY_OUTPUT_PATH:库文件输出的存放路径\

    II、CMake编译工程

    CMake目录结构:项目主目录存在一个CMakeLists.txt文件

    1. 编译流程

    1. 手动编写CMakeLists.txt
    2. 执行命令cmake PATH生成Makefile(PATH是顶层CMakeLists.txt所在的目录)
    3. 执行命令make编译

    2. 两种构建方式

    2.1 内部构建

    不推荐,同级目录中间文件和工程源文件混乱

    # 在当前目录,编译,生成Makefile和其他文件
    cmake .
    # 执行make,生成target
    make
    
    • 1
    • 2
    • 3
    • 4

    2.2 外部构建

    推荐,将编译文件与工程源文件分开存放

    mkdir build
    cd build
    # 编译上级目录的CMakeLists.txt,生成Makefile和其他文件
    cmake ..
    # 执行make,生成目标文件
    make
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    CMake多文件多目录例子

    来看下目录结构:
    在这里插入图片描述

    CMakeLists.txt代码

    在和test.cpp的同级目录下,来写我们的CMakeLists.txt,它的代码如下:

    cmake_minimum_required(VERSION 3.0)
    
    project(A)
    include_directories(./include)
    
    add_executable(main test.cpp ./src/a.cpp)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 前两句没什么好说的,前边有提
    • 第三句是头文件路径
    • 第四句是库路径 和 将两个文件一起编译得到可执行文件main
    • 第三句第四句合起来的作用等于# g++ test.cpp ./src/a.cpp -I./include -o main

    执行和效果

    依次编译执行

    $ mkdir build && cd build
    $ cmake ..
    -- The C compiler identification is GNU 9.4.0
    -- The CXX compiler identification is GNU 9.4.0
    -- Check for working C compiler: /usr/bin/cc
    -- Check for working C compiler: /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: /usr/bin/c++
    -- Check for working CXX compiler: /usr/bin/c++ -- works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Detecting CXX compile features
    -- Detecting CXX compile features - done
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/qinsir/my_car/rubbsh/build
    $ make 
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/qinsir/my_car/rubbsh/build
    Scanning dependencies of target main
    [ 33%] Building CXX object CMakeFiles/main.dir/test.cpp.o
    [ 66%] Building CXX object CMakeFiles/main.dir/src/a.cpp.o
    [100%] Linking CXX executable main
    [100%] Built target main
    $ ./main 
    successful!
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    例子的源码

    1. a.cpp
    #include "a.hpp"
    void a_print()
    {
        cout << "successful!" << endl ;
        return ;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. a.hpp
    #ifndef __A_H_
    #define __A_H_
    
    #include
    using namespace std ;
    
    void a_print() ;
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. test.cpp
    #include 
    #include"a.hpp"
    
    using namespace std ;
    
    int main(int argc, char * argv[])
    {
        a_print();
    
        return 0 ;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    超六成专科生的月薪不足5000元?网友:本科和研究生也是
    手写生产者消费者模型
    HTML5+CSS3+移动web 前端开发入门笔记(二)HTML标签详解
    [Linux]编写一个极简版的shell(版本1)
    完整的代码
    appium自动化测试技术
    Linux进程信号
    Java基础:简单工厂模式、工厂方法模式和抽象工厂模式综合概述
    文件误删除如何找回呢?四步妙招解决
    【Linux03-基本工具之VIM】Linux下的强大编辑器(附软件生态与yum)
  • 原文地址:https://blog.csdn.net/Eric_Sober/article/details/126249214