CMake 的好處之一就是對彈性. 除了專案第一個被讀取的 CMakeLists.txt 比較冗長外, 新增子目錄很容易就可以繼承其母目錄的各個屬性. 實務上, 也許會讓每個子目錄自成一個 library, 最後再全部連結. 好處是每個模組獨立, 方便單獨驗證; 模組新增或移除容易; memory-map 容易根據模組去調整等. 缺點是最後連結時, 要能去把這些 library 找出來; 而且 library 間可能會有相互的相依性問題.
如果要將 library 全部放在某個目錄, 可以寫成下面的樣子. 如果是自行寫 link-script, 就很容易找到. 可是這樣還是沒解決掉 link 前去判讀 dependent.
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/myLibraries)
如果最後 link 的檔案是最後被執行, 且其為獨立的 CMakeLists.txt 則下面的方法算是一個拙劣但是可行的方式.
ADD_CUSTOM_COMMAND(OUTPUT ${someFile} DEPENDS ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/* COMMAND touch ${someFile} COMMENT "Touch someFile for re-link libraries." ) ADD_CUSTOM_TARGET(${myTarget} ALL DEPENDS ${someFile} COMMAND echo some-commands. COMMENT "re-Link" )
前面提到, CMake 的屬性具繼承關係, 但是卻不具回溯性. 換言之, 子目錄裡宣告的變數無法讓母目錄繼續使用. 不過卻可透過宣告 PARENT_SCOPE 達到讓母目錄使用的目的. 如下面的例子. 但是缺點是, 中繼的目錄就算不使用該變數, 還是得將該變數再宣告一次 PARENT_SCOPE, 好讓上一層的母目錄可以得到該變數的變化, 如新增一個 library. 否則變數的有效性就會被中繼目錄給破壞.
SET(subVar "subVar myValue" PARENT_SCOPE)
使用 Global 變數則是另一個變通的方法, 透過 MACRO 來新增一個 library. 如下面的例子. 缺點是每新增一個 library 必須記得呼叫該 macro.
Project/CMakeLists.txt
... SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/myLibraries) LINK_DIRECTORIES(${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) MACRO(AddMyLib arg) SET_PROPERTY(GLOBAL APPEND PROPERTY myLibs "${arg}") ENDMACRO(AddMyLib) ADD_SUBDIRECTORY(myLibA) ADD_SUBDIRECTORY(myLibB) ADD_SUBDIRECTORY(myExe) ...
Project/myLibA/CMakeLists.txt
... ADD_LIBRARY(myLibA ${mySRC_LIST}) AddMyLib(myLibA) ...
Project/myLibB/CMakeLists.txt
... ADD_LIBRARY(myLibB ${mySRC_LIST}) AddMyLib(myLibB) ...
Project/myExe/CMakeLists.txt
... ADD_EXECUTABLE(myExe ${mySRC_LIST}) GET_PROPERTY(myLibsList GLOBAL PROPERTY myLibs) # For cross-reference between libraries. TODO: Workaround solution.... FOREACH(myll ${myLibsList}) TARGET_LINK_LIBRARIES(myExe -l${myll}) ENDFOREACH() TARGET_LINK_LIBRARIES(myExe ${myLibsList}) ...
沒有留言:
張貼留言