I'm not sure what this minimal recompile which we were discussing is. It
is technically impossible to do a true minimal recompile
algorithmically. Let's define it as "Let a build be a set of file
compilations. Let the minimum recompile be the minimum such set for
which the output class file are equivalent to the class files of a full
clean build." First, we'd have to prove such a minimum exists. That's
relatively straightforward.
Extremely so.
With that out of the way, I think I could then prove that the problem is
equivalent to the Halting problem.
Certainly not.
If you define "equivalent" generously, I'm pretty sure this is the case.
If you define it as "same binary file content", then perhaps not, though
still possibly yes.
I'm not sure what you mean by 'generously'. Is there a kind of equivalence
less strict than binary equivalence which would actually work?
Anyway, here's a straightforward but slow algorithm to find the minimal
recompile:
1. Copy all your source code somewhere and do a clean build on it; call
the output the reference output
2. Count your source files, and call the total number N
3. Number all your source files, starting at 0 and going up to N
4. Let M be the set of all source files
5. For each integer i between 0 and 2**N - 1:
6a. Let S be the set of source files for whose number j, the jth bit in i
is set
6b. Do a recompilation of just the files in S
6c. Compare the output to the reference output, and if it is identical,
and the size of S is smaller than the size of M, let M be S
6d. Restore the class files to how they were before recompilation
S now contains the set of source files needed for a minimal recompile. It
doesn't follow from this algorithm that it's the only minimal set,
although i suspect that in practice it will be.
I wouldn't suggest you do this in practice, but it shows that the minimal
set exists, can be found algorithmically, and can be found in O(2**N)
time, with a rather large constant. Your task is thus merely to improve
the speed!
Either way, this is not my goal. If someone modifies comments to a Java
source file, I'm not going to try and catch that. What I will do is
recompile all files which depend directly on that changed-source Java
file, any files affected by Ghost Dependencies, and continue cascading
this change down until all of the "leaves" of the cascading recompile
are binary equivalent class files to the class files before the
recompile. Perhaps too conservative, but I think that's easy enough to
show that it's correct.
Agreed. If you were a bit more aggressive about the consequentiality of
changes, you could prune off a lot of the leaves of the tree, but it
wouldn't be an asymptotic speedup.
That said, i don't think it would be that hard to work out
consequentiality. The output of javap is almost exactly what you need - i
think the only thing it's missing is those bloody constant values. Adding
them doesn't look hard. This is the relevant bit of javap's source:
https://openjdk.dev.java.net/source...s/javap/JavapPrinter.java?rev=257&view=markup
You need to change the line that says:
out.println(fields[f].getType()+" " +fields[f].getName()+";");
To say:
int cpx = fields[f].getConstantValueIndex();
if (cpx == 0) out.println(fields[f].getType()+" " +fields[f].getName()+";");
else out.println(fields[f].getType()+" " +fields[f].getName()+" = "+cls.getCpoolEntryobj(cpx)+";");
That adds the value of any compile-time constants to the output. I'm not
sure if it will also add values to instance fields which have initial
values; i think those are handled in the constructors, rather than as
ConstantValue attributes.
You could then compare the output of javap, or hashes of that output, to
determine if the interface of the class had changed. If it hasn't, then
any changes to the class file are inconsequential in terms of
recompilation.
Unless i've missed something. Notably absent from javap output is
annotations - can the annotations on a class affect compilation of other
classes which refer to it? @Override only affects the declaring class.
@Deprecated could affect another class, but could only cause a warning to
be generated.
Perhaps I'll make it a "tighter fit" later, though honestly I'm still
fumbling around in the dark at the moment, still learning.
PROTIP: that phase never actually ends.
tom