Java Makefile Error - java

I'm having this error when trying to compile my Java project with a Makefile I created.
Error:
make: No rule to make target src/edu/osu/lispinterpreter/output/*.class', needed byclasses'. Stop.*
Makefile content:
JFLAGS = -g
JC = javac
.SUFFIXES: .java .class
.java.class:
$(JC) $(JFLAGS) $*.java
CLASSES = \
src/edu/osu/lispinterpreter/tokenizer/*.java \
src/edu/osu/lispinterpreter/core/*.java \
src/edu/osu/lispinterpreter/output/*.java \
src/edu/osu/lispinterpreter/exceptions/*.java \
src/edu/osu/lispinterpreter/input/InputParser.java \
src/edu/osu/lispinterpreter/input/ReadInputString.java
default: classes
classes: $(CLASSES:.java=.class)
clean:
$(RM) *.class
Can someone give me a hand with the Makefile please?
I'm using Eclipse btw.

From http://www.gnu.org/software/make/manual/html_node/Wildcard-Pitfall.html#Wildcard-Pitfall
When a wildcard matches no files, it is left as it is
It seems src/edu/osu/lispinterpreter/output is empty, so src/edu/osu/lispinterpreter/output/*.java does not match any file and is left as it is, which is not what is intended. Using the wildcard function, this can be avoided.
The solution would be to replace
src/edu/osu/lispinterpreter/output/*.java
by
$(wildcard src/edu/osu/lispinterpreter/output/*.java)
and so on for all the other lines, I think

You either list all the source files individually or use the wildcard directive in Makefile to automatically match the files instead.
Also from your comments it looks like the package names for the java files are edu.osu.lispinterpreter.*.
So I would suggest to move the Makefile to the src directory and make these changes in the Makefile.
CLASSES := $(wildcard edu/osu/lispinterpreter/tokenizer/*.java)
CLASSES += $(wildcard edu/osu/lispinterpreter/core/*.java)
CLASSES += $(wildcard edu/osu/lispinterpreter/output/*.java)
CLASSES += $(wildcard edu/osu/lispinterpreter/exceptions/*.java)
CLASSES += edu/osu/lispinterpreter/input/InputParser.java
CLASSES += edu/osu/lispinterpreter/input/ReadInputString.java
The java compiler should be able to pick up definitions of classes from other packages as long as the package name corresponds to the directory structure without writing any explicit dependencies in the Makefile.

I think that the problem is that your use of * in the CLASSES variable. The way you have written that variable, it is being populated with a list of "file names" that have * characters in them ... which will propagate through the rest of the processing.
You either need to list the classes individually, or do something to tell Make to "glob" the list. If you are using GNU Make then the wildcard function should do the trick.
But note that won't work on other versions of Make, so you've got a Makefile portability problem. (Which brings me back to my comment that Ant is better.)
And once you've gotten past that, you have the problem that if you are compile Java classes one at a time:
your build will be really slow ... 'cos each javac command incurs a JVM startup (assuming you are using the Hotspot or OpenJDK tool chains),
you have to build the classes in the right order ... according to the dependencies inherent in the source code,
you have to add those dependencies to the Makefile (!!!), and
if you have dependency cycles, you've got problems!
With enough patience, you could build a Makefile that coped with this, but it is really tricky, and the resulting Makefile will be fragile. Realistic alternatives are:
just build all of the /.java files in one javac command, irrespective of dependencies,
add a "make depend" rule that uses something to analyse the source code or bytecode files and generate the dependencies in the Makefile.
Or just use Ant.
References:
Why is no one using make for Java?
A Java / Make dependency generator - http://ptolemy.eecs.berkeley.edu/~cxh/java/javadepend/
Another Makefile generator for Java - http://www.tildeslash.com/mmake/mmake.html

Related

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.

About this servlet + tomcat example, can not compile servlet using javac

I am currently following the book Head First Servlets and JSP, and I got to the point on page 81 where the author asks to compile the servlet using javac.
I am having problems to execute that line of code. I think that my JAVA_HOME and etc must be set up correctly since I created a sample HelloWorld.java and
compiled it useing javac and it created the correspondent .class file.
I am failing to see the logic of this command, you specify a class path to the servlet-api.jar file and then you give it another path so it can execute the .java file?
I would like to get out of this hole I am in right now. These are the paths to my files:
C:\Users\Carlos L\Tomcat\apache-tomcat-8.0.28\bin\servlet-api.jar
and this is where my BeerSelect.java file is:
C:\Users\Carlos L\Tomcat\My Tomcat Projects\beer-v1\src\com\example\web\BeerSelect.java
so far i have been imputing:
javac -classpath C:\Users\Carlos L\Tomcat\apache-tomcat-8.0.28\bin\servlet-api.jar; classes:. d-classes src\com\example\web\BeerSelect.java
and I am getting this error:
javac: invalid flag: d-classes
usage:javac
This should not be this hard.
First, yes it is valid to compile against one jar and later run against a different one(s). In particular a jar named something-api.jar usually contains only the classes that constitute the Application Program Interface aka API, and is sufficient to compile programs that want to call something, but actually executing those calls requires additional internal classes that are packaged in jars using various names such as something-impl, something-body, plain something, or multiple jars such as something-basic something-core something-addon something-option etc.
Second, your book is apparently using the common (but not required or universal) scheme where the java source code files and compiled class files are in separate, parallel subtrees here named src and classes. Your particular sourcefile is apparently src\com\example\web\BeerSelect.java. The syntax to run the java compiler for this case is:
javac -classpath (classpath) -d classes src\com\example\web\BeerSelect.java
# or abbreviate -classpath as -cp, or use envvar CLASSPATH instead
That's hyphen then d, then a space, then the directory name here classes, then another space and the sourcepath (or multiple sourcepaths).
You shouldn't need to specify classes in the classpath initially, only the servlet-api.jar file. If you later compile some but not all sourcefiles of the src subtree, and previously-compiled classfiles for other sourcefiles are already in the classes subtree, you do need both the servlet-api.jar and the classes directory. On Windows you separate classpath entries by semicolon ; and on Unix you use colon : but you should never mix them. So your case would include:
javac -classpath \path\to\servlet-api.jar;classes (rest as above)
except that your path name apparently includes a space C:\users\Carlos L\... so you must put the value in quotes:
javac -classpath "C:\users\Carlos L\tomcat-8.0.28\bin\servlet-api.jar;classes" (rest as above)`
As an alternative to typing this numerous times, you can put the value in envvar CLASSPATH
set CLASSPATH="C:\users\Carlos L\tomcat-8.0.28\bin\servlet-api.jar;classes"
and then simply do
javac -d classes src\com\example\web\BeerSelect.java
and similarly for any other classes in the the project as you come to them.

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.

Makefile to compile both C and Java programs at the same time

I have three programs that need to be compiled at the same time, 2 written in C and 1 in java. I had all three working with the Makefile when they were in C, but then rewrote one of them in java... is there a way to compile all 3 at once with the same makefile?
Here is my current Makefile:
CC=gcc
JC=javac
JFLAGS= -g
CFLAGS= -Wall -g -std=c99
LDFLAGS= -lm
.SUFFIXES: .java .class
.java.class:
$(JC) $(JFLAGS) $*.java
CLASSES = kasiski.java kentry.java
ALL= ic ftable kasiski
all: $(ALL)
ic: ic.o
kasiski: $(CLASSES:.java=.class)
ftable: ftable.o
ic.o: ic.c ic.h
ftable.o: ftable.c ftable.h
.PHONY: clean
clean:
rm -rf core* *.class *.o *.gch $(ALL)
Yes, you can compile them all at once. If your "all" target depends on all three applications, then "make all" should build all of them. You can throw in "-j3" to actually compile using three separate threads and/or processes (it isn't clear what you mean by "at once"). Also, a couple criticisms here:
Do not define "CC", "CFLAGS", or "LDFLAGS". You should never define "CC" as it is automatically defined for you to the default C compiler on the system, and you should merely append to "CFLAGS" and "LDFLAGS" as needed (using +=) instead of clobbering them, as simply assigning to them makes your Makefile inflexible (because they cannot be overrided or augmented externally).
Using CLASSES to refer to ".java" files is confusing as hell... you should probably rename the variable to JAVA_SRCS, and define JAVA_CLASSES=${JAVA_SRCS:.java=.class}.
For more explanation, please see my Makefile tutorial. That said, you may want to consider a more modern build system such as Bazel or Gradle. These systems are designed to be much simpler to use, less error prone, more portable (because they make it easier to do things portably), and faster.

Categories

Resources