2012年2月20日 星期一

CMake 玩一玩!!PormanGL實例解析 Ver 2.0

(內文轉至巴哈姆特《三國好棒棒 哈拉版》,已取得原作者授權)

Dear All:
最近跨平台的專案越來越多,相信大家對於不同開發工具的整合一定很頭大。其實這部分可以用CMake解決,不過老實說CMake的文件真的很...不知讓我從何說起。記的前年小弟在開發自己的Lib時,就遇到不同VC版本的問題,有人只有2005、有人只有2008,搞得我只好兩套都裝,兩套都Commit.............,沒多久2010又出了.... (%$%$#@$^)

最後拖著疲憊的心情開始使用CMake,透過Try & Error!!的方式一步步將PormanGL專案重新建立,不過Porting後在開發上的爽度果然有增加!!所以 廢話不多說,來整理一下心得吧!相信對有興趣使用CMake的朋友會有些幫助。


Section1架構
CMake主要是一個跨平台"間接"編譯的工具,運作方式是透過撰寫CMake Script後,將Script透過CMake執行程式,幫你轉譯出你所需平台的compile指令,在Linux上就是makefile、Win32就是VS Project,所以"間接"兩字就是這樣來的。

CMake是一個樹狀結構,每個目錄夾下至多只有一個可以執行的CMakeLists.txt,最頂端資料夾下的CMakeList也就是Root,會對應產生VS的soluction檔,而末端資料夾會產生Project檔,中間則負責上一層與下一層的連結。

資料夾結構:
- Root
 |_ source
 |_ header
 |_ smaples
      |_ sample_01
           |_ source
           |_ header
           |_ CMakeLists.txt (Leaf, *.proj file)
      |_ sample_02
           |_ source
           |_ header
           |_ CMakeLists.txt (Leaf, *.proj file)
      |_ CMakeLists.txt (Link Root and Leaf)
 |_ bin
 |_ CMakeLists.txt (Root, *.sln file)

Section2: 指令、變數與屬性
CMake Script主要由"指令"、"變數"與"屬性 Property"組成,外加條件判斷式"if...else..."、"foreach"等等,跟一般的Script差不多,也可以自訂function來呼叫,但須特別注意的是自定function只能改變Script的邏輯判斷及功能,要能真正設定Project與Soluction檔案內容的還是所謂的"指令"及"屬性"。

"變數"在CMake的Scope是單向傳遞,上層的"變數"定義會被自動Pass到底層去,但底層"變數"的Scope不返回上層。舉個例來說:Root定義一個 XXX_SOURCE 的變數,在Leaf裡可直接使用,而定義在 Leaf 的 OOO_SOURCE 變數,Root並不會知道且無法使用。

而預設屬性的內容又有分層級:
Global Scope
Directories
Target
Tests
Source Files
Cache Entries
這幾類,但目前我有使用到的集中在Target,Target主要代表會產生"東西"的CMakeLists.txt,而"東西"就例如:exe、lib與dll這些。

以下就是我這次Porting所用到的指令列表:(詳細的說明請參照官方的Wiki文件)
cmake_minimum_required
project
set
source_group
include_directories
option
set_property
target_link_libraries
add_definitions
add_dependencies
add_library
add_subdirectory
add_executable
link_directories
remove_definitions

section3: 與VisualStudio的對應
在這個章節為以 Q&A 的形式來撰寫,點出在Cmake裡的每個指令是對應到VS的哪個設定

1 CMake自動產生的四個Configuration: Debug、Release、RelWithDebInfo、MinSizeRel有辦法新增、刪除嗎?
ANS: 我目前還沒有找到刪除 or 增加的辦法,不過基本上這些設定都還滿實用的。

2 如何設定C/C++ -> Additional Include Directories?
ANS:使用指令:include_directories,參數輸入你所需要的header files

3 如何設定C/C++ -> Preprocessor Definitions?
ANS:使用指令:add_definitions,參數輸入格式為: -D + DEFINITION,例如新增PGL_EXPORT,寫法就是:add_definitions(-DPGL_EXPORT),當然要注意的是這個設定會延續到下一層,也就是Root設定,Leaf的project也會新增這個定義,解決方法就是在leaf使用指令: remove_definitions,參數格式與add相同。

4 CMake在Link -> Output File設定都會固定加上Configuration的名子,有辦法取消嗎?
ANS: 這邊是在網路上查到的一個作弊的方式,使用指令: set_property,設定Target的Property: PREFIX等於"../",也就是set_property (TARGET ${SAMPLENAME} PROPERTY PREFIX "../")

5 如何設定Link -> Additional Dependencies?
ANS:使用指令:target_link_libraries,參數輸入你所需要link的lib,但注意這個設定也會延續到下一階層,如果你下一階不需要link這些libs,記得set_property (TARGET ${TARGETNAME} PROPERTY LINK_INTERFACE_LIBRARIES ""),將這個繼承中斷。

6 如何設定Link -> Ignore Specific Library?
ANS:例如我要刪除LIBC.lib的link,指令可以這樣下set_property (TARGET ${TARGETNAME} PROPERTY LINK_FLAGS /NODEFAULTLIB:LIBC.lib)

7 如何更改Output的檔案名稱,例如在DEBUG版本,檔案名稱最後面想加"_d"來與release做區別?
ANS: 指令上大概就是將Target property裡的ARCHIVE_OUTPUT_NAME_DEBUG、LIBRARY_OUTPUT_NAME_DEBUG、 set_property (TARGET ${TARGETNAME} PROPERTY RUNTIME_OUTPUT_NAME_DEBUG,透過指令:set,加上你所要的名子。

範例如下:
set_property (TARGET ${TARGETNAME} PROPERTY ARCHIVE_OUTPUT_NAME_DEBUG ${TARGETNAME}_d)
set_property (TARGET ${TARGETNAME} PROPERTY LIBRARY_OUTPUT_NAME_DEBUG ${TARGETNAME}_d)
set_property (TARGET ${TARGETNAME} PROPERTY RUNTIME_OUTPUT_NAME_DEBUG ${TARGETNAME}_d)

8 如何更改Output的檔案輸出的位子呢?
ANS: 一樣也是修改Target property的PROPERTY ARCHIVE_OUTPUT_DIRECTORY、PROPERTY LIBRARY_OUTPUT_DIRECTORY、PROPERTY RUNTIME_OUTPUT_DIRECTORY設定。

範例如下:
set_property (TARGET ${TARGETNAME} PROPERTY ARCHIVE_OUTPUT_DIRECTORY ${PormanGL_SOURCE_DIR}/lib)
set_property (TARGET ${TARGETNAME} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${PormanGL_SOURCE_DIR}/lib)
set_property (TARGET ${TARGETNAME} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${PormanGL_SOURCE_DIR}/bin)

9 如何新增VS裡Source Explorer的虛擬資料夾?
ANS:使用指令:source_group,例如新增一個Cg folder: source_group ("Cg" FILES Cg.h),其中參數"Cg"為folder名子、FILES代表你要加入的是檔案,而Cg.h為加入的檔案。但要記住,這個設定要成立Cg.h必須被包含在add_library or add_executable中。

10 如何設定soluction產生lib?
ANS:使用指令:add_library

11 如何設定soluction產生exe?
ANS:使用指令:add_executable

12 如何設定Linker -> Additional Library Directories?
ANS:使用指令:link_directories,即可設定此項目

沒有留言:

張貼留言

LinkWithin

Related Posts Plugin for WordPress, Blogger...