【问题标题】:javac makefile re-compiling on every 'make'javac makefile在每个'make'上重新编译
【发布时间】:2012-12-04 05:47:57
【问题描述】:

知道为什么这个 makefile 会重新编译(不必要地)每个 .class 文件吗?另外,我认为它是相关的,java文件导入它们上面的文件。我已经尝试了 4 次并且浪费了几个小时来让它工作,而不是处理我项目的实际代码,所以任何帮助都会非常感激。

最近的尝试:

#########################################################################
#                                   #
# http://ieng6.ucsd.edu/~cs131f/makenotes.html              #
#                                   #
#########################################################################
JFLAGS      = -g -d
JC      = javac
.SUFFIXES   : .java .class
SRCDIR      = simpella
OUTDIR      = simpella/out

.java.class:
    $(JC) $(JFLAGS) $(OUTDIR) $*.java

#########################################################################
#
# example run: javac -g -d simpella/out simpella/simpella.java
#
#########################################################################

CLASSES = \
    $(SRCDIR)/Util.java \
    $(SRCDIR)/Converters.java \
    $(SRCDIR)/Connection.java \
    $(SRCDIR)/Simpella.java

default: classes

classes: $(CLASSES:.java=.class)

#########################################################################
clean:
    $(RM) -v simpella/out/simpella/*.class
    @- echo "Cleaned"

尝试 3...:

#########################################################################
#                                   #
# http://ieng6.ucsd.edu/~cs131f/makenotes.html              #
#                                   #
#########################################################################
JFLAGS      = -g -d
JC      = javac
.SUFFIXES   : .java .class
SRCDIR      = simpella
OUTDIR      = simpella/out

.java.class:
    $(JC) $(JFLAGS) $(OUTDIR) $*.java

#########################################################################
#
# example run: javac -g -d simpella/out simpella/simpella.java
#
#########################################################################

all: Simpella.java


Util.java:
    Util.java=Util.java
Converters.java:
    Converters.java=Converters.class
Connection.java: Converters.java Util.java
    Connection.java=Connection.class
Simpella.java: Connection.java Converters.java Util.java
    Simpella.java=Simpella.class
    @- echo "Done Compiling!!"



#########################################################################
clean:
    $(RM) -v simpella/out/simpella/*.class
    @- echo "Cleaned"

尝试 2...:

#########################################################################
#                                   #
# http://ieng6.ucsd.edu/~cs131f/makenotes.html              #
#                                   #
#########################################################################
JFLAGS      = -g -d
JC      = javac
.SUFFIXES   : .java .class
SRCDIR      = simpella
OUTDIR      = simpella/out

.java.class:
    $(JC) $(JFLAGS) $*.java

#########################################################################

#CLASSES = Simpella.java Connection.java Converters.java Util.java

all: Simpella.java


#example run: javac -g -d simpella/out simpella/simpella.java

Util.java:
    $(JC) $(JFLAGS) $(OUTDIR) $(SRCDIR)/Util.java
Converters.java:
    $(JC) $(JFLAGS) $(OUTDIR) $(SRCDIR)/Converters.java
Connection.java: 
    $(JC) $(JFLAGS) $(OUTDIR) $(SRCDIR)/Connection.java
Simpella.java: Util.java Connection.java Converters.java
    $(JC) $(JFLAGS) $(OUTDIR) $(SRCDIR)/Simpella.java
    @- echo "Done Compiling!!"

#########################################################################
clean:
    $(RM) -v simpella/out/simpella/*.class
    @- echo "Cleaned"

尝试 1...:

JFLAGS = -g -d
JC = javac
.SUFFIXES: .java .class
.java.class:
    $(JC) $(JFLAGS) $*.java

CLASSES = \
    simpella\Util.java \
    simpella\Converters.java \
    simpella\Connection.java \
    simpella\simpella.java 


default: classes

classes: $(CLASSES:.java=.class)
    @- echo "Done Compiling!!"

clean:
    $(RM) *.class

【问题讨论】:

    标签: java compilation makefile javac


    【解决方案1】:

    为 java 创建定义良好的 makefile 是一项复杂的任务,因为 a) 源文件和类文件位于不同的目录中,b) 这些目录是嵌套的,c) 源文件和类文件没有一对一的映射。然后,即使做得好的 makefile 也不会获得良好的性能,因为 make 实用程序会产生单独的进程来编译每个 java 文件。另一方面,java 编译器本身运行速度很快,具有嵌入式依赖检查,并且能够在单进程运行中编译数百个 java 文件。因此,make 实用程序不用于编译 java 文件。对于中小型项目,使用java编译器并将所有源文件传递给它。对于大型项目,请使用 Ant、Gradle 或其他支持 java 的构建工具。

    编辑:使用 javac 依赖检查,以这种方式运行:

      javac -d ${OUTDIR} -cp ${OUTDIR} -sourcepath ${SRCDIR} ${MAIN_JAVA_FILE_NAME}
    

    也就是说,只传递主 java 文件的名称,指向其他源文件所在的位置,指向类文件所在的位置两次:存储位置和检查存在的位置。 ${SRCDIR} 应该根据它们的包结构包含 java 文件。

    【讨论】:

      【解决方案2】:

      问题是你不应该使用“*.java”作为目标,而应该使用它作为每个相关“*.class”的依赖。否则,像你的“尝试2”,当目标是一个没有依赖的文件时,它不会被重建,并且会一直喊“最新”。

      主要思想是告诉你的make清楚地理解依赖关系。下面是一个测试用例,可以更简单地构建类文件,对于一个小项目来说是可以的(类 Test 将使用来自 Ref 的方法,因此它依赖于 Ref.class,我们应该手动添加它)。我希望在这个问题上得到更好的答案!!!但是对于大型项目,嗯,为什么不试试ant呢?

      生成文件:

      OBJ = ./obj/
      SRC = ./src/
      JARS = $(wildcard lib/*.jar)
      LIB = .:$(OBJ):$(shell echo '$(JARS)' | sed 's/jar /jar:/g')
      
      define make-target
          @echo + cc $<
          @javac -classpath $(LIB) $< -d $(OBJ) $*
      endef
      
      all: always ./obj/Ref.class ./obj/Test.class
      
      ./obj/Ref.class: ./src/Ref.java
          $(make-target)
      ./obj/Test.class:./src/Test.java ./obj/Ref.class
          $(make-target)
      
      run:
          @java -classpath $(LIB) Test
      always:
          @mkdir -p $(OBJ)
      

      Test.java:

      public class Test {
        public static void main(String argv[]) {
          Ref ref = new Ref();
          ref.run();
        }
      }
      

      参考.java:

      public class Ref {
        public void run() {
          System.out.println("hhhh");
        }
      }
      

      我想在这里分享我的“更简单”模板(您只需要添加文件名和依赖项):

      OBJ = obj
      SRC = src
      JARS = $(wildcard lib/*.jar)
      LIB = .:$(OBJ):$(shell echo '$(JARS)' | sed 's/jar /jar:/g')
      
      targets := $(wildcard */*.java)
      targets := $(patsubst %.java,%.class,$(targets))
      targets := $(notdir $(targets))
      targets := $(addprefix $(OBJ)/,$(targets))
      
      define build
          @echo + cc $<
          @javac -classpath $(LIB) $< -d $(OBJ) $*
      endef
      define extend 
          $(shell echo $1|sed 's/.class/.java/'|sed 's/$(OBJ)/$(SRC)/')
      endef
      
      all: always $(targets)
      
      .SECONDEXPANSION:
      $(OBJ)/Ref.class: $$(call extend, $$@)
          $(call build)
      $(OBJ)/Test.class:$$(call extend, $$@) $(OBJ)/Ref.class
          $(call build)
      
      run:
          @java -classpath $(LIB) Test
      
      
      .PHONY: clean always
      clean:
          @rm -rf $(OBJ)
      always:
          @mkdir -p $(OBJ)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-23
        • 2021-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多