How can this src vs. build tree timestamp comparison be faster?

292 views Asked by At
for n in `cd src; find . -name "*.java"; cd -`;
  do a=`echo $n | cut -d '.' -f2`;
  if [[ src/$a.java -nt build/$a.class ]];
    then echo src/$a.java;
  fi;
done

It lists all the java files in the src tree; then for each one, it removes the suffix ".java" (cut -d '.' -f2 because find . output is prefixed with .). It then uses -nt to test if the java file in the src tree is newer than the corresponding class file in the build tree; if it is newer, it is output. [javac can then use this to compile only the needed src files, instead of using ant or make]

The problem is that it is too slow, taking about 275ms. How to make it faster?

Or is there a faster way to do this in bash? I can't see how to do it with find, diff, rsync nor make (which doesn't seem to traverse trees automatically, and needs explicitly listed source files).

4

There are 4 answers

4
kon On BEST ANSWER

try this:

for f in src/*.java; do 
  file=`basename $f`; 
  if [[ src/$file -nt build/${file//.java/} ]]; then 
     echo src/$file; 
  fi; 
done 
3
13ren On

Adopting kon's approach to the filename munging, the speed improves from 320ms to 45ms on average. Thanks kon!

for n in `cd src; find . -name "*.java"; cd -`; do
  if [[ src/$n -nt build/${n/.java/.class} ]];
     then echo src/$n;
  fi;
done

The original is a bit slower now (was 275ms; now 320ms); I don't know why. I'm using the same line. Maybe different system sources after playing a video.

EDIT re rst's comment: mangling the "src/" away instead of cd src; ... cd -;. Note that both $n and $n2 are used [you can't nest the ${var/A/B} construct, can you?]

for n in `find src -name "*.java"`; do
  n2=${n/src/}
  if [[ $n -nt build/${n2/.java/.class} ]];
     then echo $n;
  fi;
done
2
Maxim Veksler On

ant performs smart building logic, it will not build a class unless the source was modified.

You might also like to look into scons which is not a native Java build tool but is very handy at compiling efficient complex build trees and does have java builder as well.

5
Dennis Williamson On

I don't know if this structure would be any faster, but it might be worth a try:

while read n
do
     # capture the basename all at once
     [[ $n =~ src/(.*)\.java ]]   # escape the parentheses for Bash < 3.2 (or thereabouts)
     [[ $n -nt "build/${BASH_REMATCH[1]}.class" ]] && echo $n
done < <(find src -name "*.java")

The while form probably won't provide any boost. The collapsed if may. The regex might provide a small contribution.

As you've found out, eliminating a call to cut has made the biggest difference.