2011-09-30 76 views
6

我正在尋找一個高級構建系統/工具,可以幫助我將嵌入式C項目組織到「模塊」和「組件」中。請注意,這兩個術語非常主觀,所以我的定義如下。爲嵌入式C/C++項目構建系統

  • 模塊是c和h文件的連貫集合,但只有一個公共h文件對其他模塊可見。另一方面,組件(或層)是模塊(例如,應用層,庫層,驅動層,RTOS層等)的集合。

構建系統/工具應該 -

  • 防止環狀部件和模塊之間的依賴關係(循環依賴內部模塊是好的)
  • 防止訪問模塊的私人障礙。如果其他模塊嘗試包含模塊專用的頭文件,則生成系統必須拋出錯誤。但是,私有屏障內的文件必須能夠在該屏障內包含其他文件。在主機
  • 支撐建築物和自動的單元測試執行(對於TDD快速反饋迴路)
  • 支持單元測試要對目標模擬器
  • 支持代碼靜態分析
  • 支持代碼生成
  • 支持代碼運行重複檢測(執行DRY原則)
  • 支持代碼美化
  • 支撐生成單元的測試代碼覆蓋率度量
  • 支撐件產生的代碼質量度量
  • 與平臺無關

我可以寫我自己的構建工具,花了很多時間在上面。但是,這不是我的專業領域,如果有人已經創建了這樣的工具,我寧願不重新發明輪子。

回答

4

實現這一目標的常規方法是將每個模塊的源代碼放入單獨的目錄中。每個目錄可以包含模塊的所有源文件和頭文件。

每個模塊的公共頭可以放在一個單獨的公共頭中。我可能會使用從公共目錄到每個頭文件的相關模塊目錄的符號鏈接。

編譯規則只是聲明沒有模塊可能包含除公共目錄中的標題以外的其他模塊的標題。這樣做的結果是,任何模塊都不能包含來自其他模塊的頭文件 - 除了公共頭文件(因此強制執行私有障礙)。

自動防止循環依賴不是微不足道的。問題在於,您只能通過一次查看幾個源文件來確定是否存在循環依賴關係,而編譯器一次只能查看一個源文件。

考慮一對模塊,ModuleA和ModuleB,以及一個使用這兩個模塊的程序Program1。

base/include 
     ModuleA.h 
     ModuleB.h 
base/ModuleA 
     ModuleA.h 
     ModuleA1.c 
     ModuleA2.c 
base/ModuleB 
     ModuleB.h 
     ModuleB1.c 
     ModuleB2.c 
base/Program1 
     Program1.c 

當編譯Program1.c時,如果它包含ModuleA.h和ModuleB.h,如果它使用兩個模塊的服務是完全合法的。因此,如果ModuleB.h包含在同一個翻譯單元(TU)中,ModuleA.h就不會抱怨,如果ModuleA.h包含在同一個TU中,ModuleB.h也不會抱怨。

讓我們假設它是合法的ModuleA使用ModuleB的設施。因此,在編譯ModuleA1.c或ModuleA2.c時,包含ModuleA.h和ModuleB.h都不會有問題。

但是,爲了防止循環依賴,你必須能夠使用ModuleA.h禁止ModuleB1.c和ModuleB2.c代碼。

就我所見,唯一能做到這一點的方法是需要ModuleB的一個私有頭文件,它說「ModuleA已經包含了」,即使它不是,並且這包含在ModuleA.h之前被包括在內。

ModuleA.h的骨架將是標準格式(和ModuleB.h將是類似的):

#ifndef MODULEA_H_INCLUDED 
#define MODULEA_H_INCLUDED 
...contents of ModuleA.h... 
#endif 

現在,如果在ModuleB1.c的代碼包含:

#define MODULEA_H_INCLUDED 
#include "ModuleB.h" 
...if ModuleA.h is also included, it will declare nothing... 
...so anything that depends on its contents will fail to compile... 

這遠不是自動的。

你可以做的包括文件的分析,並需要有一個循環,少拓撲排序的依賴關係。曾經有UNIX系統一起提供必須的,從而靜態(.a)庫可以創建包含在並不需要的重新掃描命令的目標文件的服務程序tsort(和伴侶程序,lorder)存檔。該ranlib程序,並最終arld承擔了管理單個庫的重新掃描,因此特別製作冗餘的lorder的職責。但tsort有更多的一般用途;它在某些系統上可用(例如MacOS X; RHEL 5 Linux)。

因此,使用依賴從GCC加tsort跟蹤,你應該能夠檢查是否有模塊之間循環。但這必須小心處理。

可能有一些IDE或其他工具集自動處理這些東西。但通常程序員可以有足夠的紀律以避免問題 - 只要需要和模塊間的依賴關係被仔細記錄。

+0

+1很好的回答,特別是最後一段。 – mouviciel

+0

Jonathan,選擇什麼工具來實現您的建議解決方案? Make,CMake,Rake還是其他什麼? – thegreendroid

+1

我對更現代的系統沒有強烈的觀點;我見過CMake讚美,但你可以使用它們中的任何一個。它可能部分取決於你最熟悉的語言。例如,如果您使用Ruby,那麼Rake很有意義。我仍然傾向於使用普通的老式Make,但是我一直這麼做......很長一段時間...所以我覺得這樣做很舒服。這是一個最低公分母解決方案,具有可移植性問題。我有時使用Autoconf來處理可移植性問題,但它有其自身的複雜性(並且大大增加了小型項目的規模)。 –

2

對於一般的解決方案,我完全推薦使用Jonathan Leffler的解決方案。但是,如果你絕對需要一個自動化的測試你的模塊是否是自包含的,孤立的,你可以給Debian的構建系統一試。

包裝每個模塊爲Debian軟件包(這是非常快的時候它已經完成autoconf'd),正確申報構建時刻依賴,並建立一個pbuilder環境中的軟件包。這確保了每個模塊的唯一的公共報頭是可用的(因爲只有那些在由pbuilder構建其它軟件包安裝.deb軟件包),並有很好的工具來看待Debian軟件包樹木,並確保他們是cycle-自由。

但是,這可能是過度殺戮。只是說明它的完整性和案例,你肯定需要一個自動化的解決方案。