C/C++学习笔记-CMake教程

在Linux的开发环境下,大多数个的就是CMake和make来对编译继进行管理。但是对于很多像我这样的新手来说。makefile规则过于复杂。有个同事说,这两个的关系就像是汇编语言和C++语言一样,我觉得比喻得十分贴切。本文就CMake的学习做一个笔记。


简单的helloworld

首先我们在工作目录上新建一个helloworld.cpp的文件,然后再新建一个CMakeLists.txt的文件。如下:

|

然后编写CMakeLists.txt文件

#项目名称
PROJECT(HELLOWORLD)

#定义变量
SET(SRC_LIST helloworld.cpp)

#打印用户的一些信息
MESSAGE(STATUS "This is BINARY dir " ${HELLOWORLD_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir "${HELLOWORLD_SOURCE_DIR})

#生成可执行文件
ADD_EXECUTABLE(helloworld ${SRC_LIST})

在当前目录下执行cmake . ("."表示当前目录)执行成功后,发现工作目录多了很多东西,其中有最重要的是生成了makefile文件。然后就可以执行make命令,生成可执行文件。大功告成

 编写规则:

在上面的CMakeLists.txt中有5条指令。我们来一条一条的看。

#项目名称
           PROJECT(HELLOWORLD)

这条指针是必须的,以大写的PROJECT指明项目的名称,注意:这个名称和生成的可执行文件名字没有关系。原型为PROJECT(projectname [CXX] [C] [Java]),后面省略的是指明支持的语言,一般不写

#定义变量
           SET(SRC_LIST helloworld.cpp)

SET指令,用于申明变量,例如这里就是以SRC_LIST 代替 helloworld.cpp,后面如果要使用的话就直接以变量的形式${SRC_LIST}来表示helloworld.cpp 。注意:这里的变量名一般都是用大写和下划线组成,个人习惯。

 

          #打印用户的一些信息
          MESSAGE(STATUS "This is BINARY dir " ${HELLOWORLD_BINARY_DIR})
          MESSAGE(STATUS "This is SOURCE dir "${HELLOWORLD_SOURCE_DIR})

这两条命令是在cmake编译的时候打印一些关于路径的信息,打印的形式如下。你可能会疑问,${HELLOWORLD_BINARY_DIR}和${HELLOWORLD_SOURCE_DIR}打印出来的是源码路径和最后生成可执行文件的路径。但是,我们在前面并没有SET这两个变量,那是因为,PROJECT命令不仅定义了项目名称,还悄悄给我们定义了俩个变量,规则是项目名称_BINARY_DIR和 项目名称_SOURCE_DIR,所以我们直接使用就行。

-- This is BINARY dir /root/mcloud/MyWorkSpace/helloworld/src
-- This is SOURCE dir /root/mcloud/MyWorkSpace/helloworld/src

#生成可执行文件
           ADD_EXECUTABLE(helloworld ${SRC_LIST})

这个命令就是生产可执行文件的命令了。第一个参数就是生成可执行文件的名字,后面相关的源文件。

总结:简单来说4步,PSMA


但是有个问题:就是在我们进行编译的时候回生成很多中间文件,就是上面那些,而与项目本身无关,会导致项目结构看起来很混乱。那么,我们的做法是:新建一个build文件夹,把所有的编译信息放到这个文件夹里面。

 编译的时候,进入build文件夹,然后执行cmake ..(".."表示上一级目录),当然也可以在其他地方建build文件夹,只不过后面要指定CMakeLists.txt的路径即可,它会在指定的路径下面寻找CMakeLists.txt文件。

项目级别的helloworld

在实际的项目中,目录结构绝不会像上面的例子那样简单,一个工程目录简单结构入下所示:build文件夹,用于存放编译后的文件(包括二进制文件,可执行文件等);CMakeLists.txt文件,整个项目的cmake文件,用于整个各个子目录的cmake文件;src文件夹,用于存放整个项目的源码。我们做的是要在工程下CMakeLists.txt 文件中整合各个子目录的CMakeLists.txt 。因此要懂得怎么写工程下和子目录下的CMakeLists.txt 。

helloworld
├── build  //用于存放编译后的文件
├── CMakeLists.txt //整个项目的cmake文件
└── src //存放源码的文件夹
    ├── CMakeLists.txt //子目录的cmake文件
    └── helloworld.cpp //源码

我们先来看子目录下的CMakeLists.txt ,在一个工程中可能有很多个子目录,每个子目录都要有CMakeLists.txt 。每个子目录CMakeLists.txt写法都是一个简单的helloworld类似的写法,只是PROJECT的申明不需要放在里面,应该放在工程下CMakeLists.txt的文件里。如下:

#定义变量
SET(SRC_LIST helloworld.cpp)

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

#生成可执行文件
ADD_EXECUTABLE(helloworld ${SRC_LIST})

工程目录下的CMakeLists.txt:该camke主要是整合整个项目的编译。很简单,一个是声明项目的名称,一个是整合子目录,ADD_SUBDIRECTORY(src bin),src表示子目录,bin表示创建编译文件的地方。注意这里有一个新的命令ADD_SUBDIRECTORY,区别在于这个命令不是用来生成可执行文件的,而是用来整合子目录编译文件的。

#项目名称
PROJECT(HELLOWORLD)

#生成可执行文件
ADD_SUBDIRECTORY(src bin)

使用CMake编译共享库(动态和静态库)

在某些情况下,我们需要已经编译好的库文件直接使用。当我们实现某个常用功能,就可以将其编译成库,然后直接使用就可以(使用的时候,只需要一个库文件和一个头文件就可以用了,大大缩短了我们开发周期)。什么叫动态库和静态库?顾名思义,静态库:就是当我们编译的时候就需要链接到目标文件的库;而动态库,就是我们在运行程序的时候才需要的库。好了,下面看一下,怎么样把自己平时写的功能和一些公共函数编译成共享库。

目录结构:

.
├── print
│   ├── CMakeLists.txt
│   ├── printHello.cpp
│   └── printhello.h
└── CMakeLists.txt//工程下的,后面将这个CMakelists简称为总CMakelists

如上的目录结构,假设有一个print文件夹,里面有三个文件。我们需要把print里面的函数编成共享库,供以后使用。print里面CMakelists为:

SET(PRINT_LIST printHello.cpp)

SET(DCMAKE_INSTALL_PREFIX /root/mcloud/MyWorkSpace/helloworld/)

#=======编译动态库和静态库=========
#step1 编译成xxx.so 和xxx_static.a
ADD_LIBRARY(printhello SHARED ${PRINT_LIST})
ADD_LIBRARY(printhello_static STATIC ${PRINT_LIST})

#step2 将xxx_static 以xxx的形式输出
SET_TARGET_PROPERTIES(printhello_static PROPERTIES OUTPUT_NAME "printHello")
GET_TARGET_PROPERTY(OUTPUT_VALUE printhello_static OUTPUT_NAME)

#step3 打印信息
MESSAGE (STATUS "This is the printhello_static OUTPUT_NAME: " ${OUTPUT_VALUE})

#step4 防止被清理掉,需要同时得到两种库文件
SET_TARGET_PROPERTIES(printhello PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(printhello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)

#step5 给动态库加上版本号
SET_TARGET_PROPERTIES(printhello PROPERTIES VERSION 1.2 SOVERSION 1)
#===========================

#安装到指定路径里面
INSTALL(TARGETS printhello printhello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
INSTALL(FILES printhello.h DESTINATION include/)

总Cmakelists

#项目名称
PROJECT(HELLOWORLD)

#生成可执行文件
ADD_SUBDIRECTORY(print lib)

猜你喜欢

转载自blog.csdn.net/qq_35703954/article/details/81771858