I've got a build that's a mess. In the end, targets are executed up to 15 times. Most targets are executed over a dozen times. This is because the build and targets are divided into 10 separate build files (build.xml, build-base.xml, compile.xml, etc.).
In many build files, you have at the beginning <property> tasks outside of all targets in the build file. These are usually executed first before any targets are called.
Here is my build.xml file:
<import file="build-base.xml"/>
[...]
<target name="compile-base">
<antcall target="setup-tmpj"/>
<ant antfile="compile.xml" target="compile-base"/>
[...]
</target>
Here's the compile.xml file:
<import file="build-base.xml"/>
<property name="target" value="1.5"/>
<available file="target/gensrc/com" property=gensrc.exists"/>
[...]
<target name="buildAndCompileCodeGen" unless=gensrc.exists">
<blah blah blah/>
</target>
<target name="compile-base" depends="buildAndCompileCodeGen">
<blah blah blah/>
</target>
I execute this:
$ ant -f build.xml compile-base
This calls the target compile-base in the compile.xml file. This is dependent upon the target buildAndCompileCodeGen in the compile.xml file. However, the target buildAndCompileCodeGen is only executed if the property gensrc.exists is unset.
In the compile.xml file is an <available> task that will set the gensrc.exists property, but this task is located outside of all targets in compile.xml. Is that <available> task ever called, so that gensrc.exist is set?
Okay I figured out what's going on...
Yes, when I call the compile-base target in the compile.xml file via the <ant> task, all tasks not under a target are executed before the target I call is executed. That means, if the code is already there, the buildAndCompileCodeGen target is called but not executed.
What I did was combine all the build files into one big file and got rid of all of the <ant> and <antcall> tasks. I had put the <available> task in the combined build.xml file.
In the original circumstance, I would first do a clean, then call compile-base in the compile.xml file. At that time, the <available> task would run. Since I did a clean, the file didn't exist, the property gencode.exists isn't set, and buildAndCompileCodeGen target would run.
When I combined everything, the <available> task would run, set the gencode.exists property. Then, when I did a clean, I would delete the generate code. However, the buildAndCompileCodeGen target still wouldn't execute because gencode.exists has already been set.
What should be done is this:
<target name="compile-base"
depends="buildAndCompileCodeGen">
<echo>Executing compile-base</echo>
</target>
<target name="buildAndCompileCodeGen"
depends="test.if.gencode.exists"
unless="gencode.exists">
<echo>Executiing buildAndCompileCodeGen</echo>
</target>
<target name="test.if.gencode.exists">
<available file="${basedir}/target/gensrc/com"
property="gencode.exists"/>
</target>
In this case, I call compile-base. That will call buildAndCompileCodeGen. That will first call test.if.gencode.exists first. This will be done even if the property gencode.exists already is set. Dependent clauses are run on targets before Ant looks at the if or unless parameters. This way, I don't set gencode.exists until I am ready to execute the buildAndCompileCodeGen target. Now, the available task will be run after I do a clean.
Related
I'm creating a target in the build.xml file which depends on three other targets:
<target name="test" depends="target1,target2,target3">
<echo message="Build Successful!"/>
</target>
What I'm trying to do here is to pass some argument to 'target2'. Can this be done in Ant? If so, how can I do it?
Any help is truly appreciated!!
Do you understand how depends works?
When you call target test, it will run the following targets:
target1
target2
target3
test
In that order. There's no way for target test to pass any arguments to target2.
You can pass properties to your build.xml script using the -D parameter:
$ ant -Dsource.version="1.5" compile
When your build script is executed, the property source.version will be set to 1.5.
Otherwise, look at macrodef task as a way of passing arguments to particular routines.
By the way, if I had more information what you want, I could give you a better answer.
I have a target, that is executed if my_step==true:
<target name="pre-compile" if="my_step">
...
</target>
But I want to make that pre-compile target available regardless of the value of my_step, so that I could execute my action manually using ant do_my_step:
<target name"-do_my_step">
...
</target>
Question. How can I run make pre-compile execute -do_my_step target?
That is, if property my_step is true, then pre-compile step will execute -do_my_step target.
Obviously, I could simply copy-paste contents of -do_my_step target into pre-compile target, but I want to keep my target cleanly separated.
Target names with prefix '-' are a common practice to make the target somewhat 'private' as it's impossible to call it via commandline. ant -f yourbuildfile.xml -yourprivatetarget won't work as ant commandline interface uses leading '-' for options. So strip the leading '-' from your target name to call it via ant -f yourbuildfile.xml do_my_step
Also consider :
"..Question. How can I run make pre-compile execute -do_my_step target? .."
Ant has antcall task for calling a target within the same buildscript. But antcall should be avoided because it opens a new project scope (so it needs more memory and will slow down your build) and breaks the dependency chain which is normally built via <target name="..." depends"=..."> . antcall is superfluous since ant 1.6 introduced macrodef for that purpose (reuse of functionality).
<target name="pre-compile" if="my_step" depends="-do_my_step">
...
</target>
When pre-compile is called, it will run -do_my_step before.
If I pass a variable to ant by doing
ant -Dsomething=blah
How can I refer to it in my build.xml? I tried #something# and ${something} but neither seem to work.
Ultimately what I am trying to do is set some properties (versions) at compile time.
update: the problem of course turned out to be somewhere else - accepting the most complete looking answer with examples
Don't you hate it when you over think these things:
<project name="test">
<echo message="The value of foo is ${foo}"/>
</project>
Now, I'll run my program. Notice that I never defined a value for property foo in my build.xml. Instead, I'll get it from the command line:
$ ant -Dfoo=BAR_BAR_FOO
test:
[echo] The value of foo is BAR_BAR_FOO
BUILD SUCCESSFUL
time: 0 seconds
See. Nothing special at all. You treat properties set on the command line just like normal properties.
Here's where the fun comes in. Notice that I've defined the property foo in my build.xml this time around:
<project name="test">
<property name="foo" value="barfu"/>
<echo message="The value of foo is ${foo}"/>
</project>
Now watch the fun:
$ ant
test:
[echo] The value of foo is barfu
BUILD SUCCESSFUL
time: 0 seconds
Now, we'll set the property foo on the command line:
$ ant -Dfoo=BAR_BAR_FOO
test:
[echo] The value of foo is BAR_BAR_FOO
BUILD SUCCESSFUL
time: 0 seconds
See the command line overrides the value I set in the build.xml file itself. This way, you can have defaults that can be overwritten by the command line parameters.
It sounds like you want to do something like the following:
<mkdir dir="build/src"/>
<copy todir="build/src" overwrite="true">
<fileset dir="src" includes="**/*.java"/>
<filterset>
<filter token="VERSION" value="${version}"/>
</filterset>
</copy>
...which will cause your source to get copied, replacing #VERSION#:
public class a { public static final String VERSION = "#VERSION#"; }
...and then include build/src in your javac src.
That said, I don't recommend this approach since the source copy step is expensive, and it will undoubtedly cause confusion. In the past, I've stored a version.properties file in my package with version=x.y. In my Java code, I used Class.getResourceAsStream("version.properties") and java.util.Properties. In my build.xml, I used <property file="my/pkg/version.properties"/> so that I could create an output-${version}.jar.
${argsOne} works for me and is easily referenced if the invoking command is
ant -DargsOne=cmd_line_argument
Ant documentation also says so. This should work, try running with ant -debug and paste the output.
i am currently writing an ANT script which will include some intelligence to check for things. I am using SnapshotCM from True Blue Software as my version control and using CruiseControl as a framework for my nightly build.
Basically, I will need to always check for the latest version found in my version control and execute commands. In this case here is an example:
<project name="nightly_build" default="main" basedir="checkout">
<target name="init">
<property file="initial.properties"/>
</target>
<target name="main" depends="init">
<!-- need some code to set variable -->
<!-- need some code to increment variable -->
<!-- need some code here to check for the latest version -->
<exec executable="C:/Program Files/True Blue Software/SnapshotCM/wco.exe">
<arg line='-f -R "C:/Work/7.10.000_Tip/7.10.000_Tip_GUI_TEST/"'/>
</exec>
</target>
</project>
In the code above, I will load the "initial.properties" file.
The algorithm should be as follow:
load the initial properties file
get the build_number
increment build_number by 1 (let this new variable be X)
if X is found, increament X by 1 (if not found jump to 6.)
if X is found, repeat 4 (until X cannot be found)
else use the build number inside the <arg line ='-f -R "C:/..../7.10.100.X..../"'/>
The initial.properties file is as follow:
Major_Version=7
Minor_Version=10
Project_Number=100
Build_Number=036
Product_Version=${Major_Version}.${Minor_Version}.${Project_Number}.${Build_Number}
can anyone guide me on that?
Ant is not a programming language. It's a dependency matrix language.
That means you don't specify execution order in Ant. Ant will calculate the order it needs to run the targets. It also means Ant doesn't have the ability to do loops, or even change the value of a property once it is set.
There are a few packages that build upon Ant. The old standby is the Antcontrib. Antcontrib has the concept of variables which are like mutable properties. It also has various looping structures. However, I'm not sure if the <foreach> or <for> tasks will do what you want...
Searching sequentially for the next build number is something you can do in a shell script. In fact, I highly recommend this.
I use Ant for builds only and keep my CM functions outside of my build.xml file. Instead, I rely on my build system to do everything that's not related to the build itself. This includes checking out the code, saving the artifacts, and compiling unit tests. This way, if I change the way I use my continuous build system or my version control system, I don't have to modify my build.xml files.
I have a build script and as part of that script it copies a jar file to a directory, for ease lets call it the utils jar. the utils jar is built by another build script sitting in another directory. What im trying to do have my build script run the utils build script so that I can ensure the utils jar is up to date.
So I know I need to import the utils build file.
<import file="../utils/build/build.xml" />
Which doesn't work because the import task, unlike almost every other ant taks, doesn't run from basedir, it runs from the pwd. So to get around that I have this little ditty, which does successfully import the build file
<property name="baseDirUpOne" location=".." />
<import file="${baseDirUpOne}/utils/build/build.xml" />
So now that ive solved my import problem I need to call the task, well that should be easy right:
<antcall target="utils.package" />
note that in the above, utils is the project name of ../utils/build/build.xml
the problem I'm now running into is that ant call doesn't execute in ../utils/build so what I need, and cant find, is a runat property or something similar, essentially:
<antcall target="utils.package" runat="../utils/build" />
The reason I need this is that in my utils build file the step to select which code to copy to the jar is based on relative paths so as to avoid hardcoding paths in my ant file. Any ideas?
I've got something similar set up: I have a main Ant build.xml which calls a separate build.xml that takes care of building my tests. This is how I do it:
<target name="build-tests">
<subant target="build">
<fileset dir="${test.home}" includes="build.xml"/>
</subant>
</target>
The trick is to use subant instead of antcall. You don't have to import the other build file.
Try using the "ant" task instead of the "antcall" task, which runs the imported build directly instead of importing it into the current build file. It has a "dir" parameter:
the directory to use as a basedir
for the new Ant project. Defaults to
the current project's basedir, unless
inheritall has been set to false, in
which case it doesn't have a default
value. This will override the basedir
setting of the called project.
So you could do:
<ant antfile="${baseDirUpOne}/utils/build/build.xml" dir="../utils/build" />
or something like that.
You can pass params down to antcall using nested in the antcall block. So, you can pass the properties down that way (probably even basedir since properties are immutable).