• CMake基本使用


    CMake基本使用



    1. Linux环境安装

    1. 安装gcc软件依赖

      yum install -y gcc gcc-c++ make automake
      
      # 输出版本则安装成功
      gcc -v 
      
      • 1
      • 2
      • 3
      • 4
    2. 下载最新CMake

      https://cmake.org/download/

      # 下载完成后解压
      tar -xvf [压缩包]
      
      • 1
      • 2
    3. 进入根目录,运行命令

      ./bootstrap
      
      • 1

      如果出现以下错误:
      在这里插入图片描述
      运行命令:

      yum install  -y openssl  openssl-devel
      
      • 1

      然后重新运行即可

      ./bootstrap
      
      • 1
    4. 运行gmake

      gmake
      
      • 1
    5. 进行安装

      gmake install
      
      • 1

      输入cmake -v,如果出现版本号则安装成功:
      在这里插入图片描述

    2. 使用CMake运行C++程序

    2.1 运行简单的示例程序

    用vim编写一段C++代码:

    #include <iostream>
    using namespace std;
    int main() {
            cout << "hello world" << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在同一个目录下编写CMakeLists.txt文件:

    PROJECT (HELLO)
    SET(SRC_LIST main.cpp)
    MESSAGE(STATUS "This is BINARY dir" ${HELLO_BINARY_DIR})
    MESSAGE(STATUS "This is SOURCE dir" ${HELLO_SOURCE_DIR})
    ADD_EXECUTABLE (hello ${SRC_LIST})
    
    • 1
    • 2
    • 3
    • 4
    • 5

    使用CMake生成Makefile文件:

    cmake .
    
    • 1

    在这里插入图片描述自动生成了以下文件:

    在这里插入图片描述

    使用make命令编译:

    make
    
    • 1

    在这里插入图片描述
    编译出了一个可执行文件
    在这里插入图片描述
    运行可执行文件:

    hello
    
    • 1

    在这里插入图片描述

    3. CMake基本语法

    用上面编写的CMakeLists.txt文件做示例:

    PROJECT (HELLO)
    SET(SRC_LIST main.cpp)
    MESSAGE(STATUS "This is BINARY dir" ${HELLO_BINARY_DIR})
    MESSAGE(STATUS "This is SOURCE dir" ${HELLO_SOURCE_DIR})
    ADD_EXECUTABLE (hello ${SRC_LIST})
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.1 关键字

    PROJECT关键字

    可以用来指定工程的名字和支持的语言,默认支持所有语言.
    PROJECT (HELLO):指定了工程的名字,并且支持所有语言.
    PROJECT (HELLO CXX):指定了 工程的名字,并且支持语言是C++.
    PROJECT (HELLO C CXX):指定了工程的名字,并且支持语言是C和C++.

    该指令隐式定义了两个CMAKE的变量
    <projectname>_ BINARY_ DIR,本例中是HELLO_ BINARY_ DIR.
    <projectname>_ SOURCE_ DIR, 本例中是HELLO_ SOURCE DIR.
    MESSAGE关键字就可以直接使用这两个变量,当前都指向当前的工作目录,后面会讲外部编译.

    问题:如果改了工程名,这两个变量名也会改变.
    解决:可以使用CMake为我们预定义的两个变量: PROJECT_ BINARY_ DIRPROJECT_SOURCE_ DIR, 这两个变量和HELLO_ BINARY_ DIR, HELLO_ SOURCE_ DIR是一致的.

    SET关键字

    用于显示的指定变量.
    SET(SRC_ LIST main.cpp)指令中的SRC_ LIST变量就包含了main.cpp.
    如果当前有多个cpp文件,也可以SET(SRC_LIST main.cpp t1.cpp t2.cpp).

    MESSAGE关键字

    向终端输出用户自定义的信息
    主要包含三种信息:

    • SEND_ ERROR,产生错误,生成过程被跳过.
    • SATUS, 输出前缀为-的信息.
    • FATAL_ ERROR,立即终止所有cmake过程.

    ADD_EXECUTABLE关键字

    生成可执行文件
    ADD_ EXECUTABLE(hello ${SRC_ LIST})指令表示生成的可执行文件名是hello,源文件读取变量SRC_ LIST中的内容.
    也可以直接写ADD_ EXECUTABLE(hello main.cpp).

    所以工程名HELLO与生成的可执行文件名hello是没有任何关系的.

    上述例子可以简化的写成:

    PROJECT(HELLO)
    ADD_EXECUTABLE(hello main.cpp)
    
    • 1
    • 2

    3.2 语法的基本原则


    • 变量使用${}方式取值,但是在IF控制语句中可以直接使用变量名.
    • 指令(参数1 参数2…) 参数使用括弧括起,参数之间使用空格或分号分开.以上面的ADD_ EXECUTABLE指令为例,如果存在另外一个func.cpp源文件
      就要写成: ADD_ EXECUTABLE(hello main.cpp func.cpp)或者ADD_ EXECUTABLE(hello main.cpp;func.cpp).
    • 指令是大小写无关的,但是参数和变量是大小写相关的。推荐全部使用大写指令.
    • SET(SRC_ LIST main.cpp)可以写成SET(SRC_ LIST "main.cpp"), 但是如果源文件名中含有空格,就必须要加双引号.

    3.3 内部构建和外部构建

    • 内部构建:上述例子就是内部构建,生产的临时文件特别多,不方便清理.
    • 外部构建:会把生成的临时文件放在build目录下,不会对源文件有任何影响,推荐使用外部构建的方式.

    外部构建

    先回退到刚刚编写完CMakeLists.txt文件的时候:
    在这里插入图片描述创建一个build目录并进入:

    mkdir build
    cd build
    
    • 1
    • 2

    build目录中执行cmake命令:

    cmake ..
    
    • 1

    build目录中执行make命令:

    make
    
    • 1

    生成的临时文件都会在build目录中:

    在这里插入图片描述

    4. 工程化项目

    • 为工程添加一个子目录src,用来放置工程源代码.
    • 添加一个子目录doc,用来放置这个工程的文档hello.txt.
    • 在工程目录添加文本文件COPYRIGHT README.
    • 在工程目录添加一个runhello.sh脚本,用来调用hello二进制.
    • 将构建后的目标文件放入构建目录的bin子目录.
    • doc目录的内容以及 COPYRIGHT/README 安装到/usr/share/doc/cmake/.
    .
    ├── build
    ├── CMakeLists.txt
    ├── COPYRIGHT
    ├── doc
    │   └── hello.txt
    ├── README
    ├── runhello.sh
    └── src
        ├── CMakeLists.txt
        └── main.cpp
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4.1 生成二进制文件到bin目录中

    每个目录下都要有一个CMakeLists.txt说明:

    .
    ├── build
    ├── CMakeLists.txt
    └── src
        ├── CMakeLists.txt
        └── main.cpp
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    外层CMakeLIsts.txt

    PROJECT(HELLO)
    ADD_SUBDIRECTORY(src bin)
    
    • 1
    • 2

    src下的CMakeLists.txt

    ADD_EXECUTABLE(hello main.cpp)
    
    • 1

    ADD_SUBDIRECTORY指令

    ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

    • 这个指令用于向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置.
    • EXCLUDE_FROM_ALL函数是将写的目录从编译中排除,如程序中的example.
    • ADD_SUBDIRECTORY(src bin)
      将src子目录加入工程并指定编译输出(包含编译中间结果)路径为bin目录
      如果不进行bin目录的指定,那么编译结果(包括中间结果)都将存放在build/src目录.

    更改二进制的保存路径

    SET指令重新定义EXECUTABLE_OUTPUT_PATHLIBRARY_OUTPUT_ PATH变量来指定最终的目标二进制的位置:

    SET(EXECUTABLE_OUTPUT_PATH ../../src/bin)
    SET(LIBRARY_OUTPUT_PATH ../../src/lib)
    
    • 1
    • 2

    注意:哪里要改变目标存放路径,就在哪里加入上述的定义,所以就在src目录下的CMakeLists.txt中写.

    改变之后重新执行:

    .
    ├── build
    ├── CMakeLists.txt
    └── src
        ├── bin
        │   └── hello
        ├── CMakeLists.txt
        └── main.cpp
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    可以看到可执行文件hello 已经到了src/bin目录下.


    4.2 使用CMake进行安装

    安装文件COPYRIGHT和README

    在根目录下的CMakeLists.txt文件中加上:

    INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)
    
    • 1

    FILES:文件名.
    DESTINATION:
    1.可以直接写绝对路径.
    2.也可以写相对路径,相对路径实际路径是:${CMAKE_INSTALL _PREFIX}/<DESTINATION>定义的路径.
    CMAKE_JINSTALL_PREFIX默认是在/usr/local/.
    cmake-DCMAKE_JNSTALL_PREFIX=/usr 在cmake的时候指定CMAKE_ JNSTALL_ PREFIX变量的路径.

    安装脚本runhello.sh

    PROGRAMS:非目标文件的可执行程序安装(比如脚本之类).

    在根目录下的CMakeLists.txt文件中加上:

    INSTALL(PROGRAMS runhello.sh DESTINATION bin)
    
    • 1

    说明:实际安装到的是/usr/bin.

    安装doc目录下的hello.txt

    在根目录下的CMakeLists.txt文件中加上:

    INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake) 
    
    • 1

    DIRECTORY后面连接的是所在Source目录的相对路径.

    注意: abcabc/有很大的区别

    • 目录名不以/结尾:这个目录将被安装为目标路径下的abc.
    • 目录名以/结尾:将这个目录中的内容安装到目标路径.

    安装

    cd build
    cmake ..
    make
    make install
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述


    5. 静态库与动态库的构建和使用

    静态库和动态库的区别:

    • 静态库的扩展名一般为".a”或".lib"; 动态库的扩展名- -般为".so"或".dIl".
    • 静态库在编译时会直接整合到目标程序中,编译成功的可执行文件可独立运行.
    • 动态库在编译时不会放到连接的目标程序中,即可执行文件无法单独运行.

    下面我们来创建一个静态库和动态库,提供HelloFunc函数供其它程序编程使用,HelloFunc向终端输出Hello World字符串.

    构建实例:

    .
    ├── build
    ├── CMakeLists.txt
    └── lib
        ├── CMakeLists.txt
        ├── hello.cpp
        └── hello.h
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    hello.h中的内容:

    #ifndef HELLO_H
    #define Hello_H
    
    void HelloFunc();
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    hello.cpp中的内容:

    #include "hello.h"
    #include <iostream>
    using namespace std;
    void HelloFunc() {
            cout << "hello world" << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    5.1 单独构建静态库或动态库

    根目录下CMakeLists.txt中的内容:

    PROJECT(HELLO)
    ADD_SUBDIRECTORY(lib bin)
    
    • 1
    • 2

    lib目录下CMakeLists.txt中的内容:

    SET(LIBHELLO_SRC hello.cpp)
    ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
    
    • 1
    • 2

    ADD_LIBRARY

    ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

    • hello: 就是正常的库名,生成的名字前面会加上lib,最终产生的文件是libhello.so.
    • SHARED:动态库;STATIC: 静态库.
    • ${LIBHELLO_ SRC}:源文件.

    在这里插入图片描述

    5.2 同时构建静态库和动态库

    SET_TARGET_PROPERTIES

    这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和API版本.

    同时构建静态和动态

    lib目录下CMakeLists.txt中的内容:

    SET(LIBHELLO_SRC hello.cpp)
    
    ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
    
    SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
    SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
    
    ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
    
    SET_TARGET_PROPERTIES(hello PROPERTIES OUTPUT_NAME "hello")
    SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    编译之后:

    在这里插入图片描述

    5.3 动态库的版本号

    一般动态库都有一个版本号的关联.

    libhello.so.1.2
    libhello.so ->libhello.so.1
    libhello.so.1->libhello.so.1.2
    
    • 1
    • 2
    • 3

    CMakeList.txt插入如下:

    SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)
    
    • 1

    VERSION指代动态库版本,SOVERSION指代API版本.

    5.4 安装共享库和头文件

    本例中我们将hello的共享库安装到<prefix>/lib目录,将hello.h安装到<prefix>/include/hello目录.

    在lib目录下CMakeLists.txt的添加:

    # 文件放到该目录下
    INSTALL(FILES hello.h DESTINATION include/hello)
    
    # 二进制、静态库、动态库安装都用TARGETS
    # ARCHIVE 特指静态库,LIBRARY 特指动态库,RUNTIME 特指可执行目标二进制
    INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    安装的时候指定一下路径,放到系统下:

    cmake -D CMAKE_INSTALL_PREFIX=/usr ..
    
    • 1

    在这里插入图片描述

    5.5 使用共享库和头文件

    构建实例:

    .
    ├── build
    ├── CMakeLists.txt
    └── src
        ├── CMakeLists.txt
        ├── main.cpp
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    main.cpp中的内容:

    #include <hello.h>
    using namespace std;
    int main() {
    	HelloFunc();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    根目录下的CMakeLists.txt:

    PROJECT(HELLO)
    ADD_SUBDIRECTORY(src bin)
    
    • 1
    • 2

    src下的CMakeLists.txt:

    ADD_EXECUTABLE(hello main.cpp)
    
    • 1

    然后编译:

    会报找不到hello.h头文件的错误:
    在这里插入图片描述需要在src下的CMakeLists.txt加上:

    # 表示在hello目录下去找头文件
    INCLUDE_DIRECTORIES(/usr/include/hello)
    
    • 1
    • 2

    再编译,还会报错,找不到HelloFunc这个函数:

    在这里插入图片描述
    可以使用TARGET_LINK_LIBRARIES关键字添加需要链接的共享库,注意一定要写在ADD_EXECUTABLE关键字的后面:

    TARGET_LINK_LIBRARIES (hello libhello.so)
    
    • 1

    注意hello是生成的二进制文件的名字.

    所以最终src下的CMakeLists.txt文件内容:

    INCLUDE_DIRECTORIES(/usr/include/hello)
    
    ADD_EXECUTABLE(hello main.cpp)
    
    TARGET_LINK_LIBRARIES (hello libhello.so)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    再次编译的时候,就可以成功生成可执行文件hello了,但是运行hello的时候会再次报错:

    在这里插入图片描述

    原因是我们之前生成的动态库libhello.so是在/usr/lib/目录下的,但是我的linux系统是64位的,需要把这个动态库移动到/usr/lib64/目录下才能使用:

    mv /usr/lib/libhello.so /usr/lib64/
    
    • 1

    之后就可以正常运行了:

    在这里插入图片描述

  • 相关阅读:
    【NET 7.0、OpenGL ES】使用Silk.NET渲染MMD,并实时进行物理模拟。
    一致性协议-ChainPaxos详解
    MODBUS RTU转CCLINK协议网关
    Deformable Convolution 可变形卷积
    debian无法使用reboot 等系统命令解决
    webservice笔记
    高通道筛选出的小分子 应用到伊蚊“控制”
    springboot写一个简单的接口样例
    GIT相关内容总结
    学习记忆——数学篇——案例——代数——方程——一元二次方程
  • 原文地址:https://blog.csdn.net/qq_49723651/article/details/125503470