I'm about to create some complex Ant build files and I wanted find out what people think are best practices for naming ant tasks. It is going to build some Java, C++, compresses JavaScript, generate docs and lots more.
What tasks do you always add to an any script? Things like clean, build?
How to you name targets that make up a single target through dependencies (or don't you do this)? E.g. build.proj1 and build.proj2
Any other naming conventions do you follow?
Another common practice is a kind of 'private' target. Simply put a leading '-' before
the target name, i.e. <target name="-yourprivatetarget" ... />.
Thus it's impossible to call that target via command line, as :
ant -f yourbuild.xml -yourprivatetarget won't work whereas
<target name="yourprivatetarget" ... /> and ant -f yourbuild.xml yourprivatetarget would.
Also a target without a description attribute won't be listed when using
ant -projecthelp (or ant -p).
So you have some kind of private / internal targets, but beware, some tools, i.e. Eclipse
or similar will expose all targets in the Outline view of it's ant editor.
Finally => there's no real private/internal target in ant, but it's helpful sometimes
This link explains the typical targets you should have in your project.
Using standard targets helps with new team members (and any experienced Ant hands) quickly getting to grips with the build process.
From personal experience, I'd say clean, build, deploy/install, test (test for running your junits, findbugs etc)
For the dependent targets, we use a convention like below
<target name="build" depends="clean,compile">
<target name="compile" depends="compile.src, compile.test">
Related
I have a project with a number of compile-time dependencies on other projects (of the same code-base).
So the compile classpath is defined somewhat like the following:
<path id = "compile.classpath">
<fileset dir="${dependency-a.dist.dir}">
<include name ="*.jar"/>
</fileset>
<fileset dir="${dependency-b.dist.dir}">
<include name ="*.jar"/>
</fileset>
<fileset dir="${dependency-c.dist.dir}">
<include name ="*.jar"/>
</fileset>
<fileset dir="${dependency-d.dist.dir}">
<include name ="*.jar"/>
</fileset>
</path>
Also, you can image the corresponding build targets for the dependencies and so on.
To reduce repetition I need to somehow generate those structures dynamically.
I thought that one Ant-friendly way to capture those dependencies might be to create a deps directory and add sym-links to all the compile-time dependencies of my project.
So the question is: is there an Ant way to write a macrodef or a custom Ant task that would scan that directory (or, alternatively, read a configuration file) and expand into/generate the necessary filesets / build targets automatically, in effect changing the XML nodes of the build.xml file at runtime? I am looking for a generic Ant way to do that (if such exist) so I don't have to use the more disruptive way of generating myself the build.xml file in its entirety from some other configuration. I am not asking how to use subant etc. as I am wondering whether there might exist a more sweeping capability of extending/enriching the Ant build file at runtime that would also apply to other cases not involving building dependencies.
Writing a task that builds the paths would be pretty easy, but Ant targets are fixed once the build file has been parsed. Ant builds a directed graph of the targets and then executes them.
It is possible to add new targets via a task that is outside of any target itself. include is such a task. It might be possible to generate a build file snippet containing the paths and targets you need via a custom task later include it. Unfortunately include won't allow you to embed it in a macrodef so the two steps had to appear in pairs.
Of course you can use Ant's API rather than include in order to add the paths and targets. You'd get hold of an existing Path using getReference on the Project instance you've received and add you filesets to it. Completely new data types use addReference, addTarget is for targets.
Have you considered using ivy? It's a dependency manager that provides a set of ANT tasks that can be used control classpaths but it can also download jars from managed repositories (like Maven).
The following answers can give your a flavour of how ivy is used:
sample example which explain how to use filesystem resolver
How to avoid copying dependencies with Ivy
Ivy provides a more powerful solution because it also prevents conflicting versions of the same jar. For example where several dependencies all contain a copy of a common jar like log4j.
In conclusion ivy may appear complex at first glance, but I can assure you that it's solving a complex problem.
i have this ant build.xml file with 3 targets in it:
target1, target2 and target3.
If the user simply runs ant and not an explicit ant target1 or something like that, i want to prompt the user asking which target he would like to call.
Remember, the user should only be prompted for this only if he doesnt explicitly call a target while running ant
Ant is not a programming language, it's a dependency matrix language. There's a big difference between the two.
In a program language, you can specify the absolute order of sequence. Plus, you have a lot more flexibility in doing things. In Ant, you don't specify the execution order. You specify various short how to build this steps and then specify their dependencies. Ant automatically will figure out the execution order needed.
It's one of the hardest things for developers to learn about Ant. I've seen too many times when developers try to force execution order and end up executing the same set of targets dozens of times over and over. I recently had a build her that took almost 10 minutes to build, and I rewrote the build.xml to produce the same build in under 2 minutes.
You could use <input/> to get the user input, then use <exec> or <java> to execute another Ant process to execute the requested target. However, this breaks the way Ant is suppose to work.
The default target should be the default target that developers would want to execute on a regular basis while they program. It should not clean the build. It should not run 10 minutes of testing. It should compile any changed files, and rebuild the war or jar. That's what I want about 99% of the time. The whole process takes 10 seconds.
I get really, really pissed when someone doesn't understand this. I hate it when I type ant and I get directions on how to execute my build. I get really irritated when the default target cleans out my previous compiles. And, I get filled with the deadly desire to pummel the person who wrote the damn build file with a large blunt object if I am prompted for something. That's because I will run Ant, do something else while the build happens, then come back to that command window when I think the build is done. Nothing makes me angrier to come back to a build only to find out it's sitting there waiting for me to tell it which target.
If you really, really need to do this. Use a shell script called build.sh. Don't futz with the build.xmlto do this because that affects development.
What you really need to do is teach everyone how to use Ant:
Ant will list user executable targets when you type in ant -p. This will list all targets, and their descriptions. If a target doesn't have a description, it won't list it. This is great for internal targets that a user shouldn't execute on their own. (For example, a target that merely does some sort of test to see if another target should execute). To make this work, make sure your targets have descriptions. I get angry when the person who wrote the Ant file puts a description for some minor target that I don't want, but forgets the description of the target I do want (like compile). Don't make David angry. You don't want to make David angry.
Use default target names for your group. That way, I know what targets do what across the entire project instead of one project using BUILD vs. build-programs vs. Compile vs build-my-stuff vs. StuffBuild. We standardized on Maven lifecycle names names. They're documented and there's no arguments or debates.
Do not use <ant/> or <antcall> to enforce build order. Do not divide your build.xml into a dozen separate build.xml programs. All of these probably break Ant's ability to build a target dependency matrix. Besides, many Ant tools that show dependency hierarchy in a build and they can't work across multiple build files.
Do not wrap your builds inside a shell script. If you do this, you're probably not understanding how builds work.
The build should not update any files in my working directory that were checked out by me. It shouldn't polute my working directory with all sorts of build artifacts spread out all over the place. It shouldn't do anything outside of the working directory (except maybe do some sort of deploy, but only when I run the deploy target). In fact, all build processing should take place in a sub-directory INSIDE my working directory. A clean should merely delete this one directory. Sometimes, this is called build, sometimes dist. I usually call it target because I've adopted Maven naming conventions.
Your build script should be a build script. It shouldn't do checkouts or updates -- at least not automatically. I know that if you use CruiseControl as a continuous build process, you have to have update and checkout functionality inside your build.xml. It's one of the reasons I now use Jenkins.
Sorry about this answer not necessarily being the one you're looking for. You didn't really state what you're doing with Ant. If you're doing builds, don't do what you're trying to do. If you're writing some sort of program, use a real programming language and not Ant.
An Ant build should typically finish in under a minute or two, and redoing a build because you changed a file shouldn't take more than 30 seconds. This is important to understand because I want to encourage my developers to build with Ant, and to use the same targets that my Jenkins server uses. That way, they can test out their build the same way my Jenkins server will do the official build.
you may use the input task provided by ant and make it your default target.
<input
message="Please enter Target ID (1,2 or 3):"
validargs="1,2,3"
addproperty="targetID"
/>
Use the value of this property to decide which target to execute.
From the ant documentation:
message : The Message which gets displayed to the user during the build run.
validargs: Comma separated String containing valid input arguments. If set, input task will reject any input not defined here.
You may pass any arguments according to your needs.
addproperty : The name of a property to be created from input.Behaviour is equal to property task which means that existing
properties cannot be overridden.
Android has an ant script file with generic targets for compile, clean, etc.
Are there any open source ant scripts that define standard targets such as these for general java projects?
I don't want to bother installing and using maven, but I also don't want to bother creating and maintaining ant scripts for each project.
I'm guessing you are new to both Maven and Ant. If I'm wrong you can ignore the rest of this post :)
I don't know of any generic open source Ant files. I've never had the need to look for one. I think its well worth the effort to learn Ant and create your own generic script. Ant is easy to learn and it is a very flexible, powerful and reliable build tool. You'll find it quite easy to create a build file that you can reuse over and over again on different projects.
With regards to having to maintain Ant scripts, its a bit of a fallacy. You'll find that once you've got a script that works in a generic way you'll hardly ever have to touch it again except when you need to do things in a custom way (usually around packaging and deployment). When that happens, you'll be glad you're using a tool like Ant that gives you the flexibility to do what you want to be able to do without getting in your way.
I'm trying to unify a build process, running one build to get multiple packages. My first shot at this is just having a central build script call <ant> or <subant> on each project's build.xml file. I'm using Ant 1.6, and I've run into a funny problem: either I use the <ant> task, and I can specify multiple targets but not multiple build files, or I use the <subant> task, and I can specify multiple build files but not multiple targets.
I realize there's a few solutions here already:
Just upgrade to Ant 1.7 already; <antcall> can do multiple targets there.
Edit the separate project build files to have a variety of top-level targets, so I can call each individual file with just one target, and use <antcall>.
Copy-paste a lot of <ant> tasks, with a little help from <macrodef> to help the sanity.
Is there something I've missed, that will allow me to do what I want from this single central build.xml without a) editing individual project files, b) writing lots of repetitive code, or c) upgrading Ant, and that d) doesn't require editing every time I add a new project?
For those of you that use Ant with multiple projects, where do you put the build.xml files? Do you put one in each project, or do you put them in a separate project that contains all your Ant-related files?
The usual recommendation is to put a build.xml in each project. But this has a few drawbacks:
It makes it hard to reuse common targets in multiple projects.
Sometimes you want to use Ant to export a project from source control and deploy it. Obviously you can't do this if the build file is in the project itself.
But if you put them all in a common location:
People need to be aware of their location to use them; they can't just use "ant -find" to find the current project's file.
You can't have different build instructions for different branches of the project.
What do you guys do?
EDIT: Thanks for the good suggestions so far. As far Maven, these aren't Java projects, and I get the impression that Maven is only meant for Java.
Place the Ant files with the project. That is the de facto standard and recommended by the creator of Ant. I will try to address some of the issues you have brought up:
Reuse of common targets should be done using techniques as described by Eric Hatcher in his book Java Development with Ant. Basically, you extract all commonality into a some top level files that all other Ant files "inherit" from.
Using Ant to export a project from source control seems odd to me, but if you want to do this, use a different Ant file :-) You can make a target like ant export -Dproject=foo/bar.
For Ant, I recommend you grab that book - it has a ton of helpful techniques.
The real recommendation I would make though is to drop Ant and convert over to Maven - like the Apache Software Foundation did (they maintain both Ant and Maven).
If you're working with independent projects, you can:
put your build.xml at the top level
place common Ant definitions (Antlib) into another project (e.g. config)
use svn:externals to import the common Antlib definition (from 'config') into your project
EDIT The trick with svn:externals is that if you link to the HEAD of some common files, it may happen that they will change after a couple of months/years. So each time you tag, you should change the svn:externals to point to a fix version of the included project. This may come handy when a project has to be rebuild years after it was last built.
My rule of thumb is to put the build.xml file in the directory under which all files are referenced. In other words, no relative paths should start with "../". Where I live, that usually means putting it in the "trunk" directory, which has src, lib, build, docs, etc underneath it.
Doing this makes the paths much cleaner in the file, and it makes it obvious how to build the project.
Where I have multiple projects that need to build, I will create a separate build.xml for each project, and a central build.xml in the directory all the project are in that calls those other build.xml files. That gives you a lot of flexibility with very little work.
I'd expect an Ant build file to be located at the top of a project (it's already a pain to have to look at a the build file to "discover" how to build the project, so if I have to locate it first, it'll drive me totally crazy). Now, regarding all the drawbacks you mentioned, I'm tempted to say: why don't you use Maven?
The way I have done this is in the past (Now I just use Maven):
Have a build.xml in the root of each project
Create an overarching build.xml
for all projects and place it in
the trunk of my repository
The overarching buid.xml has
checkout tasks for each project.
I am guessing when you mentioned
export from repository, you
actually meant import.
The overarching build file also
defines the dependencies, if any
You may update individual projects using each project's individual build file
If you do have common tasks defined, you may inherit from a common build file as well as someone else suggested.
Looks like your set of projects might be a good candidate for migration to Maven, I realize it is not always possible but if you have time, you might want to look into it.