How Javac works

R

Roedy Green

I have been reorganising my entire code base so that dependencies
don't force me to use Java 1.5 when I don't really need it.

I have discovered something that surprised me.

If I delete all the class files in the universe, and compile one class
that references all sorts of other packages, the compile seems
completely happy, but when it comes time to jar to bundle in code from
other packages, the class files are not there yet.

So it looks as if Javac peeked at the source, compiled it enough to
deduce method signatures, but did not leave a class file behind.

I wonder if there is some other explanation for my observations.

I had thought java would automatically recompile and out of date class
files from other packages when it went to check the signatures.

This may explain why it sometimes feels as though my code changes
don't "take" right away. It takes multiple compiles to propagate
them.

--
Bush crime family lost/embezzled $3 trillion from Pentagon.
Complicit Bush-friendly media keeps mum. Rumsfeld confesses on video.
http://www.infowars.com/articles/us/mckinney_grills_rumsfeld.htm

Canadian Mind Products, Roedy Green.
See http://mindprod.com/iraq.html photos of Bush's war crimes
 
J

Joan

Roedy Green said:
I have been reorganising my entire code base so that dependencies
don't force me to use Java 1.5 when I don't really need it.

I have discovered something that surprised me.

If I delete all the class files in the universe, and compile one class
that references all sorts of other packages, the compile seems
completely happy, but when it comes time to jar to bundle in code from
other packages, the class files are not there yet.

So it looks as if Javac peeked at the source, compiled it enough to
deduce method signatures, but did not leave a class file behind.

I wonder if there is some other explanation for my observations.

Maybe it is looking at the "import" statements.
 
E

E.Otter

javac is not a build program like make or ant. It does not check if a
..class file is out of date and recompile it. When you compile java code
that references other classes, javac will check the classpath for those
class files. If it finds a required class, even a horribly out-of-date
file, it will use it. If it can't find a required class at all, but can
find a .java file in a directory where the .class should be, it will compile
that other java code too.

If you want that a sophisticated build tool for Java code check out ant at
http://ant.apache.org
 
H

Hemal Pandya

Roedy said:
I have been reorganising my entire code base so that dependencies
don't force me to use Java 1.5 when I don't really need it.

I have discovered something that surprised me.

If I delete all the class files in the universe, and compile one class
that references all sorts of other packages, the compile seems
completely happy, but when it comes time to jar to bundle in code from
other packages, the class files are not there yet.

If the class files were not generated by javac then it was able to find
the class definition somewhere in classpath. Since you deleted all the
classfiles, it must be one of the jars in the classpath. May I suggest
jwhich, which is trivial but useful.

[....]
I had thought java would automatically recompile and out of date class
files from other packages when it went to check the signatures.
Not out of date, but it will (try to) compile from source if it can't
find the class file.
This may explain why it sometimes feels as though my code changes
don't "take" right away. It takes multiple compiles to propagate
them.

I don't think it does. Try the -verbose switch with javac. The output
might be large, but look for the missing class -- the one that did not
make it into the jar. The "loading" line will show where javac found it.
 
D

Dale King

E.Otter said:
javac is not a build program like make or ant. It does not check if a
..class file is out of date and recompile it. When you compile java code
that references other classes, javac will check the classpath for those
class files. If it finds a required class, even a horribly out-of-date
file, it will use it. If it can't find a required class at all, but can
find a .java file in a directory where the .class should be, it will compile
that other java code too.

That's not true. It will also compile out of date files if it finds both
the source and the class file. From the javac documentation:

"Search produces both a source file and a class file: javac determines
whether the class file is out of date. If the class file is out of date,
javac recompiles the source file and uses the updated class file.
Otherwise, javac just uses the class file."

That doesn't mean everything is rebuilt. Consider if I have three java
files so that A depends on B and B depends on C. If A and C are out of
date but B is not and you compile A.java then C will not get rebuilt. If
B were out of date then all three would be compiled.
If you want that a sophisticated build tool for Java code check out ant at
http://ant.apache.org

Ant is no more sophisticated than javac in this regard. It is trivial to
have Ant say everything is OK, yet have things not be recompiled that
need to be.
 
H

Hemal Pandya

Dale said:
E.Otter wrote:

Ant is no more sophisticated than javac in this regard. It is trivial to
have Ant say everything is OK, yet have things not be recompiled that
need to be.

The Ant optional task Depend is slightly more sophisticated, but it too
has subtle and important limitations.

One argument I have often heard is: When it doubt rebuild all, javac is
very fast anyway.
 
T

Tim Tyler

Hemal Pandya said:
One argument I have often heard is: When it doubt rebuild all,
javac is very fast anyway.

One argument I have often heard is to use Eclipse or JavaMake,
which know how to keep track of dependencies, and - unlike
javac - have the intelligence to avoid leaving your project
in an inconsistent mess.
 
D

Dale King

Hemal said:
The Ant optional task Depend is slightly more sophisticated, but it too
has subtle and important limitations.

One argument I have often heard is: When it doubt rebuild all, javac is
very fast anyway.

And in my opinion if you ever have to do a "make clean" in order to get
a correct build then your build system is broken. I don't know of any
command line build system for Java that isn't slightly broken.

Eclipse is the least broken build system that I know of as long as you
aren't chaging your source files without its knowledge.
 
R

Roedy Green

