【cmake系列使用教程】
這個系列的文章翻譯自官方cmake教程:cmake tutorial。
示例程式地址:github.com/rangaofei/t…
不會僅僅停留在官方教程。本人作為一個安卓開發者,實在是沒有linux c程式開發經驗,望大佬們海涵。教程是在macos下完成,大部分linux我也測試過,有特殊說明的我會標註出來。本教程基於cmake-3.10.2,同時認為你已經安裝好cmake。
cmake中有兩個相似的關鍵字,macro和function。這兩個都是建立一段有名字的程式碼稍後可以呼叫,還可以傳引數。
macro巨集定義與function函式的相同點
macro形式如下:
macro(<name> [arg1 [arg2 [arg3 ...]]])
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
endmacro(<name>)
複製程式碼
function形式如下:
function(<name> [arg1 [arg2 [arg3 ...]]])
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
function(<name>)
複製程式碼
定義一個名稱為name的巨集(函式),arg1...是傳入的引數。我們除了可以用${arg1}
來引用變數以外,系統為我們提供了一些特殊的變數:
變數 | 說明 |
---|---|
ARGV# | #是一個下標,0指向第一個引數,累加 |
ARGV | 所有的定義時要求傳入的引數 |
ARGN | 定義時要求傳入的引數以外的引數,比如定義巨集(函式)時,要求輸入1個,書記輸入了3個,則剩下的兩個會以陣列形式儲存在ARGN中 |
ARGC | 傳入的實際引數的個數,也就是呼叫函式是傳入的引數個數 |
macro巨集定義與function函式的不同點
巨集的ARGN、ARGV等引數不是通常CMake意義上的變數。 它們是字串替換,很像C前處理器對巨集的處理。 因此,如下命令是錯誤的:
if(ARGV1) # ARGV1 is not a variable
if(DEFINED ARGV2) # ARGV2 is not a variable
if(ARGC GREATER 2) # ARGC is not a variable
foreach(loop_var IN LISTS ARGN) # ARGN is not a variable
複製程式碼
正確寫法如下:
if(${ARGV1})
if(DEFINED ${ARGV2})
if(${ARGC} GREATER 2)
foreach(loop_var IN LISTS ${ARGN})
or
set(list_var "${ARGN}")
foreach(loop_var IN LISTS list_var)
複製程式碼
一個簡單的例子
macro(FOO arg1 arg2 arg3)
message(STATUS "this is arg1:${arg1},ARGV0=${ARGV0}")
message(STATUS "this is arg2:${arg2},ARGV1=${ARGV1}")
message(STATUS "this is arg3:${arg3},ARGV2=${ARGV2}")
message(STATUS "this is argc:${ARGC}")
message(STATUS "this is args:${ARGV},ARGN=${ARGN}")
if(arg1 STREQUAL one)
message(STATUS "this is arg1")
endif()
if(ARGV2 STREQUAL "two")
message(STATUS "this is arg2")
endif()
set(${arg1} nine)
message(STATUS "after set arg1=${${arg1}}")
endmacro(FOO)
function(BAR arg1)
message(STATUS "this is arg1:${arg1},ARGV0=${ARGV0}")
message(STATUS "this is argn:${ARGN}")
if(arg1 STREQUAL first)
message(STATUS "this is first")
endif()
set(arg1 ten)
message(STATUS "after set arg1=${arg1}")
endfunction(BAR arg1)
set(p1 one)
set(p2 two)
set(p3 three)
set(p4 four)
set(p5 five)
set(p6 first)
set(p7 second)
FOO(${p1} ${p2} ${p3} ${p4} ${p5})
BAR(${p6} ${p7})
message(STATUS "after bar p6=${p6}")
複製程式碼
輸出結果如下:
-- this is arg1:one,ARGV0=one
-- this is arg2:two,ARGV1=two
-- this is arg3:three,ARGV2=three
-- this is argc:5
-- this is args:one;two;three;four;five,ARGN=four;five
-- after set arg1=nine
-- this is arg1:first,ARGV0=first
-- this is argn:second
-- this is first
-- after set arg1=ten
-- after bar p6=first
複製程式碼
接下來看一個讓我們蛋都能疼碎了的例子,簡直不想用cmake:
macro(_bar)
foreach(arg IN LISTS ARGN)
message(STATUS "this is in macro ${arg}")
endforeach()
endmacro()
function(_foo)
foreach(arg IN LISTS ARGN)
message(STATUS "this in function is ${arg}")
endforeach()
_bar(x y z)
endfunction()
_foo(a b c)
複製程式碼
看一下輸出:
-- this in function is a
-- this in function is b
-- this in function is c
-- this is in macro a
-- this is in macro b
-- this is in macro c
複製程式碼
就是這麼蛋疼,我們傳給了_bar(x y z)
,結果列印出來的是a b c
,那我們把第二行的foreach改成foreach(arg IN LISTS ${ARGN})
,
看一下結果:
-- this in function is a
-- this in function is b
-- this in function is c
複製程式碼
沒有輸出_bar
中的資訊。為啥?因為這個ARGN的作用域是在function中的,也就是_foo
函式中的那個ARGN。有興趣的話可以試試在macro中呼叫function。