Thursday, May 14, 2009

Derby's clean targets are quite complex

I was puzzled by a mystifying build error in one of my Derby clients.

The problem arose in the runmessagecheck target, which is an internal build tool that cross-checks the internationalized message files against the message codes in and

In this particular Derby client, the cross-checks were failing.

I couldn't figure out anything different between this Derby client and my other Derby clients. It was, as I say, a mystifying build error.

Then, on a hunch, I noticed that I had CLASSPATH set when I ran the build, so I cleared CLASSPATH, and the problem went away. So I set CLASSPATH back again, and the problem came back.

OK, so I understood that the problem was due to my CLASSPATH, but I was still puzzled, because on my other machines, I can set CLASSPATH and I don't have this build error.

I struggled with the problem some more, until I finally looked in great detail at the CLASSPATH, and at the jars it was pointing to, and saw that the jars were ancient. On this particular machine, I hadn't built in a while, and so my jars were months old.

I rm'd the jars, and the problem went away.

Now I understood that the problem was:
  • the MessageBundleTest tool cross-checks the externalized message files against the SQLState and MessageId classes that it loads from the CLASSPATH
  • I had set CLASSPATH to point to some very old jars, so it was cross-checking some old binaries against the current up-to-date source, and failing the cross-check
But, there was still something I didn't understand: I had done "ant clobber". I have this mantra that whenever I re-visit an old Derby client, I can bring it up to date by:
  • "svn revert -R .". This removes any partly-made changes from the client.
  • "svn up". This gets the latest source code from the master repository.
  • "ant clobber". This removes all the build artifacts from the client. I always use "ant clobber", not "ant clean", since "ant clean" cleans much less than "ant clobber".
  • "ant all". This compiles the Derby code.
  • "ant buildjars". This packages the Derby code into jars.
So what was wrong with my mantra?

It turns out that the error is in the "ant clobber" step. I thought that "ant clobber" did a good job of cleaning the build artifacts from the client, but it doesn't. In particular, it doesn't remove the jars that I built. (It also doesn't remove junit test results, and perhaps some other things. But the jars is the part that was really messing me up.)

So my problem is that, since my CLASSPATH was pointing at my jars, and since "ant clobber" was not cleaning my jars, my "ant all" step was running the message check utility against the old version of the code. When I cleared my CLASSPATH, the message check utility checked the messages in the classes directory, and passed.

This behavior is documented in the build.xml file, where there is a comment saying that "ant clobber" does not remove the jars.

But while I was studying build.xml, I found the "cibuild" target, which does just what I want:

cibuild - target suitable for continuous integration builds.
Clobbers/cleans everything it can, then builds the jars
and the javadoc.

<target name="cibuild"

<target name="gump_all" depends="all,buildjars,javadoc"/>

So now I know that, when I go to a relatively out-of-date client, and bring it up to date, I shouldn't just do "ant clobber; ant all; ant buildjars". Instead, to be thorough, I should do "ant cibuild".

I've been a Derby committer for 3+ years, and I just figured this out now!

1 comment:

  1. Have you updated Derby's build documentation with these facts now?