I'm attempting to optimize our build procedure for our applications we have here. I'd like to skip the compilation of our backend .dll file should the file timestamp not have change using Netbeans Ant scripts.
I've been using Incremental and fast build using Ant and Advanced Free-form project configuration as a reference point but it seems to require 2 build targets to create the .timestamp comparison in the first link.
Is there a way to circumvent the need for 2 targets and check the timestamp of the .dll file instead? or do I simply need to add another tag inside of my call to make the comparison, or is what I'm trying to do not feasible?
Any help would be greatly appreciated or if better methods of doing this are known I am open to listening to it.
We use Netbeans to compile our projects, and uses Ant by default. I've included a snippit of my build.xml Ant script so far.
Thanks in advance!
<target name="init-skip-dll" description="initializes the skip property for the Ada dll">
<uptodate srcfile="create-ada-dll.timestamp" targetfile="ada-dll.timestamp" property="ada-dll.skip" value="true" />
</target>
<target name="-build-dll" description="builds the Ada dll if needed" depends="init-skip-dll">
<exec executable="gprbuild.exe">
<arg value="-P"/>
<arg file="..\DLL\ifccs_dll.gpr"/>
</exec>
<touch file="create-ada-dll.timestamp"/>
</target>
I don’t use Ant, but the same problem exists with Make; the Ada dependency rules are complex, and best handled by unconditionally letting gprbuild do whatever it needs to to bring the DLL up-to-date. Gprbuild will do nothing besides checking dependencies if the DLL is actually up-to-date.
In Make, this involves a phony target: e.g. for a real target testbed,
testbed: force
gprbuild -p -P testbed
.PHONY: force
or for an already-phony target
all:
gprbuild -p -P build_runtime.gpr
.PHONY: all
By the way, note the -p, which says to create needed directories, e.g. an object directory.
I have a build server (running windows) and would like to convert markdown (including tables) to HTML.
I don't want to write software for this but rather use something existing from the Java World.
The whole thing should work from the command line:
Example:
java -jar some.jar -Dinput someMarkdownfile.md -Doutput someOutputfile.html
Is there an elegant way to do something like this?
Update: Java is not a hard "must-be" in my case. I thought that Java is a good option so it would be platform independent.
For a java solution you could use markdownj
The following example uses ivy to retrieve the jar from Maven Central
<project xmlns:ivy="antlib:org.apache.ivy.ant" name="markdownj" default="build">
<target name="resolve">
<ivy:cachepath pathid="build.path">
<dependency org="org.markdownj" name="markdownj" rev="0.3.0-1.0.2b4" conf="default"/>
</ivy:cachepath>
</target>
<target name="build" depends="resolve">
<java classname="com.petebevin.markdown.MarkdownProcessor" classpathref="build.path" input="test.markdown" output="test.html">
</java>
</target>
</project>
I found a command line tool that does just what I want to do:
Multimarkdown can handle tables and converts HTML output like so:
mulimarkdown.exe -o someOutputfile.html someMarkdownfile.md
What is a bit tedious is that I don't have an option to provide a CSS but I can do that manually by stitching together a header the generated content and a footer.
I want the javac task to use jars from the system classpath, by which I mean the classpath that is set in the shell's environment before ant is started. That classpath is
CLASSPATH=D:\local\lib\java\*;.;C:\lib\java\*;C:\lib\java\db\*
on my system. I have popular jars there that are used by many projects. The basic snippet I use in the build file is
<target name="build">
<mkdir dir="${obj}" />
<javac srcdir="${src}" destdir="${obj}"
includes="**/*.java"
excludes="**/package-info.java **/deprecated/*.java"
includeAntRuntime="no" debug="true" debuglevel="source,lines"
>
<compilerarg value="-Xlint"/>
</javac>
</target>
That way ant only passes the output directory as classpath.
[javac] '-classpath'
[javac] 'D:\dev\tbull-projects\jsonc\obj'
(jsonc is the project I'm working on, and D:\dev\tbull-projects\jsonc is the working directory.)
I browsed the documentation for a while and came up with two attempts. First one was adding the attribute classpath="${java.class.path}" to the javac tag. That would pass a tremendously long classpath to the compiler, listing every single jar from ant's own lib directory and finally tools.jar from the JDK. Not the classpath that I wanted.
The second shot was setting
<property name="build.sysclasspath" value="first" />
before javac was invoked, and that got me in the right direction. Now these lines were among the output:
dropping D:\dev\tbull-projects\jsonc\D:\local\lib\java\* from path as it doesn't exist
dropping D:\dev\tbull-projects\jsonc\C:\lib\java\* from path as it doesn't exist
dropping D:\dev\tbull-projects\jsonc\C:\lib\java\db\* from path as it doesn't exist
dropping D:\dev\tbull-projects\jsonc\C:\Program Files\Java\jdk1.6.0_18\jre\lib\sunrsasign.jar from path as it doesn't exist
dropping D:\dev\tbull-projects\jsonc\C:\Program Files\Java\jdk1.6.0_18\jre\classes from path as it doesn't exist
Well, you can imagine that these paths really don't exist. I just don't get why ant constructed them this way. It would know how to do path arithmetic on Windows, would it?
Maybe my approach is flawed more fundamentally, so I'll let you know what I'm actually after. So I'm developing this project (a library), which uses another library. The project is gonna be open source, so I want other developers to be able to build it after they have downloaded the dependency library and placed it somewhere in their classpath.
From what I saw in other questions about ant+classpath, it appears that it's a custom fashion to distribute the dependency libs with the source code (so the classpath can be just like ./libs). But I surely don't want to have jars in my git repo. So how could that be done?
Set includeJavaRuntime=true in javac task.
<target name="build">
<mkdir dir="${obj}" />
<javac srcdir="${src}" destdir="${obj}"
includes="**/*.java"
excludes="**/package-info.java **/deprecated/*.java"
includeAntRuntime="no" includeJavaRuntime="true"
debug="true" debuglevel="source,lines">
<compilerarg value="-Xlint"/>
</javac>
</target>
Why wouldn't you set CLASSPATH in Ant? It's perfectly suited to do just that. You're making a mistake if you do anything else. Not only will it work, bu your build.xml will document the requirements as well.
When javac compiles the code , it tries to find the files in rt.jar in a symbol file called ct.sym (which is also present in lib directory). some files are missing in this symbol file.
i have to add a compile option to ignore symbol file and look directly in rt.jar.
so i have used this option -XDignore.symbol.file for ant i put this value in javac tag. it works perfectly if you use eclipse or any other ide .
<compilerarg value="-XDignore.symbol.file"/>
So , whenever you get ClassNotFoundException in using classes from rt.jar , and if the class is still present there , just try to add this argument in java compiler
To reference rt.jar from ant you may use:
<fileset dir="${java.home}/lib" includes="rt.jar"/>
Original details were found here: http://www.javaroots.com/2013/01/javac-error-using-classes-from-rtjar.html
If someone is new to java/ANT world, people who suggest maven are idiots
whatever happened to KISS principle?
OP, instead of using javascript abomination try this
<project default="build">
<property name="src" value="src" />
<property name="obj" value="obj" />
<property name="parent.dir" value="/jakarta-tomcat/common/lib" />
<path id="project.class.path">
<pathelement location="lib/" />
<fileset dir="${parent.dir}" includes="**/*.jar" />
</path>
<target name="build">
<delete dir="${obj}" />
<mkdir dir="${obj}" />
<javac srcdir="${src}" destdir="${obj}" includes="**/*.java" excludes="**/package-info.java **/deprecated/*.java" debug="true" debuglevel="source,lines" classpathref="project.class.path" />
</target>
It's pretty clear the folks behind java, and (or at least), ant, really really really don't want to see $CLASSPATH end up as storage for user installed libraries of the sort that 95% of other mainstream languages (C/C++, perl, python, ruby, etc. etc.) use. So this is a tough paradigm to swallow if you are used to general programming in most other mainstream languages.
The disinclination goes so far that it is obvious ant intentionally strips $CLASSPATH out of the environment, but an easy way around this is to just use a different variable.
<property name="classpath" location="${env.JAVALIBPATH}"/>
This will then work, no fuss, with both <javac> and <java> commands (classpath="${classpath}) which is good, because if you try this instead:
<property name="classpath" location="${env.CLASSPATH}"/>
There is no includeAntRuntime="false" option to <java> which would allow this to work. You simply cannot get $CLASSPATH in and someone has gone to lengths to make sure of it (without, apparently, and yikes, adding in a ponderous javascript hack).
Of course that means you need to use a separate env variable and for your distributed/production version stick to the Java "Sorry no user libs!" paradigm. That's not a big problem if you use a variable name that, if it becomes involved, will almost certainly be undefined on the target system.
Alternatively, there are the Maven Ant Tasks. These will allow you to use Maven's dependency mechanism in a way that, IMO, is cleaner than Ivy. But it's still not a great solution.
Soo... seems I have to answer the question myself. Passing the original classpath to the javac task can be achieved with this:
<!-- load environment into the env property -->
<property environment="env" />
<javac srcdir="${src}" destdir="${obj}"
includes="**/*.java"
excludes="**/package-info.java **/deprecated/*.java"
includeAntRuntime="no" includeJavaRuntime="no"
debug="true" debuglevel="source,lines"
>
<!-- add -classpath option manually -->
<compilerarg value="-classpath" />
<compilerarg value="${env.CLASSPATH}" />
<compilerarg value="-Xlint"/>
</javac>
That does the trick at least so far that the javac task now gets passed the correct classpath. Yet it will still not work, javac now spits these complaints:
[javac] warning: [path] bad path element "D:\local\lib\java\*": no such file or directory
[javac] warning: [path] bad path element "C:\lib\java\*": no such file or directory
[javac] warning: [path] bad path element "C:\lib\java\db\*": no such file or directory
This is a straight lie, these paths do very much exist. I use them all the time, and if I manually craft an equivalent javac invocation at the shell, it works like a charm. I suspect ant's javac doesn't resolve the jar files in those directories. I have to examine that.
UPDATE
It is indeed as I suspected, the wildcard is not resolved to the individual present jar files by the javac task. I managed to do the resolving manually, and now it works as it should. And that resolving was in fact a struggle on its own. So I'll leave the solution here for those poor souls fighting the same stupidity, hopefully before they ask people that have nothing else to do than bullshitting around (yes Anon, talking about you).
Turns out, ant lacks the most basic functionality that you would expect from a build tool. Also turns out that I'm not the first one to notice that. While solutions are rare, there is a very good post about Using JavaScript to make Apache Ant less painful, which really saved my day. Yes, ant can indeed be scripted, which seems not to be widely known, although it is not kept secret. You can safely assume, that Javascript is already available without installing additional libraries if you run ant on Java 6.
Soo... down to business. Here is the thing:
<target name="expand_classpath">
<script language="javascript"><![CDATA[
// the original classpath
var ocp = java.lang.System.getenv("CLASSPATH");
// ... split in parts
var ocp_parts = ocp.split(project.getProperty("path.separator"));
// where our individual jar filenames go,
// together with pure directories from ocp_parts
var expanded_parts = [ ];
for each (var part in ocp_parts) {
if (part.endsWith('*')) {
var dir = part.substring(0, part.length() - 1);
var f = new java.io.File(dir);
// don't know how to construct a java.io.FilenameFilter,
// therefore filter the filenames manually
for each (var file in f.listFiles())
if (file.getPath().endsWith('.jar'))
expanded_parts.push(file.getPath());
} else
expanded_parts.push(part);
}
var expanded = expanded_parts.join(project.getProperty("path.separator"));
project.setProperty("classpath.expanded", expanded);
]]></script>
<!-- <echo message="classpath.expanded = ${classpath.expanded}" /> -->
</target>
<target name="build" depends="expand_classpath">
<mkdir dir="${obj}" />
<javac srcdir="${src}" destdir="${obj}"
classpath="${classpath.expanded}"
includes="**/*.java"
excludes="**/package-info.java **/deprecated/*.java"
includeAntRuntime="no" includeJavaRuntime="no"
debug="true" debuglevel="source,lines"
>
<compilerarg value="-Xlint"/>
<compilerarg value="-Xlint:-fallthrough"/>
</javac>
</target>
I will assume that your "popular" JARs are well-known open-source projects. This means that they're available in the Maven central repository.
While I believe that using Maven is the best answer to this question, you can also hack something using Ant's <get> task. For example, to download the JUnit JAR (may have typos):
<property name="dependency.dir" value="${basedir}/dependencies"/>
<property name="junit.jar" value="junit-4.8.2.jar"/>
<property name="junit.url" value="http://search.maven.org/remotecontent?filepath=junit/junit/4.8.2/${junit.jar}"/>
<target name="download.dependencies">
<mkdir dir="${dependency.dir}/>
<get url="${junit.url}" dest="${dependency.dir}/${junit.jar}"/>
</target>
Of course, if you do this then you'll have to carefully configure your build scripts so that you don't do the download with every run. And you'll increase load on the Maven Central repository.
By specifying "-lib foo.jar" to ant I get the behaviour that the classes in foo.jar is added to the ant classloader and are available for various tasks taking a class name argument.
I'd like to be able to specify the same behaviour but only from inside build.xml (so we can do this on a vanilla ant).
For taskdefs we have functioning code looking like:
<taskdef resource="net/sf/antcontrib/antlib.xml" description="for/foreach tasks">
<classpath>
<pathelement location="${active.workspace}/ant-contrib-1.X/lib/ant-contrib.jar" />
</classpath>
</taskdef>
where the definition is completely provided from the ant-contrib.jar listed.
What is the equivalent mechanism for the "global" ant classpath?
(I have thought out that this is the way to get <javac> use ecj-3.5.jar to compile with on a JRE - Specifying the Eclipse compiler completely from _within_ build.xml - in a way compatible with ant 1.7. Better suggestions are welcome :)
EDIT: It appears that the about-to-be-released version 1.0 of ant4eclipse includes ecj. This does not answer the question, but may solve my basic problem.
if you ever decide to move to Ant 1.8 you can use following construction:
<import>
<javaresource name="resource_name.xml">
<classpath location="path_to_jar.jar" />
</javaresource>
</import>
I've posted an answer to the question that you've linked. I'll repeat a general solution here.
Reading Running Ant via Java, I think you can write a simple wrapper that will properly set a classpath and add any 3rd party library to the resulting class path.
Here I'm just cutting and pasting the sample from the above link with addition of the library to the classpath:
<java
classname="org.apache.tools.ant.launch.Launcher"
fork="true"
failonerror="true"
dir="${sub.builddir}"
timeout="4000000"
taskname="startAnt"
>
<classpath>
<pathelement location="${ant.home}/lib/ant-launcher.jar"/>
<pathelement location="/path/to/3rd-party-lib.jar"/>
</classpath>
<arg value="-buildfile"/>
<arg file="${sub.buildfile}"/>
<arg value="-Dthis=this"/>
<arg value="-Dthat=that"/>
<arg value="-Dbasedir=${sub.builddir}"/>
<arg value="-Dthe.other=the.other"/>
<arg value="${sub.target}"/>
</java>
I think you can even reuse the same build file by referencing ${ant.file}, just give a different target as an entry point.
EDIT
I think, this solution should only be used as a last resort measure. If task in general supports a <classpath> tag, then add required libraries locally to that specific task. Your gave a perfect example of this in your question with an ant-contrib taskdef.
As an experiment we want to build our products using the Eclipse java compiler (ecj-3.5.jar downloaded from eclipse.org) on the runtime version of Java 6 instead of the JDK, and as I understand it, it is a matter of adding this jar to the ant classpath, and setting the build.compiler property to point to the adapter.
By including
<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter" />
in my build.xml and invoking ant with a JRE, I get the expected error that the adapter cannot be found, and by adding ecj-3.5.jar to the classpath in the Eclipse panel I can compile my code as expected. I believe the same functionality to be available with "-lib foo.jar" from the command line with modern ants.
Now, I want to specify from within build.xml that I want ecj-3.5.jar on my classpath satisfying the same as above. We can already do this with ant tasks, so I believe it is possible.
So the question is: How can I add to the classpath used by javac to locate the compiler only from within build.xml?
It appears that the upcoming ant4eclipse 1.0 includes the Eclipse compiler (which is what I wanted to use this for), so by upgrading to that (from 0.5) should solve the problem we have.
2010-09-24: Ant4Eclipse is still at M4 without indication of when the release will happen.
2011-12-01: We have now migrated from ant to maven. The build.xml scripts hit the complexity wall and a fresh approach was needed. Anyone needing to choose what to do - do not go the ant4eclipse path except for trivial projects.
2012-11-30: A year later, the maven experience is still mostly good. There is a lot of quirks and changes in mindset but most make sense in the context. Maven can specify the compiler level on individual projects easily. We are looking into using ecj instead of javac (for several reasons) but for most purposes javac works nicely.
One way is to specify a reference to a componentdef when using javac.
<componentdef name="ecj"
classname="org.eclipse.jdt.core.JDTCompilerAdapter"
classpath="ecj-3.7.1.jar" />
<javac ....>
<ecj/>
</javac>
Another option is to set build.compiler as you have or the compiler attribute for javac and then specify a compilerclasspath for javac. This is a normal path like structure to hold the classpath for loading your compiler adapter.
<javac compiler="org.eclipse.jdt.core.JDTCompilerAdapter" ....>
<compilerclasspath>
...
</compilerclasspath>
</javac>
See the javac task documentation in the Ant manual for more details. Note that both these both solutions only work from Ant 1.8 onwards.
Reading Running Ant via Java. I think you can write a simple wrapper that will properly set a classpath and add your jar file to the resulting class path.
Here I'm just cutting and pasting the sample from the above link with addition of the library that you are interested in to the classpath:
<java
classname="org.apache.tools.ant.launch.Launcher"
fork="true"
failonerror="true"
dir="${sub.builddir}"
timeout="4000000"
taskname="startAnt"
>
<classpath>
<pathelement location="${ant.home}/lib/ant-launcher.jar"/>
<pathelement location="/path/to/ecj-3.5.jar"/>
</classpath>
<arg value="-buildfile"/>
<arg file="${sub.buildfile}"/>
<arg value="-Dthis=this"/>
<arg value="-Dthat=that"/>
<arg value="-Dbasedir=${sub.builddir}"/>
<arg value="-Dthe.other=the.other"/>
<arg value="${sub.target}"/>
</java>
I think you can even reuse the same build file, just give a different target as an entry point.