CMake编写

CMake编写学习笔记

在学习c++的过程中,不可避免的会使用到cmakecmake的亮点在于编译复杂项目上的应用,是一个跨平台的Makefile生成工具。那么在一个项目的建构中,你是否读得懂别人写的cmake文件呢?你要在别人的cmake文件基础上加上自己的内容又要如何编写cmake文件呢?

因此,学习自己手动编写cmake文件是一个不得不进行的一个工作。下面是参考一些博客自己学习的笔记:

参考博客如下:

CMake入门教程

1. CMake编写最简单的模板

#设置cmake最小的版本要求
cmake_minimum_required(VERSION 3.10)
#设置项目名
project(project_name)
#添加可执行文件(第一个参数是生成的可执行文件的名字,第二个参数是源文件)
add_executable(project_name xxx.cpp)

需要注意的是,add_executable里面的cpp可能会包含其他cpp文件,可以在后面依次添加

最简单的示例

步骤

  1. 在任意目录下创建一个新文件夹,写一段c++代码,例如在桌面创建test文件夹,在里面创建一个cpp文件

    cd ~/Desktop
    mkdir test
    cd test
    gedit test.cpp
    

    在里面输入如下内容

    #include<iostream>
    using namespace std;
    int main(int argc,char* argv[]){
    	cout <<"这是最简单的cmake测试示例。。。。"<< endl;
    	return 0;
    }
    

    然后保存就可以了。

  2. 编写CMakeLists.txt文件

    gedit CMakeLists.txt
    

    然后在gedit里输入如下内容:

    #设置cmake最小的版本要求
    cmake_minimum_required(VERSION 3.10)
    #设置项目名
    project(test)
    #添加可执行文件(第一个参数是生成的可执行文件的名字,第二个参数是源文件)
    add_executable(test test.cpp)
    
  3. 执行cmake命令

    一般都会将cmake后的文件都单独放在一个文件夹下,习惯性是build。因此可以执行下列命令

    #创建build文件夹
    mkdir build
    #进入build目录下
    cd build
    #执行cmake命令,".."表示的是上一级目录,cmake会自动在上一级目录中查找CMakeLists.txt文件,并执行
    cmake ..
    

    执行结果会在build文件夹下生成几个文件,可以通过下列命令查看

    ls
    #结果如下,生成了如下文件
    CMakeCache.txt  CMakeFiles  cmake_install.cmake  Makefile
    

    4.执行生成的Makefile文件

    #make会自动寻找当前目录下的Makefile文件
    make 
    

    结果为生成了如下文件,和上面相比多了test这个可执行文件:

    CMakeCache.txt  CMakeFiles  cmake_install.cmake  test  Makefile
    

    5.执行test文件

    ./test
    

    输出结果为:

    这是最简单的cmake测试示例。。。。
    

    到这里这个最简单的示例就结束了,之后更复杂的示例的步骤也和这个大同小异。

2. 包含目录结构的项目

