1. 程式人生 > >CMakeLists.txt 介紹

CMakeLists.txt 介紹

CMake 簡要內容

CMake 是cross platform make的簡寫,從這裡你完全可以看出,CMake是基於Make來實現相關的內容的,換句話說,CMake就是在Make的基礎上抽象出來的更高階的框架。

CMakeLists.txt的編譯test.cpp生成test可執行檔案的基本例子:

<span style="color:#000000"><code class="language-CMake"><span style="color:#000088">cmake_minimum_required</span>(VERSION <span style="color:#006666">2.8</span>.<span style="color:#006666">10</span>)
<span style="color:#000088">SET</span>(PROJECT_NAME test)
<span style="color:#000088">project</span>(<span style="color:#666600">${PROJECT_NAME}</span>)
<span style="color:#000088">add_executable</span>(test test.cpp)  </code></span>
  • 1
  • 2
  • 3
  • 4

通過以下Shell Command:

<span style="color:#000000"><code class="language-Shell">mkdir -p build && <span style="color:#4f4f4f">cd</span> build && cmake .. && make </code></span>
  • 1

通過上文的shell命令,其實你也已經發現了,cmake會生成Makefile,然後我們需要呼叫make來生成可執行檔案。

CMakeLists.txt 編寫要點

常用的cmake指令解釋

<span style="color:#000000"><code class="language-CMake"><span style="color:#000088">cmake_minimum_required</span>(VERSION xxx) <span style="color:#880000">#cmake最小版本需求,新版本的cmake改了很多東西,提升了便利性,也可能讓你自己挖坑了</span>
<span style="color:#000088">project</span>(xxx) <span style="color:#880000">#設定此專案的名稱</span>
<span style="color:#000088">add_executable</span>(target target_source_codes) <span style="color:#880000">#生成可執行檔案target ,後面填寫的是生成此可執行檔案所依賴的原始檔列表。</span>
<span style="color:#000088">SET</span>(var_name var_value)<span style="color:#880000"># 設定一個名字var_name 的變數,同時給此變數賦值為var_value</span>
<span style="color:#000088">MESSAGE</span>(<span style="color:#009900">"MSG"</span>) <span style="color:#880000">#類比echo 列印訊息</span>
<span style="color:#000088">option</span>(var_name <span style="color:#009900">"comment"</span> var_value) <span style="color:#880000">#給變數var_name賦值為var_value,comment是此變數的註釋,和SET 有類似的功效,用於給某變數設定預設值</span>
<span style="color:#000088">include_directories</span>(xxx) <span style="color:#880000">#新增include路徑,也就是 gcc -I xxx 的意思,或者vs ide中新增標頭檔案包含目錄</span>
<span style="color:#000088">add_subdirectory</span>(xxx) <span style="color:#880000">#呼叫xxx子目錄的CMakeLists.txt執行</span>
add_compile_options(xxx) <span style="color:#880000">#給編譯器新增xxx引數,但是貌似沒有什麼用,我一般不這樣新增引數,不直接</span>
<span style="color:#000088">link_directories</span>(xxx) <span style="color:#880000">#給編譯器新增庫目錄,也就是 gcc -L xxx 的意思,或者vs ide中新增庫的包含目錄</span>
<span style="color:#000088">add_library</span>(lib_name SHARED <span style="color:#000088">or</span> STATIC lib_source_code) <span style="color:#880000">#和add_executable類似,生成庫檔案,SHARED代表動態庫,STATIC代表靜態庫, 最後一個引數代表此庫的原始檔列表,此指令只有三個引數</span>
<span style="color:#000088">target_link_libraries</span>(target_name lib_name ...) <span style="color:#880000">#給目標新增依賴庫,類似與gcc -l lib_name,此指令有兩個用處,一個是給可執行target_name 新增庫依賴,二是給庫target_name 新增庫依賴。</span>
</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

我常見的cmake指令也就是上述的這些,還有部分比較常見的指令這裡沒有列出,我放到了下面單獨講解如:install()

cmake 流控制指令相關

條件語句

<span style="color:#000000"><code class="language-CMake"><span style="color:#000088">if</span>(xxx)
<span style="color:#000088">...</span>
elseif(xx)
<span style="color:#000088">...</span>
<span style="color:#000088">else</span>()
<span style="color:#000088">...</span>
endif()

<span style="color:#880000">#常見條件語句用法為:</span>
<span style="color:#880000"># if (va)  va為bool型</span>
<span style="color:#880000"># if (va MATCHES xxx) va 是string型別,如果va包含了xxx,則此句為真</span></code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

迴圈語句

<span style="color:#000000"><code class="language-CMake">foreach(va va_lists)
<span style="color:#000088">...</span>
endforeach()</code></span>
  • 1
  • 2
  • 3

在foreach中,va的值會依次被va_lists的值替換

macro 和 function

<span style="color:#000000"><code class="language-CMake">macro(name arg <span style="color:#000088">...</span>)
<span style="color:#000088">...</span>
endmacro()
<span style="color:#000088">function</span>(name arg <span style="color:#000088">...</span>)
<span style="color:#000088">...</span>
endfunction()</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

巨集和函式效果都類似,唯一區別為function中的變數為區域性的。

install 指令(主要是生成Makefile中的install target)

<span style="color:#000000"><code class="language-CMake"><span style="color:#000088">install</span>(FILES flie DESTINATION dir_path) <span style="color:#880000">#執行make install時,把file拷貝到dir_path</span>
<span style="color:#000088">install</span>(PROGRAMS file DESTINATION dir_path) <span style="color:#880000">#執行make install時,把file拷貝到dir_path,並給予file可執行許可權</span>
<span style="color:#000088">INSTALL</span>(TARGETS  ylib ylib_s
    <span style="color:#880000">#RUNTIME DESTINATION xxx</span>
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
)<span style="color:#880000"># 安裝libylib.so到lib目錄,安裝libylib_s.a到lib目錄,RUNTIME 是安裝可執行檔案到xxx目錄,注意這個指令有個坑,我後面會說明這個問題。</span></code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

configure_file指令

<span style="color:#000000"><code class="language-CMake">configure_file(fileA fileB <span style="color:#4f4f4f">@ONLY</span>)
#把fileA 複製並重命名為fileB,此時,fileA中的<span style="color:#4f4f4f">@var</span><span style="color:#4f4f4f">@的</span>值會被替換為cmakelists.txt 中var的值。<span style="color:#4f4f4f">@ONLY</span>是隻轉換<span style="color:#4f4f4f">@va</span><span style="color:#4f4f4f">@這</span>種變數</code></span>
  • 1
  • 2

CMakeLists.txt常用的內建變數

<span style="color:#000000"><code class="language-CMake">CMAKE_INSTALL_PREFIX  <span style="color:#880000">#make install 的安裝路徑</span>
CMAKE_BUILD_TYPE <span style="color:#880000">#生成的目標為debug或者release</span>
CMAKE_C_FLAGS <span style="color:#880000">#gcc 的編譯引數指定,這個非常好用,一般通過set 修改其值</span>
CMAKE_CXX_FLAGS <span style="color:#880000">#g++ 和上面CMAKE_C_FLAGS 類似</span>
CMAKE_CURRENT_SOURCE_DIR <span style="color:#880000"># 當前CMakeLists.txt所在的目錄,主要用來定位某檔案</span>
CMAKE_CURRENT_BINARY_DIR <span style="color:#880000"># 當前CMakeLists.txt對應的編譯時的目錄</span>
</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

XXXConfig.cmake檔案(cmake模組檔案)編寫以及引用

yLibConfig.cmake

<span style="color:#000000"><code class="language-CMake">
<span style="color:#000088">find_path</span>(yLib_INCLUDE_DIR NAMES ylib.h PATHS @[email protected]/<span style="color:#000088">include</span>) 

<span style="color:#000088">find_library</span>(yLib_LIBRARY NAMES ylib PATHS @[email protected]/lib) 
<span style="color:#880000">#find_library 會到@[email protected]/lib目錄查詢libylib.so</span>


<span style="color:#000088">set</span>(yLib_FOUND <span style="color:#000088">TRUE</span>) 
<span style="color:#000088">set</span>(yLib_INCLUDE_DIRS <span style="color:#666600">${yLib_INCLUDE_DIR}</span>) 
<span style="color:#000088">set</span>(yLib_LIBS <span style="color:#666600">${yLib_LIBRARY}</span>) 


<span style="color:#000088">mark_as_advanced</span>(yLib_INCLUDE_DIRS yLib_LIBS )</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

XXX_INCLUDE_DIR  XXX_LIBRARY  XXX_FOUND  XXX_INCLUDE_DIRS  XXX_LIBS  以上變數最好都定義了,不然find_package可能會報錯  .cmake 檔案就是定義了相關include變數和lib變數,沒有什麼其他的東西

呼叫:

<span style="color:#000000"><code class="language-Cmake"><span style="color:#000088">set</span>(yLib_DIR <span style="color:#009900">"@[email protected]/cmake"</span>)
<span style="color:#009900">#設定.cmake 的目錄所在</span>
find_package(yLib REQUIRED)
<span style="color:#009900">#find_package會匯入.cmake 中的相關變數,完成相關模組的匯入</span></code></span>
  • 1
  • 2
  • 3
  • 4

一個關於install()指令的深坑

<span style="color:#000000"><code class="language-CMake">INSTALL(TARGETS  ylib ylib_s
    #RUNTIME<span style="color:#009900"> DESTINATION </span>xxx
   <span style="color:#009900"> LIBRARY </span>DESTINATION lib
   <span style="color:#009900"> ARCHIVE </span>DESTINATION lib
)
<span style="color:#009900">#對於RUNTIME  和 LIBRARY 兩種目標,在安裝時候,cmake會預設給你移除掉目標檔案中的gcc的Wl,rpath的值,導致某些庫找不到的錯誤。</span>
以下變數會影響此坑,更詳細的資訊去查查別的資料,我這裡就不詳細說明了。
<span style="color:#009900">#set(CMAKE_SKIP_BUILD_RPATH FALSE)                </span>
<span style="color:#009900">#set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)        </span>
<span style="color:#009900">#set(CMAKE_INSTALL_RPATH "")                      </span>
<span style="color:#009900">#set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)    </span>
<span style="color:#009900">#set(CMAKE_SKIP_INSTALL_RPATH TRUE)</span>
<span style="color:#009900">#set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")</span>

<span style="color:#009900">#set(CMAKE_SKIP_RPATH TRUE)</span>
<span style="color:#009900">#set(CMAKE_SKIP_INSTALL_RPATH TRUE)</span></code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

注意:cmake會直接修改你的二進位制檔案替換掉rpath的相關資訊。預設替換的值是一個空值,也就是說移除掉了你設定的rpath的值