本文轉自:http://blog.csdn.net/dbzhang800/article/details/6314073python
看來不學習一下cmake是不行了,一點一點來吧,找個最簡單的C程序,慢慢複雜化,試試看:編程
例子一windows |
單個源文件 main.cide |
例子二學習 |
==>分解成多個 main.c hello.h hello.cui |
例子三.net |
==>先生成一個靜態庫,連接該庫blog |
例子四get |
==>將源文件放置到不一樣的目錄it |
例子五 |
==>控制生成的程序和庫所在的目錄 |
例子六 |
==>使用動態庫而不是靜態庫 |
一個經典的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 .. -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 告訴工程生成一個可執行文件。
add_library 則告訴生成一個庫文件。
cmake 命令後跟一個路徑(..),用來指出 CMakeList.txt 所在的位置。
因爲系統中可能有多套構建環境,咱們能夠經過-G來制定生成哪一種工程文件,經過 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
例子很簡單,沒什麼可說的。
接前面的例子,咱們將 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")
恩,剩下來的工做就和原來同樣了。