cmake .. 父目录(两个点)编程
一个经典的C程序,如何用cmake来进行构建程序呢?windows
//main.c #include <stdio.h>
int main(void) { printf("Hello World!/n"); return 0; }
编写一个 CMakeList.txt 文件(可看作cmake的工程文件):ui
project(HELLO) set(SRC_LIST main.c) add_executable(hello ${SRC_LIST})
而后,创建一个任意目录(好比本目录下建立一个build子目录),在该build目录下调用cmakespa
cmake .. -G"NMake Makefiles" nmake
或者code
cmake .. -G"MinGW Makefiles" make
便可生成可执行程序 hello(.exe)blog
目录结构get
+ | +--- main.c +--- CMakeList.txt | /--+ build/ | +--- hello.exe
cmake 真的不太好用哈,使用cmake的过程,自己也就是一个编程的过程,只有多练才行。it
咱们先看看:前面提到的这些都是什么呢?io
第一行 project 不是强制性的,但最好始终都加上。这一行会引入两个变量table
同时,cmake自动定义了两个等价的变量
PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR
由于是out-of-source方式构建,因此咱们要时刻区分这两个变量对应的目录
能够经过message来输出变量的值
message(${PROJECT_SOURCE_DIR})
set 命令用来设置变量
add_exectuable 告诉工程生成一个可执行文件。
add_library 则告诉生成一个库文件。
cmake 命令后跟一个路径(..),用来指出 CMakeList.txt 所在的位置。
因为系统中可能有多套构建环境,咱们能够经过-G来制定生成哪一种工程文件,经过 cmake -h 可获得详细信息。
要显示执行构建过程当中详细的信息(好比为了获得更详细的出错信息),能够在CMakeList.txt内加入:SET( CMAKE_VERBOSE_MAKEFILE on )
或者执行make时
$ make VERBOSE=1
或者
$ export VERBOSE=1 $ make
一个源文件的例子一彷佛没什么意思,拆成3个文件再试试看:
#ifndef DBZHANG_HELLO_ #define DBZHANG_HELLO_
void hello(const char* name);
#endif //DBZHANG_HELLO_
#include <stdio.h> #include "hello.h" void hello(const char * name) { printf ("Hello %s!/n", name); }
#include "hello.h" int main(void) { hello("World"); return 0; }
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
里面有一点不爽,对不?
添加一行
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 文件了,每一个源文件目录都须要一个,还好,每个都不是太复杂
project(HELLO)
add_subdirectory(src)
add_subdirectory(libhello)
include_directories(${PROJECT_SOURCE_DIR}/libhello) set(APP_SRC main.c) add_executable(hello ${APP_SRC}) target_link_libraries(hello libhello)
set(LIB_SRC hello.c) add_library(libhello ${LIB_SRC}) set_target_properties(libhello PROPERTIES OUTPUT_NAME "hello")
恩,和前面同样,创建一个build目录,在其内运行cmake,而后能够获得
回头看看,此次多了点什么,顶层的 CMakeList.txt 文件中使用 add_subdirectory 告诉cmake去子目录寻找新的CMakeList.txt 子文件
在 src 的 CMakeList.txt 文件中,新增长了include_directories,用来指明头文件所在的路径。
前面仍是有一点不爽:若是想让可执行文件在 bin 目录,库文件在 lib 目录怎么办?
就像下面显示的同样:
+ build/
|
+--+ bin/
| |
| /--- hello.exe
|
/--+ lib/
|
/--- hello.lib
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了,仍是兼顾不一样的平台吧,因而,事情有点复杂:
#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_
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 ..
make