1

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

2 回答 2

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

于 2012-12-04T06:48:44.140 回答
0

问题是您不应该将“*.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)

测试.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)
于 2012-12-04T12:30:49.103 回答