How-To Guides
Getting Started
Policy Strategies
Format Strings
Extending Antlion
First Tutorial: Simple
Ant Tasks
inner processors
inner repositories
Optional Tasks
About optional tasks
Fequently Asked Questions for Antlion

Before you get into the FAQ, you'll need to learn a little about the language used in it:

  • module: A build process and source files that generates a distribution.
  • project: a collection of one or more modules, built at the same time. Usually, some modules may depend upon other modules before they can be built.

If you have any suggestions for more FAQs, please post them to the forums.

Q1: How do I allow for a project-wide default library version?
A: Your project has a policy of compiling against the lowest-common denominator version, which, in this case, is version 3.7. We want to centralize this information, so that when we do upgrade this version, we don't have to do it for every build file.

However, we also need to be able to have modules within the project be able to support newer versions, if they're intended to work with a different version.

If you know that the library's jar files will remain fairly stable, then you can use the dynamic attribute processor in your libraryDef type:
      <attribute attrib="version"
        property="lib.[group].version" />
  <repository refid="3rdparty repository" />
  <library id="lib.junit" group="junit">
    <lib-entry artifact="junit" />
Then, the shared files will define the default value:
<property name="lib.junit.version" value="3.7" />

before the <libraryDef>. The build files that take exception to this would set this to "3.8.1" (or whichever) before importing the shared definition file.

Q2: When should I run an Artifact or a Project?
A: If your project has a library dependency upon a generated file or other long-term created thing from another project, then reference it via the artifact terminology and set of tasks. This is useful when you need that artifact to compile or test your code.

However, if you need to bundle that artifact with your current project, then you are better off running that artifact's build as a separate project.

What's the difference? In general, building just the artifact will only run the minimal build targets to create a working file. This means things like unit tests and documentation are skipped. When you run the project, then the full build can be run, helping to ensure that the built file(s) works as expected.

This is why, currently, Antlion does not allow passing any parameters to an artifact's build: the artifact's build file should know exactly how to make this minimal artifact without external pushing and prodding. If you need an odd alternate build method for an artifact, then look into creating another Ant target to use as the artifact's build target.

Q3: How do I specify dependencies on a bootstrapped library?
A: Let's say that you've developed a project that formally releases an Ant task, but your project also relies on that Ant task to perform your build. This means you need to bootstrap that Ant task: build it in an informal way before it gets formally built. This can also be called self-hosting, or eating your own dog food.

The <subprojects> task allows for adding external dependencies into the build, but it's not just for formal dependencies.

The trick is to mirror the standard build in a file called something like bootstrap.xml for that specific module, whose sole duty is to take the smallest number of steps to build a bootstrap version of the module's distribution library. This bootstrap version isn't for formal distribution, but other modules use it to perform their builds.

To fit this into the Antlion's bag of tricks, you create another file called bootstrap-artifacts.xml to mirror the artifacts.xml file for that module. This bootstrap version will allow other modules to reference the bootstrap version and build the bootstrap library without much hacking.

Q4: How do I allow for developers to use a head build of a sibling module, but formal builds pull from a repository?
A: Normally, for a dependent sibling module, you want to use the <artifact> tag in the <library>. However, one situation where this doesn't apply is when a project has lots of independent modules, each on their own build cycle. For instance, the Apache Jakarta project is under one CVS roof, but each module is built independent of the other.

Here, a "snapshot" version of the library may be appropriate. A module would publish the formal build somewhere to a "snapshot" location. If you want to keep a history of builds, then the formal build would also publish to that historical location. (For snapshots, be sure to read the corresponding faq on them to ensure you don't fall into a pitfall.)

Then, each dependent module would add another repository that would look to this "internal" published site (this could very well could be open to the internet), with a "snapshot" version capability. When the module runs, it would try to load the snapshot version.

However, the question here is to also allow a developer to build a local copy of the dependent module, then build the other module using the local recent version. This would allow a developer to see how a change in one module affects others.

To solve this, add another repository before the "internal" publish repository, like so:
  <repository dir="${published.rootdir}"
    format="[module]/exports/[artifact].[type]" />
  <urlrepository refid="internal-published-site" />
The build would define the published.rootdir Ant property to the root directory of the tree. The developer's build would either find the local version with the first repository, or revert to pulling from the published site. Like this, the formal build would always use the local version. However, if you want the formal build to use the published site, then you can have the formal build set the property published.rootdir (either through a special properties file or passed in when it runs) to a directory that doesn't exist. This ensures that the published site is always used.

Q5: Why is the common 'SNAPSHOT' usage broken?
A: The short answer is because of branches.

When you create a new branch, you don't want to change out the "SNAPSHOT" labels with a specific version. You would only create a specific version once it has been officially published, but the branch will want to use the current "head" version of an artifact for that branch.

Now, let's look at an example developer cycle. In some CM tools, branches are represented in their own trees (ala Perforce), but usually the library repository is independent of the code tree. So, the developer is tasked to work on bug fixes in version 3 of her product, and also tasked to add new features to the trunk. The project is divided such that module B depends upon the output of module A.

If our developer adds new features to module B of the trunk, and runs a build of that module, the library repository should now store a SNAPSHOT revision of module B's artifact as it exists in the trunk.

Then she moves to fix the bug in version 3. Since the bug only lives in module A, she writes unit tests first (of course), then fixes the bug. However, since it has a dependency on module B, module A's build will look in the library repository to grab the SNAPSHOT version of module B, which happens to be the version from the trunk, not version 3! Therefore, her local build will not work like it should.

To fix this issue, make a clean separation between snapshot repositories and published repositories. When publishing the SNAPSHOT version, put it in a local repository for the branch. This way, branches won't be touching each other. There's nothing wrong with storing all the third-party repositories in a location outside a branch (as long as it is properly maintained for backwards compatibility with old branches), but built artifacts that haven't been officially published need to live with the code that built it.

Document version $Revision: 1.11 $ $Date: 2005/12/01 22:29:59 $

SourceForge Logo
Copyright © 2004-2006, The Antlion Project