Building C++ projects with ANT

New product is available!

The introduction below still remains valid for JunC++ion users, but a much better technology has arrived: terp! terp is Codemesh's brand-new product which allows you to perform complex C++ build tasks from within ANT. Please visit the terp documentation for more details.

Introduction

ANT, a popular Java-based build system, comes with a lot of built-in support for the general and for the Java side of the build process. There are built-in wrappers for tasks like

  • moving, copying, and modifying files based on patterns
  • running an arbitrary process with arbitrary arguments
  • running Java applications
  • compiling Java code
  • generating Javadoc
  • etc.

Unfortunately, there is no really good C++ compiler abstraction available. Codemesh provides a C++ compiler abstraction that works with all supported compilers to address this shortcoming. The benefit of using the compiler abstraction lies in its internal knowledge of how a certain abstract feature (like "enable/disable exception handling") translates into a compiler switch. The following (line-numbered) ANT build script snippet gives you an idea about the power of using the C++ compiler abstraction:

 1    <cc>
 2      <shared value="jms" />
 3      <targetdir value="${target.dir}" />
 4      <tempdir value="${temp.dir}" />
 5
 6      <include location="${source.dir}" />
 7      <include location="${source.generated.dir}" />
 8      <sources dir="${source.dir}" includes="*.cpp" />
 9      <sources dir="${source.generated.dir}" includes="*.cpp" />
10      
11      <define name="JMS_DECLSPEC" value="__declspec(dllexport)"
12              os="win32,win64" />
13      <define name="JMS_DECLSPEC" value=""
14              notos="win32,win64" />
15
16      <debug value="${debug.flag}" />
17      <multithreaded />
18      <dynamic />
19      <rtti />
20      <bool />
21      <exceptions />
22      <usecompilerdirectories />
23
24    </cc> 

Let's take a look at some key points of this snippet:

  1. Anything between lines 1 and 24 represents a C++ compiler invocation with the arguments based on the nested elements. <cc> is the generic C++ compiler task, which will search for a default compiler to use. There are more specific subclasses of <cc>, for example <msvc> representing the Microsoft Visual C++ compiler or <gcc> representing the GNU C++ compiler.
  2. Line 2 instructs the compiler to build a shared object (DLL on Windows) with the basename "jms". This will for example result in a file called "libjms.so" on Linux and a file called "jms.dll" on Windows.
  3. Lines 3 and 4 specify directories used by the build. Observe the flexibility gained by using build variables for the values.
  4. Lines 6 and 7 specify directories to be added to the preprocessor's search path (include path).
  5. Lines 8 and 9 specify the source files that need to be compiled. As you can see, the <sources> element is an ANT fileset and allows you to use pretty sophisticated patternmatching.
  6. Lines 11-14 specify a preprocessor definition (commonly called a macro). You can see one of the features that are available for all compiler options: a platform selector. Here, we have two different values for the macro: one for the Windows platforms and one for everything else. You can also select by compiler.
  7. Lines 16-22 specify various additional build options.

This example just provides a glimpse of the power and flexibility that you gain from using the ANT compiler wrapper. In addition to directly specifying the options in the compiler invocation, you can also define compiler options sets via a <ccopts> element and then just reference the predefined options from the compiler invocation.

Requirements

The Codemesh C++ compiler wrapper tasks require at least ANT 1.6.5 and a Java 1.4 or higher JRE. The tasks use some deprecated ANT APIs, so there is no guarantee that they will work with later versions of ANT, which might remove these deprecated APIs.

Specifying the compiler to use

As mentioned above, you can use the <cc> task and allow the ANT task to pick a compiler for you. This usually works great for our product evaluation, when we cannot know where your compiler is installed, what platform you're on, and if your compiler is in a "default" location. If you need more control, you can of course specify which compiler to use. First, you can always directly specify the compiler via an attribute, for example

<cc compiler="/opt/gcc-3.4.3/bin/g++">
  ...
</cc>

This might be all the flexibility you ever need (particularly if you also use a build variable rather than a hard-coded string value). We have gone one step further and provided you with various ways to specify default values for the compiler task(s). First, you can specify a value for the cpp.compiler property to pick the default compiler used by the <cc> task. Think of this property as the built-in variable for the C++ compiler.

But there are also the compiler-specific wrappers. <cc> could stand for any (supported) C++ compiler. The following table lists the tasks that stand for a specific compiler type and the properties you can use to override or specify which compiler they invoke by default.
 

Compiler element Compiler path property name Description
<acc> hp.compiler HP C++ compiler
<gcc> gnu.compiler GNU C++ compiler
<msvc> msvc.compiler Microsoft Visual C++ compiler
<suncc> sun.compiler Forte/Sun Workshop C++ compiler
<vacc> ibm.compiler Visual Age C++ compiler (AIX)

For example, the following two snippets would have identical results:

<suncc compiler="/opt/SUNWspro/bin/CC">
  ...
</suncc> 
<property name="sun.compiler" value="/opt/SUNWspro/bin/CC" />
 
<suncc>
  ...
</suncc> 

Using the default compiler location properties gives you a lot of flexibility because you can pass the compiler path on the command line of your ANT invocation.

Platform and compiler switches

As mentioned in the introduction, all nested elements support platform and compielr selectors. You can define build options on a per platform, per compiler, or even combination of compiler and platform basis. The following snippet demonstrates how to define a preprocessor macro only for the GNU C++ compiler:

<define name="_REENTRANT" compiler="gcc" /> 

