简体   繁体   中英

Java Makefile always rebuilds, even when no changes were made

My makefile always rebuilds the project, even if no changes were made.

How can I fix it?

My project structure follows the usual bin/, src/, Makefile pattern.

Makefile:

# output directory
BIN = bin/

# input directory
SRC = src/

# java compiler
JC = javac

# compile flags
JFLAGS = -d $(BIN) -cp $(SRC)

sourcefiles = $(addprefix $(SRC), \
  A.java \
  B.java \
  C.java)

classfiles = $(sourcefiles:.java=.class)

all: $(classfiles)

%.class: %.java
  $(JC) $(JFLAGS) $<

clean:
  $(RM)  $(BIN)*.class

I made this makefile from examples I found online, but I'm not sure I understand everything being done, so if I could also get an explanation, that would be great :3

In general, make is not a good fit for Java. Make works best with tools that behave similarly to traditional compilers: they take an input file foo.X (and maybe some other input files as well) and they generate a single output file foo.Y . For a C compiler for example X is c and Y is o ( foo.c compiles to foo.o ).

Make is hard to use in situations where a single invocation of the compiler generates more than one output file, and it's not simple to use when the name of the output file doesn't relate directly to the name of the input file (in this case you have to write all explicit rules, not pattern rules).

For Java compilers a single .java input file can generate multiple different .class files, and the names of the .class files are not necessarily related to the name of the .java file.

In your situation, I'll bet if you look at the output files that javac is generating for your A.java file you'll see it's not generating A.class . Because A.class doesn't exist, make will always try to rebuild it.

Oh. Also. You're putting files in different directories. So even if you DO restrict yourself to situations where the names are identical, you have to write your pattern like this:

# ... Keep the first part as in your example

classfiles = $(patsubst $(SRC)%.java,$(BIN)%.class,$(sourcefiles))

all: $(classfiles)

$(BIN)%.class : $(SRC)%.java
        $(JC) $(JFLAGS) $<

# ... Keep the clean rule as in your example

The patterns % must be identical; if you put things in different directories they're not identical.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM