Any idea why this makefile would re-compile (unnessesarily so) each .class file? Also, I think it is relevant, the java files import the files above them. I've tried this 4 times and wasted hours to get this to work, instead of working on the actual code of my project so any help would be really appreciated.
most recent attempt:
#########################################################################
# #
# 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"
Attempt 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"
Attempt 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"
Attempt 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
Creating well defined makefile for java is a complex task because a) source and class files are in different directories, b) those directories are nested, and c) there is no one-to-one mapping from source and class files. Then, even well-done makefile would not achieve good performance because make utility spawns separate process to compile each java file. On the other hand, java compiler itself works fast, has embedded dependence checking, and is able to compile hundreds of java files in single process run. As a result, make utility is not used to compile java files. For small and medium projects, use java compiler and pass all source files to it. For large projects, use Ant, Gradle or other java-aware build tool.
EDIT: to employ javac dependency checking, run it this way:
javac -d ${OUTDIR} -cp ${OUTDIR} -sourcepath ${SRCDIR} ${MAIN_JAVA_FILE_NAME}
That is, pass only the name of the main java file, point where other source files reside, point where class files reside twice: where to store and where to check for existence. The ${SRCDIR} should contatin java files according to their package structure.
The problem is that you should not use "*.java" as a target, but should use it as a dependency for each related "*.class". Otherwise, like your "Attempt 2", when the target is a file with no dependency, it will not be rebuild, and will always shout "up to date".
The main idea is to tell your make to understand the dependencies clearly. Below is a test case to make it simpler to build class files, it will be ok for a small project (class Test will use method from Ref, therefore it relies on Ref.class and we should manually add this). I hope better answers on this issue!!! But for large project, hmm, why not try ant instead?
Makefile:
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");
}
}
and I would like to share my 'simpler' template here(you just need to add file name and dependency):
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)
Related
I'm building a java program in Windows envoirment, but i need to be able to compile it in Linux envoirment. I'm currently having problems with the makefile:
the project folders are organized in this way:
project_folder
library.jar
src
folder1
a.java
b.java
folder2
c.java
d.java
folder3
e.java
The e.java file into folder3 is in almost all the others .java files because it's the principal struct, and for every file i have the line
import folder3.e;
Wich Eclipse automatically generates when i use a structure from another class file. What the terminal tells me:
error: Package folder3 does not exist
this is the makefile
JFLAGS = -g -cp library.jar -sourcepath .
JC = javac
.SUFFIXES: .java .class
.java.class:
$(JC) $(JFLAGS) $*.java
CLASSES = \
src/folder1/a.java \
src/folder1/b.java \
src/folder2/c.java \
src/folder2/d.java \
src/folder3/e.java
default: classes
classes: $(CLASSES:.java=.class)
clean:
find . -name "*.class" -type f -delete
It's my very first makefile for java and i think i'm wrongly including the references between classes, how i can solve this?
Thank you
UPDATE: #Karthikeyan Vaithilingam thank you for your detailed answer, now it's all clear and working!
Add -d . to JFLAGS so the class files will be created with proper folder structure.
So your JFLAGS should be as follows.
JFLAGS = -g -cp .:library.jar -sourcepath . -d .
-d is the flag is used for destination folder in the above example its the current folder. You can use any destination but don't forget to add it to the classpath using -cp. By using -d you can keep the source folders clean, also cleaning will be easy, just remove the destination folder.
Update
The problem is the order of the Java files in CLASSES section. Since folder3.e class is referred in other classes it has to be at the beginning. It should be like the below one.
CLASSES = \
src/folder3/e.java \
src/folder1/a.java \
src/folder1/b.java \
src/folder2/c.java \
src/folder2/d.java
Also you can keep the libraries in a separate folder then use -cp libs\* to add all the jars in the folder. It will be easy to maintain
So the folder structure will be
project_folder
libs
library.jar
src
folder1
a.java
b.java
folder2
c.java
d.java
folder3
e.java
And the final Makefile will be
JFLAGS = -g -cp ".:libs/*" -sourcepath . -d .
JC = javac
.SUFFIXES: .java .class
.java.class:
$(JC) $(JFLAGS) $*.java
CLASSES = \
src/folder3/e.java \
src/folder1/a.java \
src/folder1/b.java \
src/folder2/c.java \
src/folder2/d.java
default: classes
classes: $(CLASSES:.java=.class)
clean:
rm -r folder*
Unrelated
Why don't you use build tools Gradle or Maven or Ant?
I'm trying to compile java files with make.
My Makefile produces the following output when I run make.
make: *** No rule to make target `file1.class', needed by `classes'. Stop.
What's causing this error?
Here is my original Makefile
JFLAGS = -g
JC = javac
.SUFFIXES: .java .class
.java.class: $(JC) $(JFLAGS) $*.java
CLASSES = \
file1.java \
file2.java \
file3.java \
file4.java \
main.java
default: classes
classes: $(CLASSES:.java=.class)
clean: $(RM) *.class
I have a java project, and need to write makefile to let it run on Linux. My project includes external jar files and resource package(.txt resourses).I am really a newbie for Linux, and just learn how to write makefile.
I refer to some materials and write a makefile like this:
# Set the file name of your jar package:
JAR_PKG = ADBproject1.jar
# Set your entry point of your java app:
ENTRY_POINT = adb/Bing_WebResults/Run.java
# Need resource directory
RES_DIR = yes
SOURCE_FILES = \
adb/jsonModels/Metadata.java \
adb/jsonModels/Result.java \
adb/jsonModels/Data.java \
adb/jsonModels/DataContainer.java \
adb/models/Weight_ID.java \
adb/models/Pair.java \
adb/models/Document.java \
adb/models/Collections.java \
adb/Bing_WebResults/Bing_Search.java\
adb/Bing_WebResults/Run.java \
JAVAC = javac
JFLAGS = -encoding UTF-8
vpath %.class bin
vpath %.java src
# show help message by default
Default:
#echo "make new: new project, create src, bin, res dirs."
#echo "make build: build project."
#echo "make clean: clear classes generated."
#echo "make rebuild: rebuild project."
#echo "make run: run your app."
#echo "make jar: package your project into a executable jar."
build: $(SOURCE_FILES:.java=.class)
# pattern rule
%.class: %.java
$(JAVAC) -cp bin -d bin $(JFLAGS) $<
rebuild: clean build
.PHONY: new clean run jar
new:
ifeq ($(RES_DIR),yes)
mkdir -pv src bin res
else
mkdir -pv src bin
endif
clean:
rm -frv bin/*
run:
java -cp bin $(ENTRY_POINT)
jar:
ifeq ($(RES_DIR),yes)
jar cvfe $(JAR_PKG) $(ENTRY_POINT) -C bin . res
else
jar cvfe $(JAR_PKG) $(ENTRY_POINT) -C bin .
endif
But I don't know how to add those two external .jar files (gson.jar, commons.jar) into makefile. And I'm not quite sure, whether the file paths I wrote are correct.
javac has a -cp and -classpath argument:
-classpath <path> Specify where to find user class files and
annotation processors
-cp <path> Specify where to find user class files and
annotation processors
They seem to be equivalent as far as the documentation is concerned.
I solve the problem by adding all *.jar files to a new folder "lib".
Then
javac -sourcepath src/ -classpath lib/*.jar
will solve the external jar file problem.
I would like to create a runnable jar in the same manner in which eclipse does, but from CLI. I am using buildbot and I would like to be able to automatically create, for example, nightly builds automatically, but are also runnable.
My Makefile:
JFLAGS = -g
JC = javac
JAR = jar
JARFLAGS = cfe ./bin/java.jar alone.Gameloop -C resources . -C ./
.SUFFIXES: .java .class
.java.class:
$(JC) $(JFLAGS) $(wildcard alone/*.java)
#$(JC) $(JFLAGS) $*.java
CLASSES = \
$(wildcard alone/*.java) \
# alone/Enter.java \
# alone/GameLoop.java \
# alone/ImageRender.java \
# Blah.java \
# Library.java \
# Main.java
all: classes
default: classes
packages: jars
jars:
#echo $(JAR) $(JARFLAGS) $(CLASSES:.java=.class)
#false
$(JAR) $(JARFLAGS) $(CLASSES:.java=.class)
classes: $(CLASSES:.java=.class)
clean:
$(RM) *.class
Thanks for the help! :)
Your stuff looks okay all you have to do is add $(CLASSES) to the jars target as a dependency:
jars: classes
$(JAR) $(JARFLAGS) $(CLASSES:.java=.class)
and then make jars will do the stuff nightly
I need to make a makefile that compiles and executes my classes with an external jar file..
I have 4 classes;sync.java, FileSynchroniser.java, DirectoryTracer.java and SyncFileTracer.java.
I also need to include gson-1.7.1.jar ..
Heres my make file
.SUFFIXES: .class .java
JAVAC= $(JAVAHOME)\bin\javac
PATH=$(JAVAHOME)\bin;$(PATH)
CLASSPATH=.;$(JAVAHOME)\lib\classes.zip;$(JSDKHOME)\lib\classes.zip
DEST=.
DOC=.
JAVA=$(JAVAHOME)\bin\java
JAVACFLAGS=-deprecation
.SUFFIXES: .java .class
.java.class:
$(JAVAC) -classpath $(CLASSPATH) $(JAVACFLAGS) $<
CLASSFILES = sync.class \
FileSynchroniser.class \
DirectoryTracer.class \
SyncFileTracer.class
SOURCEFILES = sync.java \
FileSynchroniser.java \
DirectoryTracer.java \
SyncFileTracer.java
# begin ---- JAR support ----------
JARFILE= gson-1.7.1.jar
$(JARFILE): $(CLASSFILES) $(SOURCEFILES)
jar cfm0 $(JARFILE) <<manifest.tmp $(CLASSFILES)>>
# end ---- JAR support ----------
all : $(JARFILE) $(CLASSFILES) doc
doc : $(CLASSFILES)
javadoc -version -author -d $(DOC) $(SOURCEFILES)
install :
copy $CLASSESFILE $(DEST)
clean:
del $(CLASSFILES)
Thank you
Are you referring to making the makefile in a Linux OS?
Check this - make makefile guide
http://www.cs.swarthmore.edu/~newhall/unixhelp/howto_makefiles.html
or this - example
http://www.cs.swarthmore.edu/~newhall/unixhelp/javamakefiles.html
hope it help.