javac makefile重新编译每个'make'

时间:2012-12-04 05:47:57

标签: java compilation makefile javac

知道为什么这个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

2 个答案:

答案 0 :(得分:2)

为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文件。

答案 1 :(得分:0)

问题是你不应该使用" * .java"作为目标,但应将其用作每个相关的" * .class"的依赖项。否则,就像你的"尝试2",当目标是一个没有依赖关系的文件时,它将不会重建,并且总是大喊“#34;最新的"。

主要思想是告诉你的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();
  }
}

Ref.java:

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

我想和我分享更简单的&#39;这里的模板(你只需要添加文件名和依赖项):

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)