使用cmake自动构建工程

公司引擎是用cmake根据目标平台来构建工程的,刚接触的时候深深体会到cmake的方便:若是目标平台是windows,它能够帮你自动构建出vs工程;若是是安卓,自动构建出eclipse工程,若是是IOS,自动构建出xcode工程。想一想之前用vs建工程的时候,若是要引入第三方库,必需要手动配置第三方库路径,若是引入的库少,那还没什么,若是多的话就悲剧了,配个环境都要半天。再想一想之前在linux平台下手动写Makefile的时候,若是工程比较小,模块少还好办,若是工程大,模块多,各类写依赖关系都要让你抓狂。有了cmake这个工具,咱们彻底能够靠它来帮咱们构建vs工程,写Makefile文件。既然cmake构建工程这么方便,固然须要拿来用,但是对于我这个小白来讲,怎么学呢?果断谷歌,百度,不过并无找到比较有价值的学习资料,不少人都是贴出了cmake的源文件CMakeLists.txt,而后对文件中的每行都讲了下做用。看完这些,我依然不知道为何要这么写,为何这行要这样写,那行要那样写?后来才反应过来,cmake官网确定有讲啊,虽然是英文的,虽然本身英文比较挫,没办法,谁叫没有其它资料呢(其实官网讲的才说最权威的,不要由于是英文就畏惧,看多了其实英文也没那么难,不少人自认为英文不行或者看英文吃力就去网上找各类中文资料,结果可能花费了大量时间在找资料上,到最后啥都没学到)。本文主要经过讲解cmake中一些比较简单的命令来构建本身的工程,做为初学者的入门。html

 

一、两行命令帮你构建输出hello world的vs工程linux

      为了自动构建工程,须要在源文件所在的最上层目录写一个CMakeLists.txt文件,它是cmake的源文件,也能够看做是cmake的脚本文件,这个文件描述了cmake怎样帮咱们自动构建工程。如今咱们有一个hello.cpp文件,须要用这个文件来构建一个vs工程,手动的方法就是打开vs,新建一个工程hello,而后把hello.cpp添加到hello工程里面。而有了cmake,只须要在CMakeLists.txt写两行命令,第一行给本身工程命个名hello,第二行hello工程须要的源文件hello.cpp。而后经过下面几个步骤,就能够生成一个vs工程了,生成其它工程的步骤相同,只是在选择目标工程的时候不一样。windows

1.1 编写CMakeLists.txt文件和hello.cpp文件xcode

CMakeLists.txteclipse

project(hello)

add_executable(hello hello.cpp)

hello.cpp函数

复制代码
#include <stdio.h>

int main (int argc, char *argv[])
{
    printf("hello world!");
    return 0;
}
复制代码

 

1.2 设置路径工具

 

 

 

 

 

 

 

 

 

 

 

1.3 设置目标工程为vs工程学习

1.4  产生vs工程ui

1.5 打开vs工程,编译运行程序spa

 

2 添加子模块

      对于比较大的工程来讲,包含多个子模块是很常见的事,由于一般每一个人只是负责他本身的模块。那么怎样将各个模块加入到主工程中呢?首先咱们须要使用cmake来建立各个子模块的工程,而后再将这些模块加入到整个工程中。假设如今咱们有一个子模块myhello,它提供了一个函数PrintHelloWorld来打印hello world!,主模块hello调用这个函数来打印。首先咱们在hello.cpp所在目录建立myhello文件夹,将myhello.cpp和myhello.h放到里面,而后在这个文件夹中建立CMakeLists.txt。这三个文件的具体内容以下:

myhello/myhello.h:

void PrintHelloWorld();

myhello/myhello.cpp

#include <stdio.h>

void PrintHelloWorld()
{
    printf("hello world!");
}

myhello/CMakeLists.txt

add_library(myhello myhello.cpp)

这个CMakeLists.txt主要是告诉cmake,为myhello建立一个库工程。

hello.cpp

复制代码
#include "myhello/myhello.h"

int main (int argc, char *argv[])
{
    PrintHelloWorld();
    return 0;
}
复制代码

CMakeLists.txt

复制代码
cmake_minimum_required(VERSION 3.5)

project(hello)

add_subdirectory(myhello)
set (EXTRA_LIBS ${EXTRA_LIBS} myhello)

add_executable(hello hello.cpp)

target_link_libraries (hello ${EXTRA_LIBS})
复制代码

       add_subdirectory将myhello子工程加入到主工程,target_link_libraries将子模myhello连接到hello中。而后从新cmake下,打开vs就能够编译运行啦。

3 添加可配置的头文件

      cmake能够经过可配置的头文件来产生实际的头文件,以下面的可配置头文件hello.h.in,里面@@引用的变量能够经过CMakeLists.txt来设置,最后经过cmake来替换hello.h.in文件中的变量并生成hello.h内容。

hello.h.in

#define VERSION_MAJOR @VERSION_MAJOR@
#define VERSION_MINOR @VERSION_MINOR@

CMakeLists.txt

复制代码
cmake_minimum_required(VERSION 3.5)

project(hello)

include_directories("${PROJECT_BINARY_DIR}")
set(VERSION_MAJOR 1)
set(VERSION_MINOR 0)
configure_file(
    "${PROJECT_SOURCE_DIR}/hello.h.in"
    "${PROJECT_BINARY_DIR}/hello.h"
)

add_subdirectory(myhello)
set (EXTRA_LIBS ${EXTRA_LIBS} myhello)


add_executable(hello hello.cpp)

target_link_libraries (hello ${EXTRA_LIBS})
复制代码

上面加红的命令主要用来设置hello.h.in中的两个变量,而且让cmake生成hello.h文件。生成的hello.h以下:

hello.h

#define VERSION_MAJOR 1
#define VERSION_MINOR 0

再修改下hello.cpp文件使用这两个变量,

hello.cpp

复制代码
#include "myhello/myhello.h"
#include "hello.h"
#include <stdio.h>

int main (int argc, char *argv[])
{
    printf("version:%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
    PrintHelloWorld();
    return 0;
}
复制代码

打开vs工程,编译运行输出者两个变量的值。这样就能够经过在CMakeLists.txt中设置变量的内容来动态修改.h文件,增长了代码的灵活性。

 

4 检测系统是否有支持工程须要的函数

      对于跨平台的工程来讲,检查系统是否支持某些特性是颇有必要的,这样程序中就能够经过系统的特性来选择具体执行哪些代码。其中检查是否支持某些函数是咱们常常要作的事情,如epoll函数,可能有的linux系统就不支持,对于不支持的系统咱们只能用poll来替代等。在cmake中检查系统是否支持某个函数也很简单,先包含一个CheckFunctionExists库,而后使用check_function_exists来判断就好了。

CMakeLists.txt

复制代码
cmake_minimum_required(VERSION 3.5)

project(hello)

include (CheckFunctionExists)
check_function_exists (printf HAVE_PRINTF)

include_directories("${PROJECT_BINARY_DIR}")
set(VERSION_MAJOR 1)
set(VERSION_MINOR 0)
configure_file(
    "${PROJECT_SOURCE_DIR}/hello.h.in"
    "${PROJECT_BINARY_DIR}/hello.h"
)

add_subdirectory(myhello)
set (EXTRA_LIBS ${EXTRA_LIBS} myhello)


add_executable(hello hello.cpp)

target_link_libraries (hello ${EXTRA_LIBS})
复制代码

在配置的头文件hello.h.in中加入#cmakedefine HAVE_PRINTF,这样若是系统中有printf函数,最终生成的hello.h中会定义HAVE_PRINTF这个宏,不然不会生成这个宏,在hello.cpp文件中能够根据这个宏来是否认义来判断是否应该使用printf函数。

hello.h.in

#define VERSION_MAJOR @VERSION_MAJOR@
#define VERSION_MINOR @VERSION_MINOR@

#cmakedefine HAVE_PRINTF

hello.cpp

复制代码
#include "myhello/myhello.h"
#include "hello.h"
#include <stdio.h>

int main (int argc, char *argv[])
{
#ifdef HAVE_PRINTF
    printf("version:%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
#endif
    PrintHelloWorld();
    return 0;
}
复制代码

运行结果:

 

5 配置可选项

有时候代码可能包含了全部平台的模块代码,可是对于特定的目标平台,只须要配置该平台须要模块的代码,而不须要配置其它平台模块的代码。这种需求能够经过cmake的配置可选项来完成,配置可选项就是cmake在生成工程的时候提示你一些选项,根据你的选项来具体选择须要添加到工程中的模块代码。例如我如今须要提升是否使用myhello模块的选项,能够在CMakeLists.txt中加option命令来实现,代码以下:

复制代码
cmake_minimum_required(VERSION 3.5)

project(hello)

include (CheckFunctionExists)
check_function_exists (printf HAVE_PRINTF)

include_directories("${PROJECT_BINARY_DIR}")
set(VERSION_MAJOR 1)
set(VERSION_MINOR 0)

option (USE_MYHELLO 
        "Use myhello" ON) 
        
configure_file(
    "${PROJECT_SOURCE_DIR}/hello.h.in"
    "${PROJECT_BINARY_DIR}/hello.h"
)

add_subdirectory(myhello)
set (EXTRA_LIBS ${EXTRA_LIBS} myhello)


add_executable(hello hello.cpp)

target_link_libraries (hello ${EXTRA_LIBS})
复制代码

而且在hello.h.in中添加由cmake根据选项来定义USE_MYHELLO宏。

#define VERSION_MAJOR @VERSION_MAJOR@
#define VERSION_MINOR @VERSION_MINOR@

#cmakedefine HAVE_PRINTF
#cmakedefine USE_MYHELLO

这样在运行cmake的时候,会提示咱们一些选项来进行选择:

经过USE_MYHELLO是否被选择,cmake来肯定是否要在hello.h中定义USE_MYHELLO宏,最终咱们能够在hello.cpp中判断USE_MYHELLO宏是否认义来是否使用myhello模块中的PrintHelloWorld函数。

hello.cpp

复制代码
#include "myhello/myhello.h"
#include "hello.h"
#include <stdio.h>

int main (int argc, char *argv[])
{
#ifdef HAVE_PRINTF
    printf("version:%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
#endif
#ifdef USE_MYHELLO
    PrintHelloWorld();
#else
    printf("xx hello world!");
#endif
    return 0;
}
复制代码

最后经过选中或者不选中USE_MYHELLO选择,获得的结果会不一样。

选中结果

没选中结果:

 

6 总结

      本文主要介绍了下cmake的比较经常使用的一些命令:project、include、include_directories、set、option、configure_file、add_subdirectory、add_executable、target_link_libraries、add_library,算是一个入门吧。须要用好cmake,熟悉cmake的命令和多写cmake脚本是必须的,具体每一个命令的介绍看以参考官方文档:https://cmake.org/cmake/help/v3.5/manual/cmake-commands.7.html,脚步的编写语法能够参考官网文档:https://cmake.org/cmake/help/v3.5/manual/cmake-language.7.html。之后大点的工程建立彻底能够交给cmake来完成,同时也是熟悉cmake的过程。

 

参考:https://cmake.org/cmake/help/v3.5/index.html

相关文章
相关标签/搜索