To select by platform, simply use the os or notos attributes. You can supply a comma-separated list of platform identifiers as the attribute value. The following table lists the supported platform identifiers.
 

Platform identifier Platform
aix IBM AIX
darwin MacOS-X 10.x
hpux HP-UX
linux Linux
sunos Sun Solaris
win32 Windows 32bit
win64 Windows 64bit

To select by compiler, simply use the compiler or notcompiler attributes. You can supply a comma-separated list of compiler identifiers as the attribute value. The following table lists the supported compiler identifiers.
 

Compiler identifier Compiler
acc HP C++ compiler (aCC)
gcc GNU C++ compiler (g++)
msvc Microsoft Visual C++ compiler (cl)
suncc Forte/Sun Workshop C++ compiler (CC)
vacc VisualAge C++ compiler (xlC)

Compiler task attributes

The compiler tasks (<cc>, <acc>, etc.) support several optional attributes. The table below provides an alphabetic list of the supported attributes:
 

Attribute name Description
basedir The base directory for the compiler invocation.
compiler The fully qualified compiler path.
noarguments Set to true if you don't wish to pass any options to the compiler. You should never have to use this option. Default is false.
noforcedcompileonly Set to true if you wish to prohibit the compile-only mode for the compiler. Default is false.
showcommands Set to false if you don't wish to see the commandline options that are used. Default is true.
showonly Set to true if you only wish to see the commandline that would be invoked. Default is false.

Compiler task nested elements

Virtually all interesting compiler options are supplied via nested elements. All nested elements that are described here can also be added to a <ccopts> element. <ccopts> elements in turn can be incorporated into a compiler task by reference. The following snippet illustrates how you can declare some shared compiler options and use them by reference:

<ccopts id="shared.opts">
  <include location="${shared.source.dir}" />
  <sources dir="${shared.source.dir}" include="*.cpp" />
  <define name="_REENTRANT" compiler="gcc" />
  <multithreaded />
  <rtti />
  <exceptions />
</ccopts>


<cc>
  <ccopts refid="shared.opts" />
  <exe value="test" />
  <sources dir="${source.dir}" include="*.cpp" />
</cc>

In the above snippet, the options represented by the <ccopts> element with the ID "shared.opts" are included by reference in the C++ compiler invocation.

Compiler- and platform-specific options

All nested options support the compiler, notcompiler, os, notos, if, unless, and version attributes. These optional attributes allow you to apply an option only for a certain operating system, compiler, compiler version, or a generic ANT condition. The following example applies the debug option only for Microsoft compilers of version 13 or higher.

<debug compiler="msvc" version="13+" /> 

Some options are implicitly designed for a particular compiler and do not require you to specify a compiler attribute. The <machine> linker setting for example is implicitly designed for the Microsoft Visual C++ linker.

Boolean (on/off) options

As you can see, on/off options like <multithreaded/> or <rtti/> do not require you to add a value attribute to represent the on state. If you wish to turn the option off, you have to add a value attribute, as in

<rtti value="false" />

There is a free form option element that can be used if there is no compiler task abstraction available. The element is simply named <option> and expects you to provide information indicating whether the option is a compileroption or a link option. For example:

<option value="-qopt" compileroption="true" link="false" /> 

The following table lists all compiler/compiler options nested elements.

Nested element Description Comments
abimode Specifies the ABI mode.  
archive   Build an archive (a static library). The value should be the basename of the archive without any file prefixes or suffixes.
bool Set to true if the bool type is natively supported. Most modern C++ compilers support the bool type by default. Usually you only specify this option if you wish to turn off support for the bool type.
compileonly Set to true if only compiler and not linker should be invoked. A boolean option corresponding with the -c option in most C++ compilers and resulting in the creation of object files.
debug Set to true if a debug build is desired. A boolean option turning on debugging support.
define Defines the preprocesor macro name to the given value.  
dynamic Set to true if dynamic runtime libraries are to be used. Useful for the Microsoft compiler to choose the DLL versions of the runtime library.
exceptions Set to true if a exceptions are supported.  
exe    
implib    
include Addes the specified directories to the preprocessor search path.  
libdirs Adds the specified directories to the library search path. A CCPath element that allows you to specify a library search path using the full feature set of the ANT Path element.
library Adds the specified library to the linker invocation. Supports mutually exclusive static and dynamic attributes. A CCLibrary element that supports fully qualified library names as well as simple library names. You can also specify a static or a dynamic attribute to govern linkage.
nologo Set to true to suppress compiler/linker logo.  
machine Specifies the /MACHINE: linker switch.
Only used by MSVC compiler.
 
multithreaded Set to true to enable multithreading.  
pack Specifies the alignment.  
relocatable Set to true to make resulting module relocatable.  
rtti Set to true to enable RTTI support.  
shared    
sources An ANT fileset specifying input files for the compiler. Yes
subsystem Specifies the /SUBSYSTEM: linker switch.
Only used by MSVC compiler.
No / null
targetdir Set to directory which receives the build result. No / build directory
tempdir Set to directory which receives temporary/intermediate output files No / build directory
undefine Undefined preprocessor macro of given name. No
usecompilerdirectories Set value to true if compiler-internal directories (include and library search path) should be used.
Only used by MSVC compiler.
No / false
warninglevel    

Examples

[TBD]

 


Copyright 2006-2011 by Codemesh, Inc., ALL RIGHTS RESERVED

:
ant c++
home products support customers partners newsroom about us contact us