2.1 包含头文件和源文件

  1. 创建一个工程目录,例如:CMakeTest2

  2. 在该目录下创建如下目录结构的文件

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wMr9gMTI-1578209038124)(/home/szq/Pictures/2020-01-03 10-27-11屏幕截图.png)]

    其中Student.h的内容为:

    //
    // Created by szq on 2020/1/3.
    //
    
    #ifndef CMAKETEST2_STUDENT_H
    #define CMAKETEST2_STUDENT_H
    #include "iostream"
    using namespace std;
    class Student{
    private:
        string name;//姓名
        string sno;//学号
        string gender;//性别
        string major;//专业
    public:
    
        Student();
        Student(string name = "",string sno = "",string gender= "",string major = "");
        //获取学生姓名
        string getName();
        //获取学生学号
        string getSno();
        //获取学生性别
        string getGender();
        //获取学生专业
        string getMajor();
    
        //设置学生姓名
        void setName(string name);
        //设置学生学号
        void setSno(string sno);
        //设置学生性别
        void setGender(string gender);
        //设置学生专业
        void setMajor(string major);
    };
    #endif //CMAKETEST2_STUDENT_H
    
    

    Student.cpp的内容为:

    //
    // Created by szq on 2020/1/3.
    //
    #include "Student.h"
    
    Student::Student() {
    
    }
    
    Student::Student(string name, string sno, string gender, string major) {
        setName(name);
        setSno(sno);
        setGender(gender);
        setMajor(major);
    }
    std::string Student::getGender() {
        return this->gender;
    }
    
    std::string Student::getName() {
        return this->name;
    }
    
    std::string Student::getSno() {
        return this->sno;
    }
    
    std::string Student::getMajor() {
        return this->major;
    }
    
    void Student::setName(string name) {
        this->name = name;
    }
    void Student::setSno(string sno) {
        this->sno = sno;
    }
    void Student::setGender(string gender) {
        this->gender = gender;
    }
    void Student::setMajor(string major) {
        this->major = major;
    }
    

    main.cpp中的内容为:

    #include <iostream>
    #include "Student.h"
    using namespace std;
    int main() {
        Student *stu = new Student("szq","M201973343","男","计算机技术");
        cout << "学生姓名为:" << stu->getName() << endl;
        cout << "学生学号为:" << stu->getSno() << endl;
        cout << "学生性别为:" << stu->getGender() << endl;
        cout << "学生专业为:" << stu->getMajor() << endl;
        delete stu;
        return 0;
    }
    

    3.编写CMakeLists.txt文件,内容如下(注意看注释,比较和上一个CMakeLists的区别):

    #设置cmake的最小的版本要求
    cmake_minimum_required(VERSION 3.15)
    #设置工程名,这里和文件夹同名
    project(CMakeTest2)
    #使用include_directories命令来添加包含的头文件目录
    include_directories(include)
    #使用set来设置一个变量SOURCES,变量的值为空格后面的值
    #set(SOURCES src/main.cpp src/Student.cpp)
    
    #这里也是设置一个变量SOURCES,和上面set的效果一样
    file(GLOB SOURCES "src/*.cpp")
    #添加可执行文件,第二个参数这里使用的是变量,相当于src/main.cpp src/Student.cpp
    add_executable(CMakeTest2 ${SOURCES})
    

    4.执行cmake

    mkdir build 
    cd build
    cmake ..
    

    5.执行生成的Makefile文件

    make
    

    6.执行可执行文件

    ./CMakeTest2
    

    执行后的结果为:

    学生姓名为:szq
    学生学号为:M201973343
    学生性别为:男
    学生专业为:计算机技术
    

2.2 动态库编译

​ 步骤1、2和上面2.1中1、2差不多,只是不用创建main.cpp文件

  1. 编写CMakeLists.txt文件,这里没有使用add_executable(),而是使用add_library()
#设置cmake最小的版本要求
cmake_minimum_required(VERSION 3.10.2)
#设置工程名,这里设置为与文件夹同名
project(CMakeTest3)

#设置cmake的build类型
set(CMAKE_BUILD_TYPE Release)
#添加包含头文件目录
include_directories(include)
#设置变量SOURCES
file(GLOB SOURCES "src/*.cpp")
#通过SOURCES中的源文件生成共享库
add_library(CMakeTest3 SHARED ${SOURCES})
#install指定安装目录,执行sudo apt-get install时动态库将被安装在 /usr/lib目录
install(TARGETS CMakeTest3 DESTINATION /usr/lib)

4.执行cmake命令

mkdir build
cd build
cmake ..

5.执行Makefile文件

make

这里生成的文件有所不同,没有生成可执行文件,而是生成了一个动态库。如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KCVM3L0S-1578209038125)(/home/szq/Pictures/2020-01-03 11-09-37屏幕截图.png)]

2.3 静态库编译

​ 步骤1、2和上面2.1中1、2差不多,只是不用创建main.cpp文件

  1. 编写CMakeLists文件,编译静态库只需将add_library中参数SHARED换成STATIC即可:
