2010-08-03 62 views
5

我有一個項目,其makefile使用GNU Make獨有的功能。不幸的是,在運行make時,我們必須支持GNU make所依賴的平臺。當某人運行`make`時檢測(非)GNU Make

我的一個同事被這個咬了,當一個非GNU make的實現靜靜地無法正確地構建我們的代碼(它將自動變量擴展爲空字符串)。我想通過生成明確的錯誤消息來防止再次發生。

我可以在Makefile中寫什麼來區分GNU make和non-GNU make,打印出明確的錯誤並退出?

我已經想出了一個解決方法,將我的真實生成文件重命名爲GNUmakefile,並在Makefile中放置一個小存根,但我寧願更直接一些。

的Beta版和丹塑造的答案看起來真的不錯,很簡單,但在AIX 6.1,廠名實現不能處理任何人:

$ cat testmake 

foo: 
     touch foo 

ifeq ($(shell $(MAKE) -v | grep GNU),) 
$(error this is not GNU Make) 
endif 

ifeq "${MAKE_VERSION}" "" 
$(info GNU Make not detected) 
$(error ${MIN_MAKE_VER_MSG}) 
endif 


$ /usr/bin/make -f testmake 
"testmake", line 5: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 6: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 7: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 8: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 11: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 12: make: 1254-055 Dependency line needs colon or double colon operator. 
"testmake", line 13: make: 1254-055 Dependency line needs colon or double colon operator. 
make: 1254-058 Fatal errors encountered -- cannot continue. 

我碰到兩個古老和現代類似的問題Sun的產品版本(Solaris 8 & 10)。那個不那麼重要,但會很好管理。

+0

您運行的是哪個版本的GNU make? – bta 2010-08-04 18:00:28

+0

你是對的。我所採用的方法過於依賴GNUisms,因此可能無法在非GNU make的實現*上運行。我現在懷疑是否有一種使用Makefile(即不使用shell腳本或其他外部資源)來實現您的目標的便攜式方法。我已經取消了我的答案。 – 2010-08-04 18:46:36

回答

2

我不知道任何GNUMake特有的內部特性,但這裏有一個kludge:調用「make -v」並解析「GNU」的輸出(因爲非GNU Make本來MAKE集到GNU MAKE):

ifeq ($(shell $(MAKE) -v | grep GNU),) 
$(error this is not GNU Make) 
endif 

編輯:
像丹成型,我開始看到這個問題的真正規模。正如所寫,它需要一個Makefile,它在所有版本的Make中在語法上都是正確的。我無法訪問Sun Make(我無法找到它的手冊),所以我不知道這是否可行,或者如果是這樣寫的話,或者如果測試它,如何測試。

但我可以建議一種可能的方法。也許像這樣的東西可以通用:

default: 
    ./runGNUMake.pl 

就是這樣,這就是整個makefile。然後用Perl(或bash,或其他任何你喜歡的)編寫runGNUMake腳本,這些腳本可以像我的「make -v」kludge那樣做,然後打印錯誤信息或運行「make -f realMakefile」。

+0

我曾想過在make之前運行的外部腳本中執行此操作,但我沒想過將它嵌入makefile本身。 – Novelocrat 2010-08-04 17:14:32

+0

在AIX 6.1上不起作用:-( – Novelocrat 2010-08-04 17:32:20

+0

Novelocrat:真的嗎?它是如何失敗的,非GNU Make有一個MAKE似乎被設置爲GNU Make,或者GNU Make似乎是非GNU?(我想我們可以分別稱這些爲「false positive」和「false negative」)。 – Beta 2010-08-04 17:46:02

6

如上所述,GNU make檢查GNUmakefilemakefileMakefile或之前,我已經如你描述中使用的瑣碎修復程序,默認(誘餌)Makefile會導致一個錯誤/警告:

default: 
    @echo "This requires GNU make, run gmake instead" 
    exit 70 

的GNU make documentation建議在Makefile是GNU特定的時候使用GNUmakefile名稱,所以這是我的首選解決方案。

在原生make更喜歡不同Makefile名稱的平臺上,您可以對其進行變更,例如,在FreeBSD上,我在BSDmakefile中有上面的誘餌,它優先於Makefile(這樣可以防止系統make妨礙我的構建)。 AFAICT AIX或Solaris make沒有可以以此方式使用的備用名稱。

嘗試調用GNU make的包裝器Makefile的一個問題是傳遞所有參數。

一個看似便攜式測試(到目前爲止,我發現它在古代OSF1的混合工作,BSD和Solaris系統),可以使用SOMETHING=$(shell ...)檢測是否GNU make運行,非GNU版本將不設置SOMETHING 。由於deferred evaluation of variables,你不能像預期的那樣容易地使用它。這依賴於以$()(即將$(shell foo)作爲變量/宏名稱而不是function進行擴展,即使在該實現中對此類名稱的分配會導致錯誤)執行時使用空格處理靜默處理宏的方式。

可以打印明確錯誤的唯一可移植的方法是有一個虛擬的目標是始終運行,使用上述伎倆:

GNUMAKE=$(shell echo GNUMAKE) 

default: gnumake all 

gnumake: 
     @[ "$(GNUMAKE)" = "GNUMAKE" ] || { echo GNU make required ; exit 70; } 

這裏假設你有一個POSIX sh殼。

(我已經看到它檢查$(MAKE) -v失敗當兩個系統和GNU make被稱爲「make」,系統make密謀反對你和調用GNU make ...你會需要一些仔細檢查環境變量的PATH測試, MAKE以及可能SHELL來處理每種情況。)