cmake和CMakeLists.txt的学习

原文地址: https://blog.csdn.net/yanchuang1/article/details/69683236

想了很久,不知道从哪开始,今天决定从编写CMakeLists.txt开始吧,以前接触了皮毛,但是今天想更深刻的掌握cmake的东西,这样对于Linux下的运行提供便利,其次是编写makefile感觉有点难,内容多,而cmake简单,语法基本不多。

首先cmake到底是什么呢?
百度百科的介绍:CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似UNIX下的automake。只是 CMake 的组态档取名为 CMakeLists.txt。Cmake 并不直接建构出最终的软件,而是产生标准的建构档(如 Unix 的 Makefile 或 Windows Visual C++ 的 projects/workspaces),然后再依一般的建构方式使用。这使得熟悉某个集成开发环境(IDE)的开发者可以用标准的方式建构他的软件,这种可以使用各平台的原生建构系统的能力是 CMake 和 SCons 等其他类似系统的区别之处。

cmake的使用
cmake的所有语句都写在一个CMakeLists.txt的文件中,CMakeLists.txt文件确定后,直接使用cmake命令进行运行,但是这个命令要指向CMakeLists.txt所在的目录,cmake之后就会产生我们想要的makefile文件。
引用cmake的使用方法这篇文章http://www.cnblogs.com/lyq105/archive/2010/12/03/1895067.html

cmake执行的流程:

$> ccmake directory
$> cmake directory
$> make

其中directory为CMakeList.txt所在目录;

  1. 第一条语句用于配置编译选项,如VTK_DIR目录 ,一般这一步不需要配置,直接执行第二条语句即可,但当出现错误时,这里就需要认为配置了,这一步才真正派上用场;
  2. 第二条命令用于根据CMakeLists.txt生成Makefile文件;
  3. 第三条命令用于执行Makefile文件,编译程序,生成可执行文件;

cmake的执行流程很简单,我们的重点是如何编写CMakeLists.txt文件呢,我们通过例子来学习cmake的语法。

例子从这篇文章中学习https://www.jianshu.com/p/f3da16a89f39,大致如下:

1、一个最简单的例子:

输出hello world

// main.c
#include <stdio.h>
int main()
{
printf("hello world");
return 0;
}

CMakeLists.txt文件:

project(HELLO)
set(SRC_LIST main.c)
add_executable(hello ${SRC_LIST}))

就这几句,是不是很简单,由于执行cmake的时候会产生很多中间文件,我们采用out of source(外部编译)方式进行构建,我们建立一个build目录储存中间执行过程。


例子目录下的文件,进入build目录,执行cmake ..,cmake执行指向上一个目录,也就是存储CMakeLists.txt的目录,完成后就会看到makefile文件,make过后就会看到执行文件。
第一个行project不是强制性的,最好加上,这会引入两个变量:

HELLO_BINARY_DIR, HELLO_SOURCE_DIR

同时也会定义两个等价的变量:

PROJECT_BINARY_DIR, PROJECT_SOURCE_DIR

外部编译要时刻区分这两个变量对应的目录:
可以通过message进行输出

message(${PROJECT_SOURCE_DIR})

set 命令用来设置变量:

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

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

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

hello.h 头文件

#ifndef DBZHANG_HELLO_
#define DBZHANG_HELLO_


void hello(const char* name);


#endif //DBZHANG_HELLO_

hello.c

#include <stdio.h>
#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的过程同上

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程序

因为我的可执行程序(add_executable)占据了 hello 这个名字,所以 add_library 就不能使用这个名字了
然后,我们去了个libhello 的名字,这将导致生成的库为 libhello.lib(或 liblibhello.a),很不爽
想生成 hello.lib(或libhello.a) 怎么办?

添加一行

set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")

就可以了

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

分开放呗,现在需要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,然后可以得到
build/src/hello.exe
build/libhello/hello.lib
回头看看,这次多了点什么,顶层的 CMakeList.txt 文件中使用 add_subdirectory 告诉cmake去子目录寻找新的CMakeList.txt 子文件
在 src 的 CMakeList.txt 文件中,新增加了include_directories,用来指明头文件所在的路径。

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

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

project(HELLO)
add_subdirectory(src bin)
add_subdirectory(libhello lib)

不是build中的目录默认和源代码中结构一样么,我们可以指定其对应的目录在build中的名字。
这样一来:build/src 就成了 build/bin 了,可是除了 hello.exe,中间产物也进来了。还不是我们最想要的。

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

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")

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

如果不考虑windows下,这个例子应该是很简单的,只需要在上个例子的 libhello/CMakeList.txt 文件中的
add_library命令中加入一个SHARED参数:

add_library(libhello SHARED ${LIB_SRC})

一下午才搞了这点东西,至于多个平台的兼顾,以后有时间再讨论。

这几个例子进行演练熟悉,相信可以解决多大数的项目需要。
在后面我也进行了kcp开源项目进行编译成静态库,并链接生成可执行文件:
目录结构如下:


kcp文件放着源码,生成静态库libkcp
kcp里面的CMakeLists.txt

外面主目录下的CMakeLists.txt

每次都会提示cmake_minimum_required,版本要求,建议后面还是把它填上。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容