code style

2016年10月21日 星期五

CMake筆記(5) - 將建置資訊分類

CMake的build有2種:
In-source build:build的資料夾和source code在同一個資料夾,不推薦
out-of-source build:build的資料夾和source code在不同個資料夾,推薦,source code裡不會有cmake產生的cache,可單獨打包發佈。 

注意事項: 在執行 Out-of-source build 之前必須先確定所指定的源碼根目錄是否乾淨,若是該目錄下含有前次留下的 CMakeCache.txt 仍會執行 In-source build。 

開始前我們先清除之前CMake產生的cache,而因為CMake似乎沒有相關命令清除cache,我們自已寫一個簡單的script來清除:
#!/bin/bash
# usage: bash clean_cmake_cache.sh
echo "remove cmake cache...."
if [ -f ./cmake_install.cmake ]; then
rm ./cmake_install.cmake
fi
if [ -d ./CMakeFiles ]; then
rm -r ./CMakeFiles
fi
if [ -f ./Makefile ]; then
rm ./Makefile
fi
if [ -f ./CMakeCache.txt ]; then
rm ./CMakeCache.txt
fi

out-of-source build:
我們將資料夾整理一下:
src:放source code
lib:放library的source code
lib/include:放library的header file
bin:放build 好的執行檔
build:放build好的lib檔
Project資料夾:放CMake產生 的cache


















CMakeLists.txt:
cmake_minimum_required (VERSION 2.6)
project (Test)

include_directories(lib/include)
set(TEST_SOURCES src/main.cxx)
set(LIB_SOURCES lib/lib.cxx)
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/build)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
 

add_library(MyLib ${LIB_SOURCES})
add_executable(TestRun ${TEST_SOURCES})
target_link_libraries(TestRun MyLib)


路徑資訊:
CMake 提供了幾個變數讓使用者在撰寫 CMakeLists 時取得路徑資訊。
CMAKE_SOURCE_DIR
內容為 source tree 根目錄的完整路徑,也就是 CMake 開始建置過程的進入點。
CMAKE_BINARY_DIR
內容為 binary tree 根目錄的完整路徑,在 in-source build 的時候值與 CMAKE_SOURCE_DIR 相同。
PROJECT_SOURCE_DIR
目前所屬專案的原始碼根目錄,即內含 project() 指令的 CMakeLists 所在資料夾。前面的例子沒有階層之分,所以 PROJECT_SOURCE_DIR 和 CMAKE_SOURCE_DIR 相同;更複雜的專案會包含數個子專案,子專案下面還可能會有多個資料夾,PROJECT_SOURCE_DIR 內容為目前正在處理中的專案最上層目錄。
PROJECT_BINARY_DIR
目前所屬專案的建置根目錄,專案意義同上。在 in-source build 時和 PROJECT_SOURCE_DIR 相同。
CMAKE_CURRENT_SOURCE_DIR
目前正在處理的 CMakeLists.txt 所在位置。
CMAKE_CURRENT_BINARY_DIR
目前正在處理的 CMakeLists.txt 對應的建置資料夾位置。當然,在 in-source build 時和 CMAKE_CURRENT_SOURCE_DIR 相同。
這裡要注意的是,CMake 中都使用絕對路徑來表示檔案位置。

CMake筆記(3) - 流程控制

條件敘述:
CMake的條件敘述為 if、elseif、else、endif。
# 當 expr 值為下列其中之一時,執行 command1:
#    ON, 1, YES, TRUE, Y
# 當 expr 值為下列其中之一時,執行 command2:
#    OFF, 0, NO, FALSE, N, NOTFOUND, *-NOTFOUND, IGNORE 

if(expr)
    command1(arg)
else(expr)
    command2(arg)
endif(expr) 

else中的expr可不填,這樣比較不會有語意上的誤會,例如:
if(WIN32)
    command1(arg)
else(WIN32)
    command2(arg)
endif(expr) 
以為WIN32為真時執行command2...

在條件式當中變數即使不加 ${},if 也會先嘗試解釋成變數。
# 下面兩行意義相同
if (foo)
if (${foo})
實務上個人覺得還是加比較好,可從語法上就得知這個是變數,不會誤以為是個字串。

 迴圈:
CMake 的迴圈有兩種:
foreach ... endforeach
while ... endwhile
set(V  alpha beta gamma)
message(${V})

foreach(i  ${V})
    message(${i})
endforeach() 
Output:
alphabetagamma
alpha
beta
gamma
函數與巨集: CMake 有兩種設計子程序的方式:
function ... endfunction
macro ... endmacro
主要的差別在於 function 會建立 local的變數,而 macro 則會影響 global 變數。
# 定義名為 print1 的 macro 

macro(print1 MESSAGE)
    set(k ${MESSAGE})
    message(${MESSAGE})
endmacro(print1)

# 定義名為 print2 的 function
function(print2 MESSAGE)
    set(k ${MESSAGE})
    message(${MESSAGE})
endfunction(print2) 

print1("from print1")
print2("from print2")
message("k=${k}")

輸出結果為
from print1
from print2
k="from print1"

CMake筆記(2) - 基本語法

CMake基本語法
基本觀念,command不分大小寫,但參數和變數是有分大小寫的。
輸出訊息
message(helloworld)

變數
使用set來設定變數值,使用${}符號來get 變數值
set(var hello)
message(${var})

字串與串列
字串(string)是 CMake 當中的基本的資料型態,將字串用空白或分號分隔則表示串列
set(foo this is a list)
set(foo this;is;a;list)
在字串當中需要空白、換行、分號等字元時,可以使用 " " 將文字內容框住,如此就會被解釋成同一個字串
set(a alpha beta gamma)

set(b "alpha beta gamma")

set(c "alpha
beta
gamma"
)

message("a = ${a}")
message("b = ${b}")
message("c = ${c}")

a 等於一個串列,內容為 alpha、beta、gamma 三個字串
b 等於一個字串,內容為 alpha beta gamma
c 等於一個字串,內容為以換行為分隔的 alpha beta gamma

跳脫字元Escapes
CMake 大致上相容 C 語言當中的 Escape Sequence,如 \t \n 等等。如欲表示 CMake 當中的特殊字元時也可用 \ 標記
set(bar "alpha beta gamma")
message("\${bar}: ${bar}")

上面程式碼輸出
${bar}: alpha beta gamma

布林值:
在 CMake 當中有些字串被賦予了布林值的意義,大小寫差異會被忽略:
以下這些會被視為 FALSE:
  • OFF
  • FALSE
  • N
  • NO
  • 0
  • "" (空字串)
  • 沒被指派值的變數
  • NOTFOUND
  • 任何結尾是 -NOTFOUND 的字串

以下這些會被視為 TRUE:
  • ON
  • TRUE
  • Y
  • YE
  • YES
  • 1
  • 其他不歸類為 FALSE 的字串

數字計算:
 CMake 當中並沒有提供直接的數學運算子,所有的符號組合最終都會形成字串或串列。數學計算必須透過 math 指令解釋:
math(EXPR var "1 + 2 * 3")
message("var = ${var}")
輸出結果為7

2016年10月20日 星期四

CMake筆記(1)

CMake

語法簡介
由指令(command)和註解所組成,所有的空白、換行、tab 都沒有特殊作用,僅為語彙元素的區隔。
#為註解用。

指令為指令名稱加上小括號,括號內可以有零或若干個參數,指令則依照出現在 CMakeLists 當中的順序執行。所有指令名稱大小寫都一視同仁,例如 Command、COMMAND 皆視為同一個指令。


在撰寫 CMakeLists 時可以使用變數(Variable)儲存資料,嚴格說起來 CMake 只有字串和串列兩種資料形態,數值和布林值本質上只是帶有特殊意義的字串。變數大小寫不同視為相異,內建的變數都必須要全大寫。

首先新建一個CMakeLists.txt,並輸入下面內容:

cmake_minimum_required (VERSION 2.6)
project (CMake1)
add_executable(TestRun main.cxx)

第一行是檢查cmake version,第二行是project name ,主要作用的第三行,會產生makefile,之後下make來compiler main.cxx產生一個TestRun的執行檔。

新建main.cxx,並輸入下面內容:

#include 

int main(int argc, char **argv) {
    std::cout << "Hello, world!" << std::endl;
    return 0;
}

在當前console下輸入cmake .,成功後再輸入make,如無錯誤的話,可看到TestRun的執行檔生成。