That doesn't mean everything is rebuilt. Consider if I have three java
files so that A depends on B and B depends on C. If A and C are out of
date but B is not and you compile A.java then C will not get rebuilt. If
B were out of date then all three would be compiled.

there are two reasons for a class file to be out of date:

obvious -- its date is not after the source file date.

subtle -- some class file it depends on has changed, e.g. a method
changed from m( char ) to m( int ), or the value of some static final
has changed, e.g. flipping DEBUGGING = true to DEBUGGING = false.
The code to call it needs to be regenerated.

Javac will handle obvious, but not the subtle, right?

--
Bush crime family lost/embezzled $3 trillion from Pentagon.
Complicit Bush-friendly media keeps mum. Rumsfeld confesses on video.
http://www.infowars.com/articles/us/mckinney_grills_rumsfeld.htm

Canadian Mind Products, Roedy Green.
See http://mindprod.com/iraq.html photos of Bush's war crimes
 
D

Dale King

Roedy said:
there are two reasons for a class file to be out of date:

obvious -- its date is not after the source file date.

I really wish the world would move beyond this fantasy that the dates on
files only go forward and not backwards. This notion of just doing a
greater than comparison between the source and the object is not
sufficient in my mind for a build system.

I have this problem now at work. In this case it is with C++ and make. I
can check things out from ClearCase and build. But if I decide that I
don't want to check the changes in and just revert back to what is in
ClearCase, I'll uncheckout the file but the file date goes back to the
date it was checked in. Make won't rebuild the file because it went back
in time.

The problem is that to solve this you must save information about the
build to overcome this. For every generated file you would have to keep
a record of its timestamp and the timestamp of all its dependencies.
Then when building again if any timestamp has changed then you rebuild.
subtle -- some class file it depends on has changed, e.g. a method
changed from m( char ) to m( int ), or the value of some static final
has changed, e.g. flipping DEBUGGING = true to DEBUGGING = false.
The code to call it needs to be regenerated.

Javac will handle obvious, but not the subtle, right?

If you compile A.java it will recompile any file that A references whose
class file is older than its source. The issue is that it doesn't spider
its way out to anything beyond a file that is up to date.

So while A may depend on B and B is up to date with its source file
there may be a hundred files that B depends on that are out of date but
they won't be checked because the analysis stops at B because B was up
to date.
Bush crime family lost/embezzled $3 trillion from Pentagon.
Complicit Bush-friendly media keeps mum. Rumsfeld confesses on video.

Please stop repeating this off-topic lie that has no business in this group!
 
M

Mike Schilling

I really wish the world would move beyond this fantasy that the dates on
files only go forward and not backwards. This notion of just doing a
greater than comparison between the source and the object is not
sufficient in my mind for a build system.

I have this problem now at work. In this case it is with C++ and make. I
can check things out from ClearCase and build. But if I decide that I
don't want to check the changes in and just revert back to what is in
ClearCase, I'll uncheckout the file but the file date goes back to the
date it was checked in. Make won't rebuild the file because it went back
in time.

That's a problem with ClearCase. SCM systems that are either archive-based
(RCS, SCCS) or client-server (RCS, Perforce) wouild, on uncheckout, produce
a client file whose date is "now". I agree, producing a build system that
works with ClearCase's odd semantics would be tricky.

My pet peeve is that build systems are generally unable to determine that a
source file has been deleted, and to remove the .class file and rebuild the
..jar file (or .o file and .a file) accordingly.
 
M

Mike Schilling

That's a problem with ClearCase. SCM systems that are either archive-based
(RCS, SCCS) or client-server (RCS, Perforce)

That should read "client-server (CVS, Perforce)".
 
D

Dale King

Mike said:
That's a problem with ClearCase. SCM systems that are either archive-based
(RCS, SCCS) or client-server (RCS, Perforce) wouild, on uncheckout, produce
a client file whose date is "now". I agree, producing a build system that
works with ClearCase's odd semantics would be tricky.

ClearCase is just one way such things happen. I could get the same
result if I made a copy of the file I was going to edit and when done I
delete the old one and rename the copy back to the original.

For ClearCase dynamic views ClearCase's omake actually works as I
described and keeps a record of what files were read to produce an
output and if any changed rebuilds it.
My pet peeve is that build systems are generally unable to determine that a
source file has been deleted, and to remove the .class file and rebuild the
..jar file (or .o file and .a file) accordingly.

That's the sort of thing that could be handled by a system like I
described. It would have records of everything that went into building it.

The only way such a system would work with Java is to be tied into the
compiler however.
 
T

Tim Tyler

Roedy Green said:
there are two reasons for a class file to be out of date:

obvious -- its date is not after the source file date.

subtle -- some class file it depends on has changed, e.g. a method
changed from m( char ) to m( int ), or the value of some static final
has changed, e.g. flipping DEBUGGING = true to DEBUGGING = false.
The code to call it needs to be regenerated.

Javac will handle obvious, but not the subtle, right?

Javac doesn't even handle the obvious - unless there's a
chain of references in out-of-date class files leading
from the file you told it to compile to all the ones
that are out of date.

What /would/ handle the obvious is Javac plus a build system that
fed it a list of out-of-date files. However that would not
deal with the subtle - for that you need a slightly more intelligent
tool that knows about class dependencies.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,585
Members
45,080
Latest member
mikkipirss

Latest Threads

Top