#设置cmake最小的版本要求
cmake_minimum_required(VERSION 3.10.2)
#设置工程名,这里设置为和文件夹同名
project(CMakeTest4)
#设置cmake的build类型
set(CMAKE_BUILD_TYPE Release)
#添加包含头文件目录
include_directories(include)
#设置变量SOURCES
file(GLOB SOURCES "src/*.cpp")
#通过SOURCES中的源文件生成静态库
add_library(CMakeTest4 STATIC ${SOURCES})
#install指定安装目录,执行sudo apt-get install时,静态库将被安装到/usr/lib目录下
install(TARGETS CMakeTest4 DESTINATION /usr/bin)
  1. 执行cmake指令
mkdir build
cd build
cmake ..
  1. 执行Makefile文件
make

执行后的结果和上面生成的文件结构有所不同,上面的.so文件变成了.a文件,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4lN2Ov0P-1578209038125)(/home/szq/Pictures/2020-01-03 11-29-51屏幕截图.png)]

2.4 使用静态库或动态库

​ 步骤1、2和上面2.1中1、2差不多,只是不用创建Student.hStudent.cpp文件,而是创建main.cpp

main.cpp内容为:

#include <iostream>
#include "Student.h"
using namespace std;
int main() {
    Student *stu = new Student("szq","M201973343","男","计算机技术");
    cout << "学生姓名为:" << stu->getName() << endl;
    cout << "学生学号为:" << stu->getSno() << endl;
    cout << "学生性别为:" << stu->getGender() << endl;
    cout << "学生专业为:" << stu->getMajor() << endl;
    delete stu;
    return 0;
}
  1. 编写CMakeLists文件
#设置cmake最低版本要求
cmake_minimum_required(VERSION 3.10.2)
#设置工程名
project(CMakeTest5)
#设置PROJECT_LINK_LIBS变量,值为libCMakeTest3.so
set(PROJECT_LINK_LIBS libCMakeTest3.so)
#设置链接的动态库文件目录
link_directories(/home/szq/CLionProjects/CMakeTest3/build/)
#设置包含的头文件目录
include_directories(/home/szq/CLionProjects/CMakeTest3/include)
#添加可执行文件
add_executable(CMakeTest5 main.cpp)
#设置要链接的动态库
target_link_libraries(CMakeTest5 ${PROJECT_LINK_LIBS})

上面使用的是动态库,如果要使用2.3生成的静态库,只需将PROJECT_LINK_LIBS设置为libCMakeTest4.a即可

4.执行cmake指令

mkdir build
cd build
cmake ..

5.执行Makefile文件

make

执行后生成了可执行文件

6.执行可执行文件

./CMakeTest5

结果为:

学生姓名为:szq
学生学号为:M201973343
学生性别为:男
学生专业为:计算机技术

上面内容说明执行成功了

3. CMake中一些预定义变量

变量说明
PROJECT_SOURCE_DIR工程的根目录
PROJECT_BINARY_DIR运行cmake命令的目录,通常是${PROJECT_SOURCE_DIR}/build
CMAKE_INCLUDE_PATH环境变量,并非cmake变量
CMAKE_LIBRARY_PATH环境变量
CMAKE_CURRENT_BINARY_DIRtarget编译目录,使用ADD_SURDIRECTORY(src bin)可以更改此变量的值
CMAKE_CURRENT_SOURCE_DIR当前处理的CMakeLists.txt所在的路径
CMAKE_CURRENT_LIST_FILE输出调用这个变量的CMakeLists.txt的完整路径
CMAKE_CURRENT_LIST_LINE输出这个变量所在的行
CMAKE_MODULE_PATH定义自己的cmake模块所在的路径 SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),然后可以用INCLUDE命令来调用自己的模块
EXECUTABLE_OUTPUT_PATH重新定义目标二进制可执行文件的存放位置
LIBRARY_OUTPUT_PATH重新定义目标链接库文件的存放位置
PROJECT_NAME返回通过PROJECT指令定义的项目名称
CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS用来控制IF ELSE语句的书写方式
CMAKE_MAJOR_VERSIONcmake主版本号,如2.8.6中的2
CMAKE_MINOR_VERSIONcmake次版本号,如2.8.6中的8
CMAKE_PATCH_VERSIONcmake补丁等级,如2.8.6中的6
CMAKE_SYSTEM系统名称,例如Linux-2.6.22
CAMKE_SYSTEM_NAME不包含版本的系统名,如Linux
CMAKE_SYSTEM_VERSION系统版本,如2.6.22
CMAKE_SYSTEM_PROCESSOR处理器名称,如i686
BUILD_SHARED_LIBS控制默认的库编译方式。如果未进行设置,使用ADD_LIBRARY时又没有指定库类型,默认编译生成的库都是静态库
CMAKE_C_FLAGS设置C编译选项
CMAKE_CXX_FLAGS设置C++编译选项

4.CMake常用命令

命令语法说明
PROJECTPROJECT(projectname[CXX][C][JAVA])指定工程名称,并可指定工程支持的语言。支持语言列表可忽略,默认支持所有语言。
SETSET(VAR[VALUE][CACHE TYPE DOCSTRING[FORCE]])定义变量(可以定义多个VALUE,如SET(SRC_LIST main.c util.c reactor.c))
MESSAGEMESSAGE([SEND_ERROR|STATUS|FATAL_ERROR] “message to display” …)向终端输出用户定义的信息或变量的值。SEND_ERROR,产生错误,生成过程被跳过;STATUS,输出前缀为1的信息;FATAL_ERROR,立即终止所有cmake过程
ADD_EXECUTABLEADD_EXECUTABLE(bin_file_name ${SRC_LIST})生成可执行文件
ADD_LIBRARYADD_LIBRARY(libname [SHARED|STATIC|MODULE][EXCLUDE_FROM_ALL] SRC_LIST)生成动态库或静态库;SHARED动态库;STATIC静态库;MODULE在使用dyld的系统有效。若不支持dyld,等同于SHARED;EXCLUDE_FROM_ALL表示该库不会被默认构建
SET_TARGET_PROPERTIES设置输出的名称,设置动态库的版本和API版本
CMAKE_MINIMUM_REQUIREDCMAKE_MINIMUM_REQUIRED(VERSION version_number [FATAL_ERROR])声明CMake的版本要求
ADD_SUBDIRECTORYADD_SUBDIRECTORY(src_dir [binary_dir] [EXCLUDE_FROM_ALL])向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制的存放位置EXCLUDE_FROM_ALL含义:将这个目录从编译过程中排除
INCLUDE_DIRECTORIESINCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 … )向工程添加多个特定的头文件搜索路径,路径之间用空格分隔,如果路径包含空格,可以使用双引号将它括起来,默认的行为为追加到当前头文件搜索路径的后面。
LINK_DIRECTORIESLINK_DIRECTORIES(dir1 dir2 …)添加非标准的共享库搜索路径
TARGET_LINK_LIBRARIESTARGET_LINK_LIBRARIES(target lib1 lib2 …)target添加需要链接的共享库
ADD_DEFINITIONSADD_DEFINITIONS(-DENABLE_DEBUG -DABC)C/C++编译器添加-D定义,参数之间用空格分割
ADD_DEPENDENCIESADD_DEPENDENCIES(target-name depend-target1 depend-target2 …)定义target依赖的其他target,确保target在构建之前,其依赖的target已经构建完毕
AUX_SOURCE_DIRECTORYAUX_SOURCE_DIRECTORY(dir VAR)发现一个目录下所有的源代码文件并将列表存储在一个变量中把当前目录下的所有源码文件名赋给变量DIR_HELLO_SRCS
EXEC_PROGRAMEXEC_PROGRAM(Executable [dir where to run] [ARGS <args>][OUTPUT_VARIABLE ] [RETURN_VALUE <value>])用于在指定目录运行某个程序(默认为当前CMakeLists.txt所在目录),通过ARGS添加参数,通过OUTPUT_VARIABLERETURN_VALUE获取输出和返回值
INCLUDEINCLUDE(file [OPTIONAL])/INCLUDE(module [OPTIONAL])用来载入CMakeLists.txt文件/用来载入预定义的cmake模块;OPTIONAL参数的左右是文件不存在也不会产生错误,可以载入一个文件,也可以载入预定义模块(模块会在CMAKE_MODULE_PATH指定的路径进行搜索),载入的内容将在处理到INCLUDE语句时直接执行
  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值