使用cmake自動構建工程

公司引擎是用cmake根據目標平臺來構建工程的,剛接觸的時候深深體會到cmake的方便:若是目標平臺是windows,它能夠幫你自動構建出vs工程;若是是安卓,自動構建出eclipse工程,若是是IOS,自動構建出xcode工程。想一想之前用vs建工程的時候,若是要引入第三方庫,必需要手動配置第三方庫路徑,若是引入的庫少,那還沒什麼,若是多的話就悲劇了,配個環境都要半天。再想一想之前在linux平臺下手動寫Makefile的時候,若是工程比較小,模塊少還好辦,若是工程大,模塊多,各類寫依賴關係都要讓你抓狂。有了cmake這個工具,咱們徹底能夠靠它來幫咱們構建vs工程,寫Makefile文件。既然cmake構建工程這麼方便,固然須要拿來用,但是對於我這個小白來講,怎麼學呢?果斷谷歌,百度,不過並無找到比較有價值的學習資料,不少人都是貼出了cmake的源文件CMakeLists.txt,而後對文件中的每行都講了下做用。看完這些,我依然不知道爲何要這麼寫,爲何這行要這樣寫,那行要那樣寫?後來才反應過來,cmake官網確定有講啊,雖然是英文的,雖然本身英文比較挫,沒辦法,誰叫沒有其它資料呢(其實官網講的才說最權威的,不要由於是英文就畏懼,看多了其實英文也沒那麼難,不少人自認爲英文不行或者看英文吃力就去網上找各類中文資料,結果可能花費了大量時間在找資料上,到最後啥都沒學到)。本文主要經過講解cmake中一些比較簡單的命令來構建本身的工程,做爲初學者的入門。html

 

一、兩行命令幫你構建輸出hello world的vs工程linux

      爲了自動構建工程,須要在源文件所在的最上層目錄寫一個CMakeLists.txt文件,它是cmake的源文件,也能夠看做是cmake的腳本文件,這個文件描述了cmake怎樣幫咱們自動構建工程。如今咱們有一個hello.cpp文件,須要用這個文件來構建一個vs工程,手動的方法就是打開vs,新建一個工程hello,而後把hello.cpp添加到hello工程裏面。而有了cmake,只須要在CMakeLists.txt寫兩行命令,第一行給本身工程命個名hello,第二行hello工程須要的源文件hello.cpp。而後經過下面幾個步驟,就能夠生成一個vs工程了,生成其它工程的步驟相同,只是在選擇目標工程的時候不一樣。windows

1.1 編寫CMakeLists.txt文件和hello.cpp文件xcode

CMakeLists.txteclipse

project(hello)

add_executable(hello hello.cpp)

hello.cpp函數

複製代碼
#include <stdio.h>

int main (int argc, char *argv[])
{
    printf("hello world!");
    return 0;
}
複製代碼

 

1.2 設置路徑工具

 

 

 

 

 

 

 

 

 

 

 

1.3 設置目標工程爲vs工程學習

1.4  產生vs工程ui

1.5 打開vs工程,編譯運行程序spa

 

2 添加子模塊

      對於比較大的工程來講,包含多個子模塊是很常見的事,由於一般每一個人只是負責他本身的模塊。那麼怎樣將各個模塊加入到主工程中呢?首先咱們須要使用cmake來建立各個子模塊的工程,而後再將這些模塊加入到整個工程中。假設如今咱們有一個子模塊myhello,它提供了一個函數PrintHelloWorld來打印hello world!,主模塊hello調用這個函數來打印。首先咱們在hello.cpp所在目錄建立myhello文件夾,將myhello.cpp和myhello.h放到裏面,而後在這個文件夾中建立CMakeLists.txt。這三個文件的具體內容以下:

myhello/myhello.h:

void PrintHelloWorld();

myhello/myhello.cpp

#include <stdio.h>

void PrintHelloWorld()
{
    printf("hello world!");
}

