CMake之简单工程实践(一)

CMake之简单工程实践

 转自:http://blog.csdn.net/cywosp/article/details/9763261

 在实践CMake之前先让我们来看看cmake是什么,下面是从百度百科上摘抄下来的关于cmake的简介:
     CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似UNIX下的automake。只是 CMake 的组态档取名为 CmakeLists.txt。Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Unix 的 Makefile 或 Windows Visual C++ 的 projects/workspaces),然后再依一般的建构方式使用。这使得熟悉某个集成开发环境(IDE)的开发者可以用标准的方式建构他的软件,这种可以使用各平台的原生建构系统的能力是 CMake 和 SCons 等其他类似系统的区别之处。
     CMake 可以编译源代码、制作程式库、产生适配器(wrapper)、还可以用任意的顺序建构执行档。CMake 支援 in-place 建构(二进档和源代码在同一个目录树中)和 out-of-place 建构(二进档在别的目录里),因此可以很容易从同一个源代码目录树中建构出多个二进档。CMake 也支持静态与动态程式库的建构。
    “CMake”这个名字是“cross platform make”的缩写。虽然名字中含有“make”,但是CMake和Unix上常见的“make”系统是分开的,而且更为高阶。

    从上面可知CMake是一个跨平台的编译规则的生成工具,在不同平台上生成不同的编译规则文件,然后我们就可以根据这些文件来编译我们程序了。比 如Linux中生成makefile,Windows中生成project文件。我们都知道当我们的项目非常大时,自己去编写makefile似乎有点繁琐,但是编写CMake相关文件却是非常简单的。下面举几个例子来看看到底有多简单。(本文只举在linux系统中的例子)

1. 首先我们有个简单的程序放在/mnt/test目录中,目录中有一个main.cpp文件,代码如下:

//main.cpp  
   #include <iostream>  
  
   using namespace std;  
  
   int main (int argc, char* argv[])  
  {  
       cout << "Hello World!" << endl;  
       return 0;  
   } 

 现在让我们来编写一个CMake中必不可少的名为CMakeLists.txt文件:

#设置cmake的版本号和向下兼容性,这个是根据系统安装的cmake来确定的,而且这个是一定不能少的,否则就会报错误
cmake_minimum_required(VERSION 2.8)
# cmake_policy可以不用
cmake_policy(VERSION 2.8)
   
#设置工程的名字
project(hello)
    
#将当前目录路径作为源文件所在目录,并把该路径存入变量SRC_LIST中。cmake会在${SRC_LIST}目录中查找相关可以被编译源文件和头文件
#加入到工程中
aux_source_directory(. SRC_LIST)

#通过此来决定最终的生成的可执行文件名,以及生成该所需要的源文件。其中PROJECT_NAME变量是上面project中的名字,它是一个当前工程
#全局变量。SRC_LIST是上面定义的变量
add_executable(${PROJECT_NAME} ${SRC_LIST})

以上就是一个非常简单的CMakeLists.txt文件了,现在让我们来编译该工程。进入工程所在目录
    cd /mnt/test
    先生成makefile文件
    cmake .      #.代码当前目录,你也可以cmake /mnt/test
命令完成之后在当前目录会生成如下几个文件和目录:
    CMakeCache.txt  CMakeFiles  cmake_install.cmake  Makefile
到此我们就得到了最熟悉的MakeFile文件了。当然你会发现突然在工程目录中多了几个文件让工程目录很乱,这让人很不爽。我们可以在系统的任何地方创建一个目录然后进入到该目录中执行cmake /mnt/test,这样临时生成的文件就都在该目录下了。为了简单起见本例中在/mnt/test目录中建了一个build目录。
    mkdir /mnt/test/build
    cd /mnt/test/build
    cmake /mnt/test
    make
这样我们得到了一个名为hello的可执行文件。当然当前编译的程序是Debug版的,如果我们想编译成Release版的我们可以这样做:
    cmake -DCMAKE_BUILD_TYPE=Release /mnt/test #同时也可以将Release改成Debug

 2. 下面我们在来看一个头文件和源文件分离的例子,其目录结构如下:

        /mnt/test2
                    |____src
                    |       |__________Car.cpp
                    |____include
                    |       |__________Car.h
                    |____main.cpp
                    |____build
                           |___________CMakeLists.txt

     //Car.h:  
     #include <iostream>  
      
     class Car   
     {  
     public:  
          Car ();   
         ~Car ();   
     };  
      
     //Car.cpp  
     #include "Car.h"  
      
     Car::Car ()  
     {  
          std::cout << "Constructor" << std::endl;  
     }  
      
     Car::~Car ()  
     {  
            std::cout << "Deconstructor" << std::endl;  
     }  
      
     //main.cpp  
     #include <iostream>  
     #include "Car.h"  
      
    int main (int argc, char* argv[])  
    {  
         Car c;  
         return 0;  
    }  

CMakeLists.txt如下:

#CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
cmake_policy(VERSION 2.8)

project(car)

#将头文件的目录包含到工程中
include_directories(../include)
#将当前目录加入工程中
aux_source_directory(../ PROJECT_ROOT)
#将源文件加入工程中
aux_source_directory(../src SRC)

add_executable(${PROJECT_NAME} ${PROJECT_ROOT} ${SRC})

 3. 下面来看一个编译成库文件的例子,目录结构如下

     /mnt/test3
               |_____libsrc
               |          |____lib
               |          |____include
               |          |        |________Car.h
               |          |____src
               |          |         |________Car.cpp
               |          |_____build   
               |                    |________CMakeLists.txt
               |_____build
               |          |_____CMakeLists.txt
               |_____main.cpp
      其中Car.h和Car.cpp、main.cpp与例2中的一样,变化的是两个CMakeLists.txt

#/mnt/test3/libsrc/build/CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
cmake_policy(VERSION 2.8)

project(car)

#将头文件的目录包含到工程中
include_directories(../include)
#将当前目录加入工程中
aux_source_directory(.. PROJECT_ROOT)
#将源文件加入工程中
aux_source_directory(../src SRC)
#设置库生成后存放的路劲,LIBRARY_OUTPUT_PATH一定要大写不然不生效
set(LIBRARY_OUTPUT_PATH "../lib/")
#将工程编译成一个动态库(libcar.so),SHARED标志生成动态库,STATIC标志生成静态库
add_library(${PROJECT_NAME} SHARED ${PROJECT_ROOT} ${SRC})
 #/mnt/test3/build/CMakeLists.txt
#这里与之前的稍微有点变化——版本号改成了2.8.1。因为在2.8.1之前的版本中link_directories是需要绝对路径的而不能像一下的那样写
cmake_minimum_required(VERSION 2.8.1)
cmake_policy(VERSION 2.8.1)

project(test3)

include_directories(../libsrc/include)
aux_source_directory(../ PROJECT_ROOT)
#将要链接的库所在的路劲加入工程,在上面我们将库编译好后放在了/mnt/test3/libsrc/lib目录中
link_directories("../libsrc/lib")
add_executable(${PROJECT_NAME} ${PROJECT_ROOT})
#设置工程所生成的目标文件所需要的链接的库,在这里我们需要libcar.so这个库
target_link_libraries(${PROJECT_NAME} car)

     在准备好上述文件之后,我们来编译整个程序。首先先编译库进入/mnt/test3/libsrc/build目录中直接执行cmake . && make即可,然后到/mnt/test3/build中同样执行cmake . && make

 4. 到此为止一些简单的工程我们已经能够轻松应付了,以下还有一些写CMakeLists.txt比较常用的:

link_libraries   #设置编译时要连接的库名
假如我们的工程里需要连接数学库和线程库我们可以如下编写,库名之间用空格隔开:link_libraries (m pthread)

add_definitions   #设置编译选项
有时候我们编译工程需要在gcc或者g++中加入以下编译选选项,在此我们可以这样做(选项之间用空格隔开)比如:
add_definitions ("-g -DYOU_DEFINITION")   #-g编译成可调试的程序,YOU_DEFINITION是程序中使用到的宏需要在其之前加上-D

#设置编译好的可执行文件在执行时连接库的路径
set (CMAKE_INSTALL_RPATH .;/usr/local/lib64)
set (CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)

add_subdirectory  #将工程中的子目录加入编译工程中
假如CMakeLists.txt所在目录下有个test目录,test目录中也有一个CMakeLists.txt文件那么我们就可以直接将test目录加入。这在模块编程中很有用:
add_subdirectory (test)

本文对CMake只做简单的工程讲解,其是一个非常强大的工具,可以减少很多我们在开发工程中所遇到的繁杂的问题。网上有很多相关图书和Bolg而且也有很多的开源项目使用了CMake作为编译,有兴趣的可以继续深入。

 

注:在工程开发中为了有所区别大多数编写CMakeLists.txt的时候都采用大写字母。
更多可参考:http://www.cmake.org/cmake/help/cmake_tutorial.html 
其对应的中文:http://www.cnblogs.com/coderfenghc/archive/2013/01/20/2846621.html

https://blog.csdn.net/ma950924/article/details/103166488

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值