2017-03-12 169 views
1

我想設置我的項目使用CMake正確編譯。CMake與子目錄

我的目錄看起來是這樣的:

root 
|- bin 
| |- // Where I want to build CMake from - using 'cmake ..' 
|- build 
| |- 
|- include 
| |- database 
| | |- database.h 
|- src 
    |- database 
    | |- database.cpp 
    |- main 
      |- main.cpp 

我子目錄肯定會成長爲我的項目規模增大和揣摩CMake的可能會是一個好主意來學習。目前我只能讓CMake在我的src /裏面沒有子目錄。不過,我確實希望這個項目能夠發展成許多子目錄。

我需要多個CMakeLists.txt每個目錄內的.cpp文件?任何人都可以將我指向正確的方向嗎?

謝謝!

+0

我認爲CMakeLists.txt只是一個,在父目錄(PS)我不是cmake的專家 –

+0

@DanishAlsayed我在這裏看到了一些例子,有些人建議多個CMakeLists.txt,但是他們有一個非常具體問題,我不知道這是否是我的問題的解決方案具體。 –

+0

你看過文檔嗎? https://cmake.org/examples/ –

回答

4

您的項目似乎不需要多個CMakeLists.txt。多次使用多個CMakeLists.txt的目的是多方面的,但它似乎不適合您的項目。例如,一種好處是分層組織,因此您可以分開構建不同的單元並最終鏈接。

考慮這種情況,如果你有你的根稱爲tests另一個目錄。該目錄包含您希望開發人員選擇是否編譯它的單元測試。在這種情況下,你把一個在的CMakeLists.txt tests,並啓用這在主的CMakeLists.txt與add_subdirectory(tests)像這樣:

if(testing_enabled) 
    add_subdirectory(tests) 
endif() 

tests,會有另一種的CMakeLists.txt。這樣,你分開關注。單元測試的開發與您的項目開發無關,而且構建過程是分開的。

又如

考慮這種情況,如果你有兩個庫,用戶可以從中選擇。在這種情況下,您的root有兩個目錄lib1lib2。現在你可以做這樣的事情在你的主要的CMakeLists.txt:

if(IWantLib1) 
    add_subdirectory(lib1) 
else() 
    add_subdirectory(lib2) 
endif() 

而且兩者lib1lib2目錄中包含的CMakeLists.txt。

5

我會參考你的this article深入討論兩種主要方法,但有幾種方法可以構建這樣的項目。

  • 頂部一個CMakeLists.txt文件,它列出了所有不同子目錄中的所有源文件。您通常只會看到非常簡單的項目。
  • 每個目錄中有一個CMakeLists.txt文件,每個文件由其父代使用add_subdirectory()引入。這種方法非常普遍。
  • 頂層有一個CMakeLists.txt文件,每個子目錄都有自己的文件,列出自己的源文件和目標。頂級CMakeLists.txt文件將帶有include()的子目錄文件。不太常見,但可以比其他兩個有優勢。

各有其優缺點。只有一個頂級CMakeLists.txt文件只有在文件和子目錄很少時才被推薦。一旦項目增長,將所有內容保留在頂層可能會變得太多,導致CMakeLists.txt文件難以跟上。它還有一個缺點,即文件添加或刪除的更改不限於特定的目錄。這看起來可能不是什麼大不了的事情,但是如果有多個人正在從事項目工作,並且想要輕鬆看到其他人的更改會影響項目的哪部分內容(例如在git歷史記錄中),那就更困難了。如果您同時添加/刪除文件,則更是如此,因此都會更改頂級CMakeLists.txt文件並有可能發生衝突。

一旦項目大小變得不平凡,大多數人選擇在每個子目錄中添加一個CMakeLists.txt文件,並使用add_subdirectory()將它們放在一起。 TheQuantumPhysicist的答案給出了一個很好的例子,說明這可能是有用的,所以我不會在這裏重複大部分細節。這個結構爲您提供了輕鬆打開/關閉構建樹的整個部分的能力,但更重要的是,它爲每個子目錄提供了自己的變量範圍。如果要在源樹的一部分中設置變量等,但在另一部分中不可見這些更改(請考慮只適用於複雜目錄結構的一部分的編譯器標誌),這一點很重要。

一個頂級CMakeLists.txt文件的第三個選項與每個提供include()文件的子目錄不太一樣,但它與在每個子目錄中使用一個CMakeLists.txt文件相似。兩者都將目錄中文件的詳細信息本地化爲CMakeLists.txt或該目錄中的其他類似名稱的文件。因此,變更在版本控制歷史記錄等中變得更加容易合併和理解。第三種方法允許第二種方法不會在使用target_sources()指定每個子目錄中的源文件時更自由地使用target_link_libraries()。在這個答案的頂部鏈接的文章詳細說明了爲什麼target_sources()可以是有利的,這是爲什麼這個第三種方法對許多項目來說可能是理想的核心。

最後,我建議你不要把你的構建樹放在你的源代碼樹中。相反,創建您的構建樹作爲源樹的兄弟。旨在保持源代碼樹不受構建影響。所需要的只是讓某人在源代碼樹中創建一個與您用於構建樹的任何名稱相同的名稱來爲出錯的目錄創建一個目錄(我已經多次看到這個目錄!)。您可能還想爲一個源代碼樹設置多個構建樹,例如一個用於調試構建,另一個用作發佈構建,因此將這些構建樹放在源代碼樹之外也有助於減少源樹的混亂。

+0

偉大的建議,非常感謝。關於你的最後一點,我犯了一個錯字。我打算把這個評論放在生產線上。我不會從bin目錄生成。我想構建目錄是我想調用CMake的地方? –

+0

是的,我已經認爲你的意思是你在'build'目錄而不是'bin'中運行CMake。通常的方法是從build目錄運行CMake。可以從任何地方運行CMake,並使用未記錄的'-B'選項將特定目錄作爲構建目錄,但我不建議您這樣做,除非有充分的理由。 –