CMake 完整入门教程(五)

CMake 使用实例

13.1
例子一

一个经典的
C
程序,如何用
cmake
来进行构建程序呢?

//main.c

#include

int main()

{

printf(“Hello World!/n”);

return 0;

}

编写一个
CMakeList.txt
文件
(
可看做
cmake
的工程文件
)

project(HELLO)

set(SRC_LIST main.c)

add_executable(hello ${SRC_LIST})

然后,建立一个任意目录(比如本目录下创建一个
build
子目录),在该
build
目录下调用

cmake


注意:为了简单起见,我们从一开始就采用
cmake

out-of-source
方式来构建

(即生成中间产物与源代码分离),并始终坚持这种方法,这也就是此处为什么单

独创建一个目录,然后在该目录下执行
cmake
的原因

cmake .. -G “NMake Makefiles”

CMake 完整入门教程(五)

nmake

CMake 完整入门教程(五)

或者

cmake .. -G “MinGW Makefiles”

make

即可生成可执行程序
hello(.exe)

CMake 完整入门教程(五)

目录结构

+

|
+— main.c

+— CMakeList.txt

|

/–+ build/

 |

 +— hello.exe

CMake 完整入门教程(五)

cmake
真的不太好用哈,使用
cmake
的过程,本身也就是一个编程的过程,只有多练才

行。

我们先看看:前面提到的这些都是什么呢?

13.1.1 CMakeList.txt

第一行
project
不是强制性的,但最好始终都加上。这一行会引入两个变量


HELLO_BINARY_DIR

HELLO_SOURCE_DIR

同时,
cmake
自动定义了两个等价的变量


PROJECT_BINARY_DIR

PROJECT_SOURCE_DIR

因为是
out-of-source
方式构建,所以我们要时刻区分这两个变量对应的目录

可以通过
message
来输出变量的值

message(${PROJECT_SOURCE_DIR})

set
命令用来设置变量

add_exectuable
告诉工程生成一个可执行文件。

add_library
则告诉生成一个库文件。


注意:
CMakeList.txt
文件中,命令名字是不区分大小写的,而参数和变量是大小写

相关的。

13.1.2 cmake
命令

cmake
命令后跟一个路径
(..)
,用来指出
CMakeList.txt
所在的位置。

由于系统中可能有多套构建环境,我们可以通过
-G
来制定生成哪种工程文件,通


cmake -h
可得到详细信息。
要显示执行构建过程中详细的信息
(
比如为了得到更详细的出错信息
)
,可以在

CMakeList.txt
内加入:


SET( CMAKE_VERBOSE_MAKEFILE on )

或者执行
make


$ make VERBOSE=1

或者


$ export VERBOSE=1


$ make

13.2
例子二

一个源文件的例子一似乎没什么意思,拆成
3
个文件再试试看:


hello.h
头文件

#ifndef DBZHANG_HELLO_

#define DBZHANG_HELLO_

void hello(const char* name);

#endif //DBZHANG_HELLO_


hello.c

#include

#include “hello.h”

void hello(const char * name)

{

printf (“Hello %s!/n”, name);

}


main.c

#include “hello.h”

int main()
{

hello(“World”);

return 0;

}


然后准备好
CMakeList.txt
文件

project(HELLO)

set(SRC_LIST main.c hello.c)

add_executable(hello ${SRC_LIST})

执行
cmake
的过程同上,目录结构

+

|

+— main.c

+— hello.h

+— hello.c

+— CMakeList.txt

|

/–+ build/

 |

 +— hello.exe

例子很简单,没什么可说的。

CMake 完整入门教程(五)

13.3
例子三

接前面的例子,我们将
hello.c
生成一个库,然后再使用会怎么样?

改写一下前面的
CMakeList.txt
文件试试:

project(HELLO)

set(LIB_SRC hello.c)

set(APP_SRC main.c)

add_library(libhello ${LIB_SRC})

add_executable(hello ${APP_SRC})

target_link_libraries(hello libhello)

和前面相比,我们添加了一个新的目标
libhello
,并将其链接进
hello
程序

然后像前面一样,运行
cmake

CMake 完整入门教程(五)

得到

+

|

+— main.c

+— hello.h

+— hello.c

+— CMakeList.txt

|

/–+ build/

|

+— hello.exe

+— libhello.lib

CMake 完整入门教程(五)

里面有一点不爽,对不?


因为我的可执行程序
(add_executable)
占据了
hello
这个名字,所以
add_library
就不

能使用这个名字了


然后,我们取了个
libhello
的名字,这将导致生成的库为
libhello.lib(

liblibhello.a)
,很不爽

CMake 完整入门教程(五)


想生成
hello.lib(

libhello.a)
怎么办
?

添加一行

set_target_properties(libhello PROPERTIES OUTPUT_NAME “hello”)

就可以了

CMake 完整入门教程(五)

CMake 完整入门教程(五)

13.4
例子四

在前面,我们成功地使用了库,可是源代码放在同一个路径下,还是不太正规,怎么办

呢?分开放呗

我们期待是这样一种结构
+

|

+— CMakeList.txt

+–+ src/

| |

| +— main.c

| /— CMakeList.txt

|

+–+ libhello/

| |

| +— hello.h

| +— hello.c

| /— CMakeList.txt

|

/–+ build/

哇,现在需要
3

CMakeList.txt
文件了,每个源文件目录都需要一个,还好,每一个都不

是太复杂


顶层的
CMakeList.txt
文件

project(HELLO)

add_subdirectory(src)

add_subdirectory(libhello)


src
中的
CMakeList.txt
文件

include_directories(${PROJECT_SOURCE_DIR}/libhello)

set(APP_SRC main.c)

add_executable(hello ${APP_SRC})

target_link_libraries(hello libhello)


libhello
中的
CMakeList.txt
文件

set(LIB_SRC hello.c)

add_library(libhello ${LIB_SRC})

set_target_properties(libhello PROPERTIES OUTPUT_NAME “hello”)

恩,和前面一样,建立一个
build
目录,在其内运行
cmake

CMake 完整入门教程(五)

CMake 完整入门教程(五)

然后可以得到


build/src/hello.exe


build/libhello/hello.lib

CMake 完整入门教程(五)

CMake 完整入门教程(五)

回头看看,这次多了点什么,顶层的
CMakeList.txt
文件中使用
add_subdirectory
告诉

cmake
去子目录寻找新的
CMakeList.txt
子文件

CMake 完整入门教程(五)


src

CMakeList.txt
文件中,新增加了
include_directories
,用来指明头文件所在的路

径。

13.5
例子五

前面还是有一点不爽:如果想让可执行文件在
bin
目录,库文件在
lib
目录怎么办?

就像下面显示的一样:

+ build/

|

+–+ bin/

| |

| /— hello.exe

|

/–+ lib/

|

/— hello.lib


一种办法:修改顶级的
CMakeList.txt
文件

project(HELLO)

add_subdirectory(src bin)

add_subdirectory(libhello lib)

不是
build
中的目录默认和源代码中结构一样么,我们可以指定其对应的目录在
build
中的

名字。

CMake 完整入门教程(五)

这样一来:
build/src
就成了
build/bin
了,可是除了
hello.exe
,中间产物也进来了。还不是

我们最想要的。

CMake 完整入门教程(五)

CMake 完整入门教程(五)


另一种方法:不修改顶级的文件,修改其他两个文件

src/CMakeList.txt
文件

include_directories(${PROJECT_SOURCE_DIR}/libhello)

#link_directories(${PROJECT_BINARY_DIR}/lib)

set(APP_SRC main.c)

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

add_executable(hello ${APP_SRC})

target_link_libraries(hello libhello)

libhello/CMakeList.txt
文件

set(LIB_SRC hello.c)

add_library(libhello ${LIB_SRC})

set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

set_target_properties(libhello PROPERTIES OUTPUT_NAME “hello”)

13.6
例子六

在例子三至五中,我们始终用的静态库,那么用动态库应该更酷一点吧。 试着写一下

如果不考虑
windows
下,这个例子应该是很简单的,只需要在上个例子的

libhello/CMakeList.txt
文件中的
add_library
命令中加入一个
SHARED
参数:

add_library(libhello SHARED ${LIB_SRC})

可是,我们既然用
cmake
了,还是兼顾不同的平台吧,于是,事情有点复杂:


修改
hello.h
文件

#ifndef DBZHANG_HELLO_

#define DBZHANG_HELLO_

#if defined _WIN32

#if LIBHELLO_BUILD

#define LIBHELLO_API __declspec(dllexport)

#else

#define LIBHELLO_API __declspec(dllimport)
#endif

#else

#define LIBHELLO_API

#endif

LIBHELLO_API void hello(const char* name);

#endif //DBZHANG_HELLO_


修改
libhello/CMakeList.txt
文件

set(LIB_SRC hello.c)

add_definitions(“-DLIBHELLO_BUILD”)

add_library(libhello SHARED ${LIB_SRC})

set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

set_target_properties(libhello PROPERTIES OUTPUT_NAME “hello”)

恩,剩下来的工作就和原来一样了。

14 CMake
的局限性

世界上没有完美的东西。
CMake
也有其局限性:

– CMake
并不遵守
GNU
规则。这使得
CMake
对一些开源软件的支持不够。例如,

CMake
生成出的工程在
Linux
下不支持
make uninstall

– CMake
和其他编译系统会打架。处理起来不容易。例如,如果不用
Qt
自带的

QMake
,而是用
CMake
去编译
Qt
工程,那是一件费时费力的事情。

– CMake
不会认识开发者在
IDE
中新增加的文件。必须通过修改
CMakeLists.txt
,才

能让
CMake
知道有新的文件。

15
常用网络资源

15.1 CMake
文档

http://www.cmake.org/cmake/help/v2.8.8/cmake.html

15.2 CMake Wiki

http://www.cmake.org/Wiki/CMake
15.3 CMake
入门

http://zh.wikibooks.org/wiki/CMake_%E5%85%A5%E9%96%80

16
附录

引用资源列表如下。时间仓促,难免有遗漏。如果您发现我引用了你的文章请告知。如果

您不希望您的文章被引用也请告知。可以到我的博客留言


http://blog.csdn.net/dbzhang800/article/details/6314073


http://tzc.is-programmer.com/show/476.html


http://blog.csdn.net/vagrxie/article/details/4743484


http://www.cs.swarthmore.edu/~adanner/tips/cmake.php


http://www.cnblogs.com/doujiu/archive/2009/11/04/1596155.html


http://blog.csdn.net/onion_autotest/article/details/7222954


http://www.cnblogs.com/coderfenghc/archive/2013/01/20/2846621.html


http://blog.csdn.net/gubenpeiyuan/article/details/8667279


http://name5566.com/1795.html


http://blog.sina.com.cn/s/blog_9ce5a1b501015avz.html


http://nullget.sourceforge.net/?q=node/94


http://blog.csdn.net/gubenpeiyuan/article/details/8667035


http://blogs.gnome.org/swilmet/2012/09/05/switch-from-cmake-to-autotools/


http://tech.uc.cn/?p=914

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/197bd19c38.html