How to compile with a specified target using Makefile in Java? - java

I am trying to write a Makefile for my java project. My aim is to:
1. Compile with the target make-java
2. Run with the target run-java
I have seen on the Internet this example of the Makefile:
JFLAGS = -g
JC = javac
.SUFFIXES: .java .class
.java.class:
$(JC) $(JFLAGS) $*.java
CLASSES = \
Main.java \
Book.java \
Library.java
default: classes
classes: $(CLASSES:.java=.class)
clean:
$(RM) *.class
run-java:
java Main
My problem is the make-java target (1st option), when I try to change the:
.java.class:
$(JC) $(JFLAGS) $*.java
to
make-java:
$(JC) $(JFLAGS) $*.java
It doesn't work. Can you give me a solution on how to change it in order to compile with the following command: make make-java
Thanks

You can't change that rule. That is a suffix rule; it's basically a template that says "here's how to build a .class file from a .java file". The combination of the .SUFFIXES setting of .java .class and a rule with the special form .java.class has this effect.
If you change it, you remove make's understanding of how to build .class files.
You want to leave that alone and add this instead:
make-java: classes
to tell make that it should build all the .class files when make make-java is invoked.

Related

Makefile with Java

I realize the make isn't the best tool to be using with Java, but I just wanted to experiment with it. I have this script but I'm not sure why it isn't working:
JFLAGS = -g
JC = javac
SRC_DIR = $(PWD)
.SUFFIXES: .java .class
.java.class:
$(JC) $(JFLAGS) $*.java
CLASSES = \
$(SRC_DIR)/Fibonacci_Methods.java \
$(SRC_DIR)/Fibonacci_Methods_Test.java \
default: classes
classes:
$(CLASSES:.java=.class)
clean:
$(RM) *.class
I get this error:
/path/to/make_test/Fibonacci_Methods.class
/path/to/make_test/Fibonacci_Methods_Test.class
make: /path/to/make_test/Fibonacci_Methods.class: No such file or directory
make: *** [classes] Error 1
I'm not sure why. My understanding is that this script should define CLASSES, which should call .java.class target because I'm defining files ending with .java. I don't know the purpose of $(CLASSES:.java=.class) because I would have thought the compilation be done already before this step.
I have not yet compiled the java code, by the way (so I'm running make with .java files only, if that makes a difference).
This is wrong:
classes:
$(CLASSES:.java=.class)
Here you've defined a target with no prerequisites and recipe (which is supposed to be a command that is used to rebuild the target) that consists of a list of .class filenames, so you're getting the error you see because you can't "run" a list of .class files.
You want this:
classes: $(CLASSES:.java=.class)
which defines a target classes with a set of prerequisites which are the .class files you want to build, and no recipe because you don't want to create a target named classes.

How do I specify the path to any class in the makefile of a project?

I have a java project, with different directorys containing different classes. And I'm trying to create a makefile in the upper directory that links all the the classes and compiles de project.
So to reach class a, it should follow the path ./src/project/packageA/a.java, and to reach b, ./src/project/packageB/b.java. I have the following makefile:
JFLAGS = -g
JC = javac
JVM = javac
.SUFFIXES: .java .class
.java.class:
$(JC)$(JFLAGS)$*.java
CLASSPATH = .:./src/project
CLASSES = \
a.java \
b.java \
...
MAIN = Main
default: classes
classes: $(CLASSES:.java=.class)
run: $(MAIN).class
$(JVM)$(MAIN)
clean:
$(RM)*.class
Where CLASSES is a macro containing all the classes in the project. I've tried redefining the variable PATH for every directory, assigning vpath and directly specifying the path in every's class name. But none seems to work, I always receive the error message "there is no rule for building the object a.class, needed for 'classes'." This is my first time using makefile and I don't know how to proceed.
Thank you everyone.
Few minor fixes to move the project forward.
Fix the rule for compile - need spaces around JFLAGS
Use the input file for the build rule - so that it will include the full path name
Add vpath to tell the compiler where source files can be
.java.class:
$(JC) $(JFLAGS) $^
CLASSPATH = .:./src/project
vpath %.java src/project
It's not clear from the question where you want to place the object. Consider adding -d to specify target folder, and setting adding cp -d ... to specify the location for the run target. You will need to fix the run time to add spaces.

Java makefile that creates a folder for the classes

I'm trying without any success to create a java makefile that compiles the java source codes to classes which go in a specific folder. So far, I managed to get the classes but I am really having trouble understanding how to create a folder and place the classes in there.
Here's my code so far:
JC = javac
JVM = java
.SUFFIXES: .java .class
.java.class:
$(JC) *.java
default: .java.class
clean:
$(RM) *.class
I followed a lot of tutorials and still can't figure it out. Basically I have my .java files in my folder. When I run make, I would like the classes to go in /bin folder and if it doesn't exist it gets created
You cannot do what you want to do with suffix rules. You'll have to use pattern rules if you want the output to be placed in a different directory than the source. Pattern rules are a feature of GNU make so hopefully you're using that (you don't say).
Plus, the way you're using suffix rules is not right: you don't declare the suffix rule itself as a prerequisite. You declare the actual files you want to build as prerequisites.
Also, make cannot do this by itself: you have to tell your compiler where to put the output. I'm not a Java person so I can't help you with that. Check your manual.
Your recipe builds all the .java files with a single invocation, which is not really how make works: make wants to translate a single source file (plus possibly other header files etc.) into a single output file.
Replace your suffix rule:
.SUFFIXES: .java .class
.java.class:
$(JC) *.java
with a pattern rule:
$(OUT)/%.class : %.java
mkdir -p $(#D)
$(JC) -o $# $<
(I have no idea if -o is right for javac: as I said you'll have to consult your Java manual). You don't need to declare .SUFFIXES when you use pattern rules.
Then, declare your default target to depend on the output files you want to be generated:
classfiles := $(wildcard *.class)
default: $(classfiles:%.class=$(OUT)/%.java)

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.

JDBC in makefile

I'm trying to write a makefile for a java project as below. I have a database connected (installed and tested working when I compile with another IDE instead of javac). I am not sure how to write the driver into makefile. For the following makefile, after typing make, I got message: package com.mysql.jdbc does not exist. But I have mysql-connector-java-5.1.16-bin.jar in the same folder as my makefile.
JFLAGS = -g
JC = javac\
.SUFFIXES: .java .class
.java.class:
$(JC) $(JFLAGS) $*.java
JavaLibraries = \
mysql-connector-java-5.1.16-bin.jar
CLASSES = \
DBMain.java\
Update.java\
server.java\
Client.java
default: classes
classes: $(CLASSES:.java=.class)
clean:
$(RM) *.class
Thanks for any input.
I cannot emphasize enough that Java and make doesn't fit well together. It's likely you will run into serious problems by building a Java project with make.
However, if you really want to use make, despite all warnings, then you have to adjust the classpath settings for the Java compiler:
JFLAGS = -g
JC = javac
CLASSPATH=mysql-connector-java-5.1.16-bin.jar:.
.SUFFIXES: .java .class
.java.class:
$(JC) $(JFLAGS) -cp $(CLASSPATH) $*.java
...
So the CLASSPATH consists of all used JARs and the package root directory of your *.java files (I assumed that is the current directory), separated by a colon on Unix/Linux systems or semicolon on Windows. Then in the .java.class rule you have to call the Java compiler with the -cp flag to pass the classpath.
This Database Schema Definition Language project contains an exemplary build.xml that shows how to initialize and test a database via JDBC. Note that ant targets are perfectly fine as make commands.
Addendum:
I need is write a makefile for others to use.
This other answer shows a good example of invoking javac directly from a makefile. It shows how to include the classpath, which may solve your immediate problem; but the approach rapidly becomes unwieldy for more elaborate builds, such as those including packages. This can be somewhat mitigated by using the subst function:
PKG = com.name.util
PKG_PATH = $(subst .,/,$(PKG))
A far simpler scheme is to write a minimal ant target, such as <target name="compile"…>, as shown here; then the corresponding make command is simple:
.SUFFIXES: .java .class
.java .class:
ant compile
Certainly, the makefile now depends on ant, but ant is fairly ubiquitous.

Categories

Resources