我们需要懂得CMake文件
我们需要懂得CMake文件一、前言从事于linux下的C++开发的人员都知道,在C++下编写程序是没有类似windows下编译器的一键编译和运行的按钮,只能由我们开发人员进行手动编译、运行;为了减免这种繁琐而且复杂的劳动力,出现了makefile文件,makefile文件可以帮助我们很快的编译大量文件,最终形成可执行文件;其实编写makefile文件并不是很复杂,但是后面出现了cmak...
我们需要懂得CMake文件
一、前言
从事于linux
下的C++开发的人员都知道,在C++下编写程序是没有类似windows下编译器的一键编译和运行的按钮,只能由我们开发人员进行手动编译、运行;为了减免这种繁琐而且复杂的劳动力,出现了makefile
文件,makefile
文件可以帮助我们很快的编译大量文件,最终形成可执行文件;其实编写makefile
文件并不是很复杂,但是后面出现了cmake
,这个可以直接帮我们写makefile
文件,我们只需要编写cmake
文件即可;
接下来,我们去看看cmake
的一些规则和实践,我会从实践中来说明这些规则;
二、cmake
我们从案例开始
-
案例一:
在
demo1
的文件夹下,创建test.cpp
文件和CMakeLists.txt
文件;test.cpp
下存放的是我们测试的c++程序;CMakeLists.txt
就是cmake
文件;测试程序:
#include <iostream>
#include <memory>
using namespace std;
class Test:public enable_shared_from_this<Test>
{
public:
Test(){}
~Test(){}
shared_ptr<Test> getPtr()
{
return shared_from_this();
}
void set(int id,string name)
{
_id = id;
_name = name;
}
int getId()
{
return _id;
}
string getName()
{
return _name;
}
private:
string _name;
int _id;
};
int main()
{
shared_ptr<Test>t1 = make_shared<Test>();
t1->set(1,"test");
cout<<"id:"<<t1->getId()<<endl;
cout<<"name:"<<t1->getName()<<endl;
return 0;
}CMakeList.txt
文件内容:# 指定运行此配置文件所需的 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
#命令表示项目的名称是 Demo1
project (demo1)
#添加-std=c++11选项
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
#命令表示生成项目的名称是 test
add_executable(test test.cpp)然后,我们在当前目录下执行
cmake .
进行编译生成makefile
;
然后,执行make
命令;
我们会发现,当前目录下出现了可执行程序
我们从上面这个案例中,来解析cmake
文件的语法:
-
指定运行此配置文件所需的 CMake 的最低版本,如果不加入此行会受到警告信息
cmake_minimum_required (VERSION 2.8)
-
表示项目的名称是
Demo1
,也就是在哪个文件夹中project (demo1)
-
生成应用程序 test
add_executable(test test.cpp)
-
添加-std=c++11选项
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
或者
add_compile_options(-std=c++11)在
cmake
脚本中,设置编译选项可以通过add_compile_options命令,也可以通过set命令修改CMAKE_CXX_FLAGS
或CMAKE_C_FLAGS
。但是set命令设置CMAKE_C_FLAGS
或CMAKE_CXX_FLAGS
变量则是分别只针对c和c++编译器的;上面我们会发现产生了很多
cmake
的中间文件,我们可以创建一个文件夹,将所有的中间文件以及最终的执行文件放在其中:root@iZuf67on1pthsuih96udyfZ:~/C++/CMake/demo2# mkdir build
root@iZuf67on1pthsuih96udyfZ:~/C++/CMake/demo2# cd build/
root@iZuf67on1pthsuih96udyfZ:~/C++/CMake/demo2/build# cmake ..这样就ok了;
通过上面这个例子,我们大概熟悉了cmake
的最基本的、也是核心的用法;
-
案例二:(多文件)
目录结构
root@iZuf67on1pthsuih96udyfZ:~/C++/CMake/demo2# tree
.
├── CMakeLists.txt
├── hello.cpp
├── hello.h
└── test.cpp
0 directories, 4 files首先看下文件内容:
test.cpp
#include <iostream>
#include <memory>
#include "hello.h"
using namespace std;
class Test:public enable_shared_from_this<Test>
{
public:
Test(){}
~Test(){}
shared_ptr<Test> getPtr()
{
return shared_from_this();
}
void set(int id,string name)
{
_id = id;
_name = name;
}
int getId()
{
return _id;
}
string getName()
{
return _name;
}
private:
string _name;
int _id;
};
int main()
{
shared_ptr<Test>t1 = make_shared<Test>();
shared_ptr<Hello>t2 = make_shared<Hello>();
t1->set(1,"test");
cout<<"id:"<<t1->getId()<<endl;
cout<<"name:"<<t1->getName()<<endl;
t2->setVal(10);
cout<<"val:"<<t2->getVal()<<endl;
return 0;
}hello.h
#pragma once
#include <iostream>
using namespace std;
class Hello
{
public:
Hello();
~Hello();
void setVal(int val);
int getVal();
private:
int _val;
};hello.cpp
#include "hello.h"
Hello::Hello()
{
}
Hello::~Hello()
{
}
void Hello::setVal(int val)
{
_val = val;
}
int Hello::getVal()
{
return _val;
}再看看
cmake
文件:CMakeLists.txt
# 指定运行此配置文件所需的 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
#命令表示项目的名称是 Demo2
project (demo2)
#添加-std=c++11选项
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
#查找当前目录下的所有源文件,并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
#命令表示生成项目的名称是 main
add_executable(main ${DIR_SRCS})解析一下这个用法:
相比于第一个案例来说,这个文件新增了
aux_source_directory(. DIR_SRCS)
这句代码的代表:查找当前目录下的所有源文件,并将名称保存到
DIR_SRCS
变量我们看一下
aux_source_directory
的用法:aux_source_directory(<dir> <variable>)
该命令会把参数
中所有的源文件名称赋值给参数 然后使用
${}
方式获取值;那么,如果在不同的问价夹,那么怎么办?
-
案例三:多文件 多目录
我们只是把上面的文件进行移动,最终的目录结构为:
.
├── CMakeLists.txt
├── hello
│ ├── CMakeLists.txt
│ ├── hello.cpp
│ └── hello.h
└── test.cpp
1 directory, 5 files想比较刚才只是将
hello.h
和hello.cpp
文件移动到hello的文件夹中;我们需要写两个
cmake
文件最外层
CMakeLists.txt
文件内容:# 指定运行此配置文件所需的 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
#命令表示项目的名称是 Demo2
project (demo3)
#添加-std=c++11选项
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
#查找当前目录下的所有源文件,并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 添加 hello 子目录
add_subdirectory(hello)
#命令表示生成项目的名称是 main
add_executable(main ${DIR_SRCS})
#添加动态库
target_link_libraries(main hello)在hello文件夹中的
CMakeLists.txt
文件:# 指定运行此配置文件所需的 CMake 的最低版本
cmake_minimum_required (VERSION 2.8)
#查找当前目录下的所有源文件,并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)
# 生成链接库
add_library(hello ${DIR_LIB_SRCS})相比于前面的
CMakeLists.txt
的文件来说,本次的cmake
文件,多了以下几个规则:
add_library
:该指令的主要作用就是将指定的源文件生成链接文件,然后添加到工程中去。该指令常用的语法如下:
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[source1] [source2] [...])
其中表示库文件的名字,该库文件会根据命令里列出的源文件来创建。而STATIC、SHARED和MODULE的作用是指定生成的库文件的类型。STATIC库是目标文件的归档文件,在链接其它目标的时候使用。SHARED库会被动态链接(动态链接库),在运行时会被加载。MODULE库是一种不会被链接到其它目标中的插件,但是可能会在运行时使用
dlopen-
系列的函数。默认状态下,库文件将会在于源文件目录树的构建目录树的位置被创建,该命令也会在这里被调用。而语法中的source1
source2
分别表示各个源文件。
link_directories
该指令的作用主要是指定要链接的库文件的路径,该指令有时候不一定需要。因为find_package
和find_library
指令可以得到库文件的绝对路径。不过你自己写的动态库文件放在自己新建的目录下时,可以用该指令指定该目录的路径以便工程能够找到。
target_link_libraries
该指令的作用为将目标文件与库文件进行链接。该指令的语法如下:target_link_libraries(<target> [item1] [item2] [...]
[[debug|optimized|general] <item>] ...)
上述指令中的是指通过add_executable()和add_library()指令生成已经创建的目标文件。而[item]表示库文件没有后缀的名字。默认情况下,库依赖项是传递的。当这个目标链接到另一个目标时,链接到这个目标的库也会出现在另一个目标的连接线上。这个传递的接口存储在interface_link_libraries的目标属性中,可以通过设置该属性直接重写传递接口。
这个就是多文件多目录操作,这里贴以下具体流程截图:
-
案例四:(分类文件夹)
在实际公司开发的时候,我们遇到最多就是使用分类文件夹的方式,就比如头文件一般放在当前目录下的
include
的目录下,.cpp
文件一般放在src
文件中,静态、动态库可以放在lib
中;一般来说,这种事比较规范的,而且我们不需要根据头文件进行寻找文件的位置;先看一下案例的目录:
root@iZuf67on1pthsuih96udyfZ:~/C++/CMake/demo5# tree .
.
├── CMakeLists.txt
├── example
│ └── test.cpp
├── include
│ └── hello.h
└── src
└── hello.cpp
3 directories, 4 files简单看一下文件的内容:
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(demo4)
set(CMAKE_CXX_STANDARD 11)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
include_directories(
${PROJECT_SOURCE_DIR}/include/
)
add_library(${PROJECT_NAME} SHARED
src/hello.cpp
)
add_executable(test example/test.cpp)
target_link_libraries(test
${PROJECT_NAME}
)example/test.cpp
#include "hello.h"
int main()
{
HelloTest ht;
ht.Print();
return 0;
}include\hello.h
#include "hello.h"
HelloTest::HelloTest()
{
}
HelloTest::~HelloTest()
{
}
void HelloTest::Print()
{
cout<<"HelloTest"<<endl;
}先来执行一下:
运行一下:
我们发现运行成功了,再看看目录文件:
.
├── build
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ │ ├── 3.5.1
│ │ │ ├── CMakeCCompiler.cmake
│ │ │ ├── CMakeCXXCompiler.cmake
│ │ │ ├── CMakeDetermineCompilerABI_C.bin
│ │ │ ├── CMakeDetermineCompilerABI_CXX.bin
│ │ │ ├── CMakeSystem.cmake
│ │ │ ├── CompilerIdC
│ │ │ │ ├── a.out
│ │ │ │ └── CMakeCCompilerId.c
│ │ │ └── CompilerIdCXX
│ │ │ ├── a.out
│ │ │ └── CMakeCXXCompilerId.cpp
│ │ ├── cmake.check_cache
│ │ ├── CMakeDirectoryInformation.cmake
│ │ ├── CMakeOutput.log
│ │ ├── CMakeTmp
│ │ ├── demo4.dir
│ │ │ ├── build.make
│ │ │ ├── cmake_clean.cmake
│ │ │ ├── CXX.includecache
│ │ │ ├── DependInfo.cmake
│ │ │ ├── depend.internal
│ │ │ ├── depend.make
│ │ │ ├── flags.make
│ │ │ ├── link.txt
│ │ │ ├── progress.make
│ │ │ └── src
│ │ │ └── hello.cpp.o
│ │ ├── feature_tests.bin
│ │ ├── feature_tests.c
│ │ ├── feature_tests.cxx
│ │ ├── Makefile2
│ │ ├── Makefile.cmake
│ │ ├── progress.marks
│ │ ├── TargetDirectories.txt
│ │ └── test.dir
│ │ ├── build.make
│ │ ├── cmake_clean.cmake
│ │ ├── CXX.includecache
│ │ ├── DependInfo.cmake
│ │ ├── depend.internal
│ │ ├── depend.make
│ │ ├── example
│ │ │ └── test.cpp.o
│ │ ├── flags.make
│ │ ├── link.txt
│ │ └── progress.make
│ ├── cmake_install.cmake
│ ├── Makefile
│ └── test
├── CMakeLists.txt
├── example
│ └── test.cpp
├── include
│ └── hello.h
├── lib
│ └── libdemo4.so
└── src
└── hello.cppcmake
产生的中间文件我们不用关心,主要就是在lib文件夹中产生了libdemo4.so
文件;详细看一下
CMakeLists.txt
文件:-
按照C++11标准
set(CMAKE_CXX_STANDARD 11)
-
设置编译动态库输出路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
PROJECT_SOURCE_DIR
代表的是CMakeLists.txt
所在目录 -
include_directories
是用来提供找头文件路径的include_directories(
${PROJECT_SOURCE_DIR}/include/
)
-
基本的cmake
使用的就这么多了,当然,cmake文件还有很多的用法,不过在平时普通的项目中,这些基本够用了,更高级的语法后面还会逐渐完善。
想了解学习更多C++后台服务器方面的知识,请关注: 微信公众号:====CPP后台服务器开发====
更多推荐
所有评论(0)