Say I have my sources in my src/ tree (and possibly in my test/ tree). Say I would like to compile only part of that tree. The reasons why I might want to do that are various. Just as an example, I might want to create the smallest possible jar (without including certain classes), or I might want the fastest compile time for what I am compiling. I absolutely want to compile all the dependencies, though!
This can be easily achieved from the command line with:
javac -d build/ -cp whatever -sourcepath src src/path/to/MyClass.java
Now, how can you do that with ant? The javac ant task compiles everything:
The source and destination directory
will be recursively scanned for Java
source files to compile.
One can use the excludes and includes parameters, but they are problematic for this purpose. In fact, it seems that one has to explicitly setup all the includes (not automatic dependency lookup), and even worst that excludes has priority on includes:
When both inclusion and exclusion are
used, only files/directories that
match at least one of the include
patterns and don't match any of the
exclude patterns are used.
Thus, you cannot use
<javac srcdir="${src.dir}" destdir="${build.dir}" classpathref="classpath"
excludes="**/*.java" includes="src/path/to/MyClass.java" />
Because it will not compile anything :-(
Is there any way of achieving that simple command line javac with ant?
EDITED: Thank you for your answer, Sadie, I'm accepting it, because it does work in the way I was wondering in this question. But I have a couple of comments (too long to be in the comment field of your answer):
1) I did read the documentation (see links above), but it's unclear that with just includes you are actually also excluding everything else
2) When you just includes ant logs something like
[javac] Compiling 1 source file to /my/path/to/build
even if the dependencies make it compiling (much) more than just one source file.
Why are you excluding as well as including? If you have at least one include, then files are only compiled if they're explicitly included. So this should work:
<javac srcdir="${src.dir}" destdir="${build.dir}" classpathref="classpath"
includes="src/path/to/MyClass.java" />
Or more flexibly:
<javac srcdir="${src.dir}" destdir="${build.dir}" classpathref="classpath">
<include name="src/path/to/MyClass.java"/>
<include name="src/path/to/AnotherClass.java"/>
</javac>
To include only certain packages or classes in a jar, use a fileset attribute
<jar jarfile="${outlib}/something.jar">
<fileset dir="${build.dir}">
<include name='src/path/to/classes' />
</fileset>
</jar>
Again, you can use multiple includes to combine separate packages. Experiment with includes and read the documentation and you're sure to find the answer you need.
Old question, but I was struggling with the same problem and found a a more elegant solution. So here it is, for future reference:
According to the ant docs the <javac> element is an implicit <fileset> and as such can take Selectors like <filename name="**/MyClass.java"/>, so this would only compile MyClass.java:
<javac srcdir="${src.dir}" destdir="${build.dir}" classpathref="classpath">
<filename name="**/path/to/MyClass.java"/>
</javac>
Actually, ant only checks everything, if you run a compile twice in a row you will notice the second is much quicker. Actually, it can be easily persuaded to miss things.
If you don't even want it to consider everything, you're going to have to break it down into smaller modules/projects/source trees so that you're explicitly telling ant what to compile.
Just give only the comma seperated list of files that you want to build. Lets say example
<property name="includeFileList" value="<name of java class>.java"/>
<javac srcdir="${src.dir}" destdir="${build.dir}"
target="1.6" debug="true" includes="${includeFileList}"/>
It will work.
Related
I am having little problem with fixcrlf from ant. When I try to compile for unix target with fixcrlf filter, it modifies all files in the target folder, no matter of includes and excludes. I expect it should not convert any files that are not in the includes patterns, or at least I could force some files to not be converted via excludes attribute. None of that I tried been able to exclude anything. Even some binary files are modified and as result screwed up.
According to fixcrlf documentation from apache site, these parameters should work like this:
includes: comma- or space-separated list of patterns of files that must be included.
excludes: comma- or space-separated list of patterns of files that must be excluded.
When I run ant with parameters -verbose and -debug, there is no information on that fixcrlf did.
<copy todir="target">
<fileset dir="source1"><exclude name="**/*.bak"/></fileset>
<fileset dir="source2"><exclude name="**/*.bak"/></fileset>
<filterchain>
<fixcrlf srcdir="${src}" includes="**/*.sh,**/*.properties" excludes="**/*.xml" eol="lf" />
</filterchain>
</copy>
For a variety of reasons (regardless of whether or not this is a wise idea) we have a project with several packages (say one, two, three) that are similar in structure. There is one additional common package.
I want the build to fail when something in each of those packages imports something that isn't in common, e.g. because you accidentally accepted the wrong import completion, or because Eclipse silently brought over the wrong imports while copy-pasting bug fixes from one into two.
What works is copying all the source files, except for each package, over to a temporary folder and attempting to build the result:
<target name="enforce-no-cross-imports">
<phony-build without="one"/>
<phony-build without="two"/>
<phony-build without="three"/>
</target>
<macrodef name="phony-build">
<attribute name="without" />
<sequential>
<echo message="Checking there are no cross imports to the #{without} package." />
<mkdir dir="${java.io.tmpdir}/my-awesome-project/phony-build-#{without}/src" />
<mkdir dir="${java.io.tmpdir}/my-awesome-project/phony-build-#{without}/bin" />
<copy todir="${java.io.tmpdir}/my-awesome-project/phony-build-#{without}/src">
<fileset dir="${src.dir}">
<include name="**/*.java"/>
<exclude name="**/#{without}/"/>
</fileset>
</copy>
<javac srcdir="${java.io.tmpdir}/my-awesome-project/phony-build-#{without}/src"
destdir="${java.io.tmpdir}/my-awesome-project/phony-build-#{without}/bin"
classpathref="classpath" encoding="UTF-8" nowarn="on"/>
<delete dir="${java.io.tmpdir}/my-awesome-project" />
</sequential>
</macrodef>
However, when the build DOES break, the error obviously occurs inside ${java.io.tmpdir}.
enforce-no-cross-imports:
[echo] Checking there are no cross imports to the one package.
[mkdir] Created dir: C:\Users\me\AppData\Local\Temp\my-awesome-project\phony-build-one\src
[mkdir] Created dir: C:\Users\me\AppData\Local\Temp\my-awesome-project\phony-build-one\bin
[copy] Copying 47 files to C:\Users\me\AppData\Local\Temp\my-awesome-project\phony-build-one\src
[javac] Compiling 47 source files to C:\Users\me\AppData\Local\Temp\my-awesome-project\phony-build-one\bin
[javac] C:\Users\me\AppData\Local\Temp\my-awesome-project\phony-build-one\src\my\awesome\project\two\very\long\path\SomeController.java:43: package my.awesome.project.one.very.long.path.SomeConstantsClass does not exist
[javac] public static final String TEST = my.awesome.project.one.very.long.path.SomeConstantsClass.TEST;
As a result I can't click on the file name to jump directly to the issue. This adds way too much friction to the compilation process: it's bad enough that I'm effectively tripling the project build times.
What I thought I could do instead is not copy the files over and use the excludes attribute on the javac task instead:
excludes: Comma- or space-separated list of files (may be specified using wildcard patterns) that must be excluded; no files (except default excludes) are excluded when omitted.
...except this does not cause the build to break. What happens is that javac will not compile the other packages, but it will still look at them for confirmation. Turning on verbose shows this log line:
[javac] [checking my.awesome.project.one.very.long.path.SomeConstantsClass]
includeDestClasses seemed like another helpful flag, but setting it to false didn't help. <compilerarg value="-implicit:none"/> also was not helpful.
How can I tell javac that it really positively does need to exclude those files from the build, even if they are right there?
Alternatively, how can I take the output of javac and run find-replace on it so that the console output shows the correct path instead?
You could use the compilewithwalls or verifydesign tasks of ant-contrib, but the safest way to enforce separation like this is to isolate the modules into separate source directories and compile them independently. You'd first build the common module, then build each of the other modules with the compiled classes of "common" on their classpaths but not the classes of any of the other modules. This is the default approach when you're building with a higher level build tool like Maven. If you have a directory structure like this:
build.xml
lib
library JAR files
common
src
classes
one
src
classes
two
src
classes
then you could structure the build as
<macrodef name="compile-module">
<attribute name="module" />
<element name="depends" implicit="true" optional="true"/>
<sequential>
<javac srcDir="#{module}/src" destDir="#{module}/classes"
encoding="UTF-8" nowarn="on">
<classpath>
<path refid="classpath" />
<depends/>
</classpath>
</javac>
</sequential>
</macrodef>
<compile-module name="common" />
<compile-module name="one">
<pathelement location="common/classes" />
</compile-module>
<compile-module name="two">
<pathelement location="common/classes" />
</compile-module>
<compile-module name="three">
<pathelement location="common/classes" />
</compile-module>
You mention Eclipse in the question, so you'd need to do something similar there. Eclipse allows the root of one project to be inside another, so you could create one main Eclipse project "myapp-common" pointed at your project root with just common/src as its source directory (and common/classes as the corresponding output directory), then create separate "myapp-one", "myapp-two" etc. projects rooted at the one, two, etc. folders, each depending on the "myapp-common" project. That way you would never get Eclipse offering the "wrong" auto-completion, as project one simply cannot see project two or vice versa.
I am new to apache ant and I am currently working on an apache Ant project. I Just started out, imported the project into workspace and tried to run the build.xml. I added all the libraries that come with the original project to the build path. I am having the following problem. Please someone else wrote the code and I am supposed to improve it. The directories this is all about exist in the project directory.
BUILD FAILED
C:\workspace\MyApp\build.xml:83: srcdir "C:\workspace\MyApp\${compile.javac.srcdir}" does not exist!
The error code is referencing the following part of the build.xml file
<target name="compile.default" depends="init">
<javac fork="yes" srcdir="${compile.javac.srcdir}" destdir="${compile.javac.destdir}" includes="${compile.javac.include}" excludes="${compile.javac.exclude}" classpath="${compile.javac.classpath}" debug="${compile.javac.debug}" optimize="${compile.javac.optimize}" deprecation="${compile.javac.deprecation}" verbose="${compile.javac.verbose}">
</javac>
<copy todir="${compile.javac.destdir}">
<fileset dir="${compile.javac.srcdir}" includes="${compile.copy.include}" excludes="${compile.copy.exclude}"/>
</copy>
</target>
<target name="compile" depends="init,compile.default" description="Compile all java source">
</target>
<!--+++++++++++++++-->
<!-- lib target(s) -->
<!--+++++++++++++++-->
<target name="lib.default" depends="init,compile">
<xmlbean schema="config/schemas/validate/1.0/validate.xsd" destfile="lib/glx-beans.jar" classpath="lib/xbean.jar:lib/jsr173_1.0_api.jar" />
<jar jarfile="${lib.filename}">
<fileset dir="${lib.srcdir}" excludes="${lib.exclude}" />
</jar>
</target>
<target name="lib" depends="init,compile,lib.default" description="Create all Project Libraries">
</target>
Would you please tell me what I am missing?
The ${compile.javac.srcdir} isn't defined. There are a few possibilities:
This is defined not in the build.xml, but in some sort of properties file. See if you have something like <property file="..."/> in your build script. My recommendation is to have all properties defined in the build.xml file, and use a properties file to override those settings. This way, the only build file that a developer needs in the build.xml file and doesn't have to worry about setting up a separate build.porperties file.
This is defined in the build.xml file under a particular task, but you forgot to say that your target where you use thisis dependent upon this task.
One of the things you can do is use the -d parameter when running Ant. I run the following command when running Ant with the -d parameter:
$ and -d 2>&1 | tee ant.out
I can then look at ant.out and see if somehow I didn't define that particular property. Maybe I had the wrong capitalization or misspelled the property name. For example, it's very likely I'll define the property as copmile.javac.srcdir because I don't know how to spell. Looking at the -d output can quickly point these types of errors out.
By the way, you shouldn't have all of your tasks dependent upon init since they're dependent upon compile.default anyway:
<target name="compile.default" depends="init">
....
</target>
<target name="compile" depends="compile.default">
....
</target>
<target name="lib" depends="compile,lib.default">
....
</target>
If I run the target lib, it will see compile is dependent upon compile.default which is dependent upon init. Thus, your build will run init, then compile.default, then compile, then 'lib.defaultand finallylib`.
If the init task is just setting up properties, you can do that outside of any task. Then, these properties will be setup before any task is executed. This way, they're not forgotten. If your init is also creating directories, you may want to move those <mkdir/> tasks in front of the task where that directory is used. For example, you may want to make the destdir uses in javac before the <javac/> task.
I find assigning default properties outside of any task, and creating directories before they are needed to simplify the build.xml. Plus, you're not creating a whole flock of unused directories if the user is merely compiling and not packaging the jar/war/etc.
I have several files scattered across several packages. I need to load the file one by one and perform operations using ANT but whenever I try, only one file gets loaded. For ex. I have 2 classes - com.abc.one.One and com.bcd.two.Two . The following script print both file name but only the first file as loaded file in both loop iterations
<target name="build" description="My Task">
<for param="file">
<path>
<fileset dir="C:\workspace\AntTest1" includes="**\*.java" />
</path>
<sequential>
<echo message="#{file}" />
<loadfile property="loadedFile" srcfile="#{file}" />
<echo message="${loadedFile}" />
</sequential>
</for>
</target>
I have tried searching the documentation but could not find the concise explanation on how to use loadfile task. I suspected that this might be because ant uses immutable string but could not get workaround. I tried to split the job by creating new target but that does not help me either. Any help is highly appreciated
Ant property can only be set once, and after it is set, it is immutable.
It has been some time since my Ant days, but perhaps the following solution can work: For each file, make an antcall call, with the file name as parameter. then, in the new target, load the file and perform your task. Notice that antcall can impact severely the runtime performance.
We have quite a big tree of source code, parts of it are deployed as two separate jar files. We need an easy control of what goes to which jar.
So far we do this by <exclude name="" /> and <include name="" /> tags, but this is quite inconvenient. The best option would be a separate config file with all the packages listed which we could comment out when needed, say with a '#' character.
Does something similar exist or do we have to write a new ant task that reads such a file and runs a <jar> task?
The best option would bee to seperate the code into different modules which can be build on their own (of course with dependencies to each other). Doing this also makes cyclic dependencies obvious and gives you the chance to optimize your code base.
ANT includes and excludes can be managed with external files and referenced in a fileset using includesfile and excludesfile attributes.
includesfile the name of a file; each
line of this file is taken to be an
include pattern.
excludesfile the
name of a file; each line of this file
is taken to be an exclude pattern.
For example:
<jar destfile="${dist}/lib/app1.jar">
<fileset dir=".">
<includesfile name="app1.properties"/>
</fileset>
</jar>
<jar destfile="${dist}/lib/app2.jar">
<fileset dir=".">
<includesfile name="app2.properties"/>
</fileset>
</jar>