[antlr-interest] Antlr ANT task: Seemless builds using the Antlr - Problems and solutions. Help appreciated!

M C mortench2004 at yahoo.dk
Sun Apr 17 04:47:48 PDT 2005


Hi all,

This mail is about my "hard time" integrating the
Antlr ANT task in a seemless build enviroment. It
detils some solutions, some unsolved problems and a
request for changes in the next Antlr version.

For seemless integration I wanted to use the ANTLR
task to:
1) Automatically pick up all *.g files in whatever
src\** directories and generate *.java files
and place them in corresponding build\generatedsrc\**
directories (this assumes that the *.g files are
placed in a sub directory under the main source
directory that corresponds to the package the
resulting java files will have when put in the
generatedsrc build directory. ).

2) Generate grammar doocumentation and place it in doc
directory.

3) Only generate *.java and documentation files if the
*.g files have changed (timestamp of *.g files are
newer than the generated *.java files).

Unfortunately, unlike the javac task the antlr ant
task has key limitations:
a) Does not allow for multiple *.g files.
b) Does not provide direct support for mapping source
to destination paths.
c) Does not check timestamps.
d) Needs to be invoked twice to generate both *.java
files and documentation.

Despite the above limitation, I tried to use various
ANT extensions and complicated techniques to
accomplish my goals. See code below. The code is VERY
complex but it does conform to goals 1 and 2. However,
I could not get the timestamps to work. Consequently,
every time I build, the ANT ANTLR task generate new
java code, resulting in a long cascade of subsequent
build actions that are uncessary when nothing has
changed.

It would be really nice if the next version of Antlr
would provide a better ANT task that would allow for
integration into a seemless build enviroment.
Meanwhile, I would welcome if anyone have ideas for
improving the ANT workarounds I have detailed below:

Cheers,
Morten Christensen

----

<target name="generateparsers" depends="init">
	 <echo message="Generating source code parser(s) for
${ant.project.name}"/>

	<!-- Need to generate parsers for ALL *.g files from
whatever 
	     location. Unfortunately, the ANTLR task does not
allow
	     for multiple *.g files so we need to iterate
though
	     all *.g files -->
	<foreach target="generateparsers-antlr-subtask"
param="antlrGrammarFile">
		<path>
			<fileset dir="${mainsrc}">
				<include name="**/*.g"/>	
			</fileset>		
		</path>
	</foreach>
</target>
	
<target name="generateparsers-antlr-subtask"
if="antlrGrammarFile" description="internal helper
target">
		
	<!-- Need to calculate location in generatedmainsrc
that correspond to
	     location in src. I.e. outputDir =
${antlrGrammarFile} 
	     with substring ${srcmain] replaced with
${generatedmainsrc}.
	     Tricky using ANT - wish it could be easier.
	--> 

	<dirname property="inputDir"
file="${antlrGrammarFile}"/>
	<path id="mainSrcDirPath"
location="${basedir}${file.separator}${mainsrc}"/>
	 <pathconvert dirSep="${file.separator}"
pathsep="${file.separator}"
property="normalizedMainSrcDir"
refid="mainSrcDirPath"/>
	<path id="inputDirPath" location="${inputDir}"/>
	 <pathconvert dirSep="${file.separator}"
pathsep="${file.separator}"
property="normalizedOutputDir" refid="inputDirPath"/>
	<path id="normalizedOutputDirPath"
location="${normalizedOutputDir}"/>
	 <pathconvert dirSep="${file.separator}"
pathsep="${file.separator}" property="outputDir"
refid="normalizedOutputDirPath">
	    <map from="${normalizedMainSrcDir}"
to="${basedir}${file.separator}${generatedmainsrc}"/>
	 </pathconvert>
		
	<!--
	Would like to only run antlr task on *.g files that
	are newer than the generated java files.
Unfortunately,
	I can't make the code update property initialize
	itself correctly.
		
            <uptodate
property="checkAntlrGrammarFileChanged">
	      <srcfiles dir= "/"
includes="${antlrGrammarFile}"/>
	      <mapper type="merge" to="${outputDir}"/>
	</uptodate>
		
	<echo message="Uptodate? :
${checkAntlrGrammarFileChanged}"/>
	-->
		
	<!-- Create output dir on the fly and invoke antlr
(need to invoke antlr twice. Once for code, once for
docs). -->
	<echo message="Invoking antlr on grammar
${antlrGrammarFile} with code output to directory
${outputDir} and documentation output to
${referencedocs}"/>
	<mkdir dir="${outputDir}" />
	<antlr dir="."
	    target="${antlrGrammarFile}"
	    outputdirectory="${outputDir}"/>
	<antlr dir="." html="true"
	    target="${antlrGrammarFile}"
	    outputdirectory="${referencedocs}"/>
</target>
	


More information about the antlr-interest mailing list