myhello/CMakeLists.txt

add_library(myhello myhello.cpp)

這個CMakeLists.txt主要是告訴cmake,爲myhello建立一個庫工程。

hello.cpp

複製代碼
#include "myhello/myhello.h"

int main (int argc, char *argv[])
{
    PrintHelloWorld();
    return 0;
}
複製代碼

CMakeLists.txt

複製代碼
cmake_minimum_required(VERSION 3.5)

project(hello)

add_subdirectory(myhello)
set (EXTRA_LIBS ${EXTRA_LIBS} myhello)

add_executable(hello hello.cpp)

target_link_libraries (hello ${EXTRA_LIBS})
複製代碼

       add_subdirectory將myhello子工程加入到主工程,target_link_libraries將子模myhello連接到hello中。而後從新cmake下,打開vs就能夠編譯運行啦。

3 添加可配置的頭文件

      cmake能夠經過可配置的頭文件來產生實際的頭文件,以下面的可配置頭文件hello.h.in,裏面@@引用的變量能夠經過CMakeLists.txt來設置,最後經過cmake來替換hello.h.in文件中的變量並生成hello.h內容。

hello.h.in

#define VERSION_MAJOR @VERSION_MAJOR@
#define VERSION_MINOR @VERSION_MINOR@

CMakeLists.txt

複製代碼
cmake_minimum_required(VERSION 3.5)

project(hello)

include_directories("${PROJECT_BINARY_DIR}")
set(VERSION_MAJOR 1)
set(VERSION_MINOR 0)
configure_file(
    "${PROJECT_SOURCE_DIR}/hello.h.in"
    "${PROJECT_BINARY_DIR}/hello.h"
)

add_subdirectory(myhello)
set (EXTRA_LIBS ${EXTRA_LIBS} myhello)


add_executable(hello hello.cpp)

target_link_libraries (hello ${EXTRA_LIBS})
複製代碼

上面加紅的命令主要用來設置hello.h.in中的兩個變量,而且讓cmake生成hello.h文件。生成的hello.h以下:

hello.h

#define VERSION_MAJOR 1
#define VERSION_MINOR 0

再修改下hello.cpp文件使用這兩個變量,

hello.cpp

複製代碼
#include "myhello/myhello.h"
#include "hello.h"
#include <stdio.h>

int main (int argc, char *argv[])
{
    printf("version:%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
    PrintHelloWorld();
    return 0;
}
複製代碼

打開vs工程,編譯運行輸出者兩個變量的值。這樣就能夠經過在CMakeLists.txt中設置變量的內容來動態修改.h文件,增長了代碼的靈活性。

 

4 檢測系統是否有支持工程須要的函數

      對於跨平臺的工程來講,檢查系統是否支持某些特性是頗有必要的,這樣程序中就能夠經過系統的特性來選擇具體執行哪些代碼。其中檢查是否支持某些函數是咱們常常要作的事情,如epoll函數,可能有的linux系統就不支持,對於不支持的系統咱們只能用poll來替代等。在cmake中檢查系統是否支持某個函數也很簡單,先包含一個CheckFunctionExists庫,而後使用check_function_exists來判斷就好了。

CMakeLists.txt

複製代碼
cmake_minimum_required(VERSION 3.5)

project(hello)

include (CheckFunctionExists)
check_function_exists (printf HAVE_PRINTF)

include_directories("${PROJECT_BINARY_DIR}")
set(VERSION_MAJOR 1)
set(VERSION_MINOR 0)
configure_file(
    "${PROJECT_SOURCE_DIR}/hello.h.in"
    "${PROJECT_BINARY_DIR}/hello.h"
)

add_subdirectory(myhello)
set (EXTRA_LIBS ${EXTRA_LIBS} myhello)


add_executable(hello hello.cpp)

target_link_libraries (hello ${EXTRA_LIBS})
複製代碼

在配置的頭文件hello.h.in中加入#cmakedefine HAVE_PRINTF,這樣若是系統中有printf函數,最終生成的hello.h中會定義HAVE_PRINTF這個宏,不然不會生成這個宏,在hello.cpp文件中能夠根據這個宏來是否認義來判斷是否應該使用printf函數。

hello.h.in

#define VERSION_MAJOR @VERSION_MAJOR@
#define VERSION_MINOR @VERSION_MINOR@

#cmakedefine HAVE_PRINTF

hello.cpp

複製代碼
#include "myhello/myhello.h"
#include "hello.h"
#include <stdio.h>

int main (int argc, char *argv[])
{
#ifdef HAVE_PRINTF
    printf("version:%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
#endif
    PrintHelloWorld();
    return 0;
}
複製代碼

運行結果:

 

5 配置可選項

有時候代碼可能包含了全部平臺的模塊代碼,可是對於特定的目標平臺,只須要配置該平臺須要模塊的代碼,而不須要配置其它平臺模塊的代碼。這種需求能夠經過cmake的配置可選項來完成,配置可選項就是cmake在生成工程的時候提示你一些選項,根據你的選項來具體選擇須要添加到工程中的模塊代碼。例如我如今須要提升是否使用myhello模塊的選項,能夠在CMakeLists.txt中加option命令來實現,代碼以下:

複製代碼
cmake_minimum_required(VERSION 3.5)

project(hello)

include (CheckFunctionExists)
check_function_exists (printf HAVE_PRINTF)

include_directories("${PROJECT_BINARY_DIR}")
set(VERSION_MAJOR 1)
set(VERSION_MINOR 0)

option (USE_MYHELLO 
        "Use myhello" ON) 
        
configure_file(
    "${PROJECT_SOURCE_DIR}/hello.h.in"
    "${PROJECT_BINARY_DIR}/hello.h"
)

add_subdirectory(myhello)
set (EXTRA_LIBS ${EXTRA_LIBS} myhello)


add_executable(hello hello.cpp)

target_link_libraries (hello ${EXTRA_LIBS})
複製代碼

而且在hello.h.in中添加由cmake根據選項來定義USE_MYHELLO宏。

#define VERSION_MAJOR @VERSION_MAJOR@
#define VERSION_MINOR @VERSION_MINOR@

#cmakedefine HAVE_PRINTF
#cmakedefine USE_MYHELLO

這樣在運行cmake的時候,會提示咱們一些選項來進行選擇:

經過USE_MYHELLO是否被選擇,cmake來肯定是否要在hello.h中定義USE_MYHELLO宏,最終咱們能夠在hello.cpp中判斷USE_MYHELLO宏是否認義來是否使用myhello模塊中的PrintHelloWorld函數。

hello.cpp

複製代碼
#include "myhello/myhello.h"
#include "hello.h"
#include <stdio.h>

int main (int argc, char *argv[])
{
#ifdef HAVE_PRINTF
    printf("version:%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
#endif
#ifdef USE_MYHELLO
    PrintHelloWorld();
#else
    printf("xx hello world!");
#endif
    return 0;
}
複製代碼

最後經過選中或者不選中USE_MYHELLO選擇,獲得的結果會不一樣。

選中結果

沒選中結果:

 

6 總結

      本文主要介紹了下cmake的比較經常使用的一些命令:project、include、include_directories、set、option、configure_file、add_subdirectory、add_executable、target_link_libraries、add_library,算是一個入門吧。須要用好cmake,熟悉cmake的命令和多寫cmake腳本是必須的,具體每一個命令的介紹看以參考官方文檔:https://cmake.org/cmake/help/v3.5/manual/cmake-commands.7.html,腳步的編寫語法能夠參考官網文檔:https://cmake.org/cmake/help/v3.5/manual/cmake-language.7.html。之後大點的工程建立徹底能夠交給cmake來完成,同時也是熟悉cmake的過程。

 

參考:https://cmake.org/cmake/help/v3.5/index.html

相關文章
相關標籤/搜索