cmake用法(转)
转自:http://blog.csdn.net/dbzhang800/article/details/6314073
新工作中使用到了cmake,所以找点资料学习一下,这篇讲的确实不错,转过来保存一下,另外这一篇页不错的:http://www.ibm.com/developerworks/cn/linux/l-cn-cmake/
看来不学习一下cmake是不行了,一点一点来吧,找个最简单的C程序,慢慢复杂化,试试看:
例子一 |
单个源文件 main.c |
例子二 |
==>分解成多个 main.c hello.h hello.c |
例子三 |
==>先生成一个静态库,链接该库 |
例子四 |
==>将源文件放置到不同的目录 |
例子五 |
==>控制生成的程序和库所在的目录 |
例子六 |
==>使用动态库而不是静态库 |
例子一
一个经典的C程序,如何用cmake来进行构建程序呢?
//main.c
#include <stdio.h>
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"
nmake
或者
cmake .. -G"MinGW Makefiles"
make
即可生成可执行程序 hello(.exe)
目录结构
+
|
+--- main.c
+--- CMakeList.txt
|
/--+ build/
|
+--- hello.exe
cmake 真的不太好用哈,使用cmake的过程,本身也就是一个编程的过程,只有多练才行。
我们先看看:前面提到的这些都是什么呢?
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 文件中,命令名字是不区分大小写的,而参数和变量是大小写相关的。
cmake命令
cmake 命令后跟一个路径(..),用来指出 CMakeList.txt 所在的位置。
由于系统中可能有多套构建环境,我们可以通过-G来制定生成哪种工程文件,通过 cmake -h 可得到详细信息。
要显示执行构建过程中详细的信息(比如为了得到更详细的出错信息),可以在CMakeList.txt内加入:
- SET( CMAKE_VERBOSE_MAKEFILE on )
或者执行make时
- $ make VERBOSE=1
或者
- $ export VERBOSE=1
- $ make
例子二
一个源文件的例子一似乎没什么意思,拆成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的过程同上,目录结构
+
|
+--- main.c
+--- hello.h
+--- hello.c
+--- CMakeList.txt
|
/--+ build/
|
+--- hello.exe
例子很简单,没什么可说的。
例子三
接前面的例子,我们将 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,得到
+
|
+--- main.c
+--- hello.h
+--- hello.c
+--- CMakeList.txt
|
/--+ build/
|
+--- hello.exe
+--- libhello.lib
里面有一点不爽,对不?
- 因为我的可执行程序(add_executable)占据了 hello 这个名字,所以 add_library 就不能使用这个名字了
- 然后,我们去了个libhello 的名字,这将导致生成的库为 libhello.lib(或 liblibhello.a),很不爽
- 想生成 hello.lib(或libhello.a) 怎么办?
添加一行
set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
就可以了
例子四
在前面,我们成功地使用了库,可是源代码放在同一个路径下,还是不太正规,怎么办呢?分开放呗
我们期待是这样一种结构
+
|
+--- 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,然后可以得到
- build/src/hello.exe
- build/libhello/hello.lib
回头看看,这次多了点什么,顶层的 CMakeList.txt 文件中使用 add_subdirectory 告诉cmake去子目录寻找新的CMakeList.txt 子文件
在 src 的 CMakeList.txt 文件中,新增加了include_directories,用来指明头文件所在的路径。
例子五
前面还是有一点不爽:如果想让可执行文件在 bin 目录,库文件在 lib 目录怎么办?
就像下面显示的一样:
+ build/
|
+--+ bin/
| |
| /--- hello.exe
|
/--+ lib/
|
/--- hello.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")
例子六
在例子三至五中,我们始终用的静态库,那么用动态库应该更酷一点吧。 试着写一下
如果不考虑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")
恩,剩下来的工作就和原来一样了。
cmake用法(转)的更多相关文章
- Cmake用法
目录 1,Cmake introduce 1.1 常用的目录结构 2,CMakeLists.txt文件的写法 Cmake 常用命令 Scripting Commands set include Pro ...
- CMake 用法导览
Preface : 本文是CMake官方文档CMake Tutorial (http://www.cmake.org/cmake/help/cmake_tutorial.html) 的翻译.通过一个样 ...
- cmake用法及常用命令总结(全)
CMakeLists.txt 的语法比较简单,由命令.注释和空格组成,其中命令是不区分大小写的.指令是大小写无关的,参数和变量是大小写相关的.但推荐全部使用大写指令.符号 # 后面的内容被认为是注释. ...
- 自己常用的CMake用法总结
欢迎指正 CMake : A.download : https://cmake.org/download/ B.tutorial: https://cmake.org/cmake-tutorial/ ...
- cmake用法及常用命令总结
CMakeLists.txt 的语法比较简单,由命令.注释和空格组成,其中命令是不区分大小写的.指令是大小写无关的,参数和变量是大小写相关的.但推荐全部使用大写指令.符号 # 后面的内容被认为是注释. ...
- CMake入门实战
本文用来记录基本的Cmake用法,以一个实例,讲解如何通过cmake构建一个一个基本的工程,文件的目录如下: 说明: bin文件夹下的debug和release分别存放编译输出的文件和相关依赖的动态库 ...
- VS2015--win32project配置的一些想法之cmake
近期两天都在配置一个win32项目.为了实现跨平台,写底层代码的人仅仅build了安卓和ios的工程,没有build win32项目. 因为对一些库不是非常了解.配置起来非常困难,心力交瘁. 为了实现 ...
- cmake 的简单使用示例
https://www.zybuluo.com/khan-lau/note/254724 CMake 用法导览 Preface : 本文是CMake官方文档CMake Tutorial (http:/ ...
- CMake技术总结
在做算法部署的过程中,我们一般都是用C++开发,主要原因是C++的高效性,而构建维护一个大型C++工程的过程中,如何管理不同子模块之间的依赖.外部依赖库.头文件和源文件如何隔离.编译的时候又该如何相互 ...
随机推荐
- java List 简单使用
Student类 class Student{ String name; String pwd; public Student(){} public Student(String name, Stri ...
- 树形DP +01背包(HDU 1011)
题意:有n个房间,有n-1条道路连接着n个房间,每个房间都有若干个野怪和一定的能量值,有m个士兵从1房间入口进去,到达每个房间必须要留下若干士兵杀死所有的野怪,然后其他人继续走,(一个士兵可以杀死20 ...
- 树形DP(统计直径的条数 HDU3534)
分析:首先树形dp(dfs计算出每个点为根节点的子树的最长距离和次长距离),然后找出L=dis[u][0]+dis[u][1]最长的那个点u,然后在以u为根节点dfs,统计长度为L的条数:具体做法:把 ...
- 2013年各大小IT公司待遇
2013年各大小IT公司待遇(初版 摘自好网)本人西电硕士,根据今年找工作的情况以及身边同学的汇总,总结各大公司的待遇如下,吐血奉献给各位学弟学妹,公司比较全,你想去的公司不在这里面,基本上是无名 ...
- Android DatePickerDialog TimepickerDialog
package com.example.myact5; import java.util.Calendar; import android.app.DatePickerDialog; import a ...
- full_case & parallel_case
case中的full_case与parallel_case讨论: 1)术语介绍: 整个case模块叫做:case_statement,注释部分叫做case_statement_header case ...
- ASP.NET MVC (一)
工作清闲好一段时间了,趁这段时间弄了弄PHP,做个了简单的MVC网页.玩了玩Android,弄了个拨号器,发短信的,嘿嘿,最满意的还是两天弄了个数独游戏.不务正业一个多月了,也该磨磨刀,接下来一段时间 ...
- js调用后台方法(如果你能容忍执行的后台方法变成一个常量)
最近一直在做一个电话拨号的系统,系统不大,但是做的时间有点长了.其中用到了一个技术:js调用后台方法.解决这个问题花了不少时间,现如今仍然还有些不明白的地方,今天跟大家分享一下.真正明白的同学欢迎指正 ...
- seo之google rich-snippets丰富网页摘要结构化数据(微数据)实例代码
seo之google rich-snippets丰富网页摘要结构化数据(微数据)实例代码 网页摘要是搜索引擎搜索结果下的几行字,用户能通过网页摘要迅速了解到网页的大概内容,传统的摘要是纯文字摘要,而结 ...
- JVM学习笔记(三)------内存管理和垃圾回收【转】
转自:http://blog.csdn.net/cutesource/article/details/5906705 版权声明:本文为博主原创文章,未经博主允许不得转载. JVM内存组成结构 JVM栈 ...