為什麼沒有人使用make for Java?


Answers

可敬的make程序能夠很好地處理單獨編譯的語言,如C和C ++。 您編譯一個模塊,它使用#include來拉入其他包含文件的文本,並將單個目標文件寫入輸出。 編譯器是一個一次一個的系統,有一個單獨的鏈接步驟將目標文件綁定到可執行的二進製文件中。

但是,在Java中,編譯器必須實際編譯通過import其他類。 儘管可以編寫一些能夠從Java源代碼生成所有必需的依賴項的代碼,以便make可以按照正確的順序構建類,但仍然無法處理循環依賴項等情況。

通過緩存其他類的編譯結果,Java編譯器也可以更高效,同時編譯依賴於已編譯結果的更多類。 單獨make這種自動依賴性評估是不可能的。

Question

幾乎所有我見過的Java項目都使用Maven或Ant。 他們是很好的工具,我認為任何項目都可以使用它們。 但是發生了什麼? 它用於各種非Java項目,並且可以輕鬆處理Java。 如果您使用Windows,那麼必須下載make.exe,但Ant和Maven也不會隨JDK一起提供。

與Java一起使用時,是否存在一些基本缺陷? 僅僅是因為Ant和Maven是用Java編寫的?




螞蟻和後來的Maven被設計來解決由Make造成的一些頭痛(當在過程中創建新的時)這只是進化。

此後不久,幾個開源Java項目意識到Ant可以解決他們在Makefiles中遇到的問題....

http://ant.apache.org/faq.html#history

無論他們解決什麼問題,或只是創建一個額外的格式來學習是一個主觀的話題。 事實是,這幾乎是每一項新發明的歷史:創造者說它解決了很多問題,原來的用戶說這些都是美德。

它的主要優點是可以與java集成。

我猜想類似的歷史將與rake例如。




我認為最可能的解釋是有幾個因素阻礙了Java社區在關鍵時期(90年代後期)使用make:

  1. 由於Java包含多個平台,所以Java程序員通常不像Unix工具那樣熟練,程序員通常只限於Unix環境(例如,C和Perl程序員)。 請注意,這是一般情況。 毫無疑問,有很多天才的Java程序員對Unix有深刻的理解。
  2. 因此他們不善於製作,也不知道如何有效地使用製作。
  3. 儘管可以編寫一個簡短的Makefile來高效地編譯Java,但需要特別注意以獨立於平台的方式來完成。
  4. 因此,對內在平台無關的構建工具有著極大的興趣。
  5. 正是在這種環境下,Ant和後來的Maven才被創造出來。

簡而言之,儘管肯定可以用於Java項目,但還有一段時間可以讓它成為事實上的Java構建工具。 那一刻已經過去了。




除非我沒有人假設沒有人(錯)使用make for java是錯誤的。

“使用GNU Make管理項目”(根據GFDL提供)包含一個完整的章節,專門介紹如何使用make項目。

由於它包含了使用make而非其他工具的優點和缺點的長期(並希望是公平的)列表,因此您可能需要查看一下。 (見: http://oreilly.com/catalog/make3/book/ : http://oreilly.com/catalog/make3/book/




實際上,make可以在所有過時的java文件的一個命令中處理重新編譯。 如果您不想編譯目錄中的所有文件或想要特定順序,請更改第一行...

JAVA_FILES:=$(wildcard *.java)
#
# the rest is independent of the directory
#
JAVA_CLASSES:=$(patsubst %.java,%.class,$(JAVA_FILES))

.PHONY: classes
LIST:=

classes: $(JAVA_CLASSES)
        if [ ! -z "$(LIST)" ] ; then \
                javac $(LIST) ; \
        fi

$(JAVA_CLASSES) : %.class : %.java
        $(eval LIST+=$$<)



簡答:因為make不好。 即使在C方面,你也會看到許多備選方案出現。

長答案: make有幾個缺陷,使它幾乎不適合編譯C,並且不適合編譯Java。 如果需要,您可以強制它編譯Java,但可能會遇到問題,其中一些問題沒有適當的解決方案或解決方法。 這裡有幾個:

依賴性解決方案

固有地期望文件彼此具有樹狀依賴關係,其中一個文件是構建其他幾個文件的輸出。 處理頭文件時,這已經在C中反彈了。 make需要生成make -specific包含文件來表示C文件對其頭文件的依賴性,因此對後者的更改會導致先前被重建。 但是,由於C文件本身並未重新創建(僅重建),因此經常需要將目標指定為.PHONY 。 幸運的是,GCC支持自動生成這些文件。

在Java中,依賴關係可以是循環的,並且在make格式中沒有自動生成類依賴關係的工具。 相反, antDepend任務可以直接讀取類文件,確定它導入的類,並刪除類文件,如果其中任何類過期。 否則,任何不平凡的依賴可能會導致您被迫使用重複的干淨構建,從而消除使用構建工具的任何優勢。

文件名空間

雖然Java和C都不鼓勵在你的源代碼文件名中使用空格,但在這種情況下,即使空格在文件路徑中,這也可能成為問題。 例如,考慮您的源代碼是否存在於C:\My Documents\My Code\program\src 。 這足以打破make 。 這是因為將文件名稱視為字符串。 ant將路徑視為特殊對象。

掃描構建文件

make要求明確設置為每個目標構建哪些文件。 ant允許指定要為源文件自動掃描的文件夾。 這可能看起來很不方便,但考慮到在Java中,每個新類都需要一個新文件。 將文件添加到項目可能會變得非常麻煩。

最大的問題在於:

make是POSIX依賴的

Java的座右銘是“編譯一次到處運行”。 但是,將編譯限制在基於POSIX的系統中,其中Java支持實際上是最糟糕的,但這並非意圖。

make中構建規則基本上是小型bash腳本。 儘管Windows有一個make端口,為了能夠正常工作,它必須與bash端口捆綁在一起,其中包括用於文件系統的POSIX仿真層。

這有兩種:

  1. MSYS試圖將POSIX轉換限制為文件路徑,因此在運行不是特別為其創建的外部工具時會產生不愉快的問題。

  2. cygwin提供了完整的POSIX仿真。 然而,結果程序往往仍然依賴於該仿真層。

出於這個原因,在Windows上,標準構建工具根本就沒有,但MSBuild也是基於XML的工具,原則上更接近於ant

相比之下, ant是用Java構建的,可以在任何地方運行,並且包含稱為“任務”的內部工具,用於以獨立於平台的方式處理文件和執行命令。 它具有足夠的通用性,使您可以更輕鬆地在Windows中使用ant構建C程序,而不是使用make

最後一個小小的一個:

即使C程序本身不使用make

您最初可能不會注意到這一點,但C程序通常不附帶Makefile 。 它們附帶一個CMakeLists.txt或一個bash配置腳本,用於生成實際的Makefile 。 相比之下,使用ant構建的Java程序的源代碼隨附預先構建的ant腳本。 Makefile是其他工具的產物 - 這是多少make不適合自己構建的工具。 ant是獨立的,可以處理您的Java構建過程所需的所有內容,而無需任何額外的需求或依賴關係。

當你在任何平台上運行ant時,它只是工作(tm)。 你做不到。 這是令人難以置信的平台和配置依賴。




曾幾何時,我曾參與一個使用gmake的Java項目。 我的記憶很模糊,但是IIRC很難處理javac期望的軟件包目錄結構。 我還記得建立JAR文件是一件麻煩事,除非你有一些微不足道的東西。




我從來沒有使用Java項目的GNU Make,但我曾經使用jmk 。 可悲的是,它自2002年以來一直沒有更新。

它具有一些特定於Java的功能,但足夠小可以包含在源代碼tarball中,而不會顯著增加其大小。

現在,我只是假設任何Java開發人員與Ant共享代碼。