标签:
看来不学习一下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文件):
project(HELLO) set(SRC_LIST main.c) add_executable(hello ${SRC_LIST})
然后,建立一个随意文件夹(比方本文件夹下创建一个build子文件夹),在该build文件夹下调用cmake
cmake .. -G"NMake Makefiles" nmake
或者
cmake .. -G"MinGW Makefiles" make
就可以生成可运行程序 hello(.exe)
文件夹结构
+ | +--- main.c +--- CMakeList.txt | /--+ build/ | +--- hello.exe
cmake 真的不太好用哈,使用cmake的过程,本身也就是一个编程的过程,仅仅有多练才行。
我们先看看:前面提到的这些都是什么呢?
第一行 project 不是强制性的,但最好始终都加上。这一行会引入两个变量
同一时候,cmake自己主动定义了两个等价的变量
PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR
由于是out-of-source方式构建,所以我们要时刻区分这两个变量相应的文件夹
能够通过message来输出变量的值
message(${PROJECT_SOURCE_DIR})
set 命令用来设置变量
add_exectuable 告诉project生成一个可运行文件。
add_library 则告诉生成一个库文件。
cmake 命令后跟一个路径(..),用来指出 CMakeList.txt 所在的位置。
因为系统中可能有多套构建环境,我们能够通过-G来制定生成哪种project文件,通过 cmake -h 可得到具体信息。
要显示运行构建过程中具体的信息(比方为了得到更具体的出错信息),能够在CMakeList.txt内增加:
或者运行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() { 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
样例非常easy,没什么可说的。
接前面的样例,我们将 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下,这个样例应该是非常easy的,仅仅须要在上个样例的 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")
恩,剩下来的工作就和原来一样了。
标签:
原文地址:http://www.cnblogs.com/mengfanrong/p/4184796.html