 |
Please see the New Build Process FAQ for a quick explanation of what the new build process provides beyond the old process. |
 |
Please see Build Process Converted Components for a list of components and versions that have been converted.
There is an ongoing effort made internally at TopCoder to switch all the components to this new building format so there are even more components than the ones specified in the page linked above. |
Overview
Generally the principles of the build process are:
- Build scripts that require no component specific customization.
- All component specific configuration is external to the build script.
- Standard version rules are used for all components in a fashion that will prevent broken builds.
- Third party libraries can be easily adjusted for all components in build environment.
1. Setup the System Environment
This will install the major system components of Java and Ant required for building most Java based products. Please note that there are many versions of Java and Ant available. TopCoder certifies components for the environment specified in the component's Design Specification. If another environment is used then the component should be re-certified. Ant provides a lot of flexibility, these instructions provide an intended process to be followed, other processes may also yield working results.
1.1. Install JDK
- Download
and install the JDK required by the component to build.
- Set an environment variable JAVA_HOME to the installation directory
- JAVA_HOME should be the parent directory of jre and lib directories
1.2. Install ANT
- Download
and install ANT.
- Set an environment variable ANT_HOME pointing at the installation directory
- ANT_HOME should be the parent directory of bin and lib directories
2. Setup a TopCoder Build Environment
This step will install the required libraries that are standard to all TopCoder components. JUnit is used as a testing harness to run unit, accuracy, failure, and stress tests packaged with each component. Cobertura is used to provide a test coverage report. A standard directory structure is also defined to ensure each component runtime jar is placed in the correct place for other components that may depend on it. Finally a standard properties file is used to provide environment configuration for the build scripts.
2.1. Install JUnit
Download JUnit\
(you need the Jar file.)
2.2. Install Cobertura
The following directory structure should be followed exactly:
- Cobertura Install Directory (currently TopCoder uses version 1.8)
- cobertura.jar
- lib (contains libraries Cobertura uses)
- Jar file for ASM (cureently version 2.2.1)
- Jar file for Jakarta ORO (currently version 2.0.8)
- Jar file for log4j (currently version 1.2.9)
2.3. Designate Source and Library Directories
TopCoder relies on a top level source directory which contains all the Java components as sub directories. The exact name of the Java component directory is flexible. For example a component could be called ConfigurationManager or ConfigMgr-2.1.5 and the build process will work in either case. An example of this directory might be: c:\code\topoder\java-components\
TopCoder components build to a standard location specified by the build configuration, this ensures that the binary jar for a given component version is in a unique location on the build system. Additionally it ensures that components which depend on that binary will find it. And example of this directory might be: c:\code\lib\topcoder-java\
2.4. Setup topcoder_global.properties file
The build scripts depend on a common build properties file in addition to those which are packaged with the component. This file describes the overall build properties for the specific integration box, including:
- The TopCoder Library directory
- The TopCoder integration environment uses ext_libdir as the parent for all third party libraries, however it's not necessary to setup your environment in this fashion, by having each individual jar or dir property point to the exact path.
- The install location of Cobertura and JUnit for all components
- Note the build file just references standard properties junit.jar and cobertura.dir to allow for upgrading to newer versions of these tools without editing the build-dependencies.xml file
- The location of third party libraries (as needed for components on a case by case basis)
- Standard build parameters
3. Java component file structure
The general files and directories for a Java component are:
- README - instructions for setting up this component for build
- build.xml and build_dist.xml - ant build script
 | TopCoder uses build.xml as an internal build file, containing targets used in publishing components, and build_dist.xml as the external build file (identical, but with the distribution targets removed.) If you have download directly from SVN both files are likely to be in your distribution. If you download from the website, the build_dist.xml file is moved to build.xml. In the case that you have both, it's okay to use either file.
When downloading those files from SVN for building these files are suposed to be modified ONLY IF they are outdated and in this case you need to replace them with their latest versions. The modifications to be done when building should be made in build.version, build-dependencies.xml and build-override.xml if necessary.
You can see in the Master build files location that there is a directory for the generic components and a directory for each of the TopCoder's major clients for Java components. When building the component be sure to choose the build files from the right directory by taking into account whether they are generic or custom. |
- build.version - specific component version information, including version number and component name
- Component versions are specified as major.minor.micro.build - the public version is major.minor.micro and is used by components to find their dependencies. The full version is used for internal management and non-software changes, such as updating documentation.Whenever a modification is done in svn for a specific public version for a component (major.minor.micro) the value for component.version.build is incremented.
Let's say we're having a specific component A with version to be retrieved from the catalog - 1.0.1 . If there are small changes made on the component which don't need a public version incremented (like 1.1.3) released for the component, the only thing which changes regarding the component version will be the value for component.version.build property which will be always incremented.
So component A could have version numbers like these ones: 1.0.0.1 ; 1.0.1.1 ; 1.0.1.2 ; 1.0.1.3 ; 1.1.0.1 .
- build-dependencies.xml - configuration for the TopCoder and third party dependencies, specific to this component
Note the format used for referencing the dependencies : ${component.repository}/${component.name}/${component.version}/${component.jar.name}
Also note that the values set for component.target and component.bootclasspath (its value in this example is taken from the global properties file) will be used when executing compile_targets target.
In the previous examples that all libraries are specified only by using their name (base_exception.jar, configuration_api.jar, junit.jar, antlr.jar) without specifying in the property name the version number as well. This detail is very important as on the assembly phase the assembler can define properties for the libraries used by him in the topcoder_global.properties file (overriding in this way the property values defined in build-dependencies.xml file - very important when the project needs a specific library version for a library (ex: log4j-1.2.12.jar), but a component has been built with reference to another version of that library (ex: log4j-1.2.9.jar)).
This is the reason why the build-dependencies.xml file is NOT allowable to have structures of this kind:
or
because this would prevent someone from using the libraries that were specified in topcoder_global.properties file.
It seems tedious at first having to write by hand property declarations for all the libraries of a framework from a component developer point of view, but from a assembler point of view this is the way to go (for making things easier for himself the developer should write small apps which would scan the directory structure of the framework and automatically generate xml property declarations and from which the developer should have to remove the libraries not needed in compiling/testing his component).
Example of the above properties as specified in the global properties file:
You can see above that the version number for junit.jar library is 4.4 and is different from the value used in build-dependencies.xml file (3.8.2).These properties are easiest specified in the global properties file. Note that components may overlap their dependencies, so by default all components that use junit.jar will use the same version of it. The integration environment should be setup with the same dependencies as application's will use for best results.
Another thing that is worth talking about here is the way in which the libraries are referenced. In the examples bellow can be seen that a TopCoder dependency is declared:
or that a third party library is declared in the following way :
or this way :
- build-override.xml - this is an OPTIONAL file used in building components and is to be used only when the common behavior of the targets defined in build.xml file NEEDS to be overridden (e.a. when testing with cactus the component) or there is a need for custom targets in the build script.
There will be shown several examples on how this file should look like in order to give you a better understanding of its purpose. Please note in this samples that there are defined extra targets which don't fit in the generic build file and macrodef
instructions which have the ability to be overridden when they are declared several times in the build scripts. Since ANT doesn't have the ability to override targets, using macrodef tasks is used as solution for this kind of problem.
If you have the curiosity to read the master buid file (build.xml) you can see build-dependencies.xml file and optionally build-override.xml file are imported in the master build file. So you don't have to worry that some of the properties are not seen in those files by the intellisense of some of the IDEs used to edit those build files. A good practice when you develop the build files is to add a temporary import statement for the build.xml file and this way you have all the properties correctly highlighted in you IDE. When you finish developing the build-dependencies.xml/build-override.xml file you can remove the temporary import statement.
- conf - configuration files for the component
- docs - documents of the component
- Typically this directory needs to include a fileset of documents having this format :
Note that ${distfilename} represents the component distribution file name.
The documents belonging, if it is the case, to a previous version of the component need to be removed from docs/ directory when adding in svn the new version. Be sure to have the files from docs/ directory matching EXACTLY the format specified earlier.
To help out what I'm trying to say here I will add an image on how the structure for docs/ directory should look like.

- test_files - file resources needed for testing
- test_reflib - this is an OPTIONAL directory containing TopCoder components that are used by the test code
- Please note these runtime jars are provided for the purposes of compiling and running the test code, not for any other use, including production. The components that are required for the production code must be referenced in the build-dependencies.xml file.
- To make things coherent please keep the same structure in this directory for the libraries included as in tcs_libdir. An example file structure of test_reflib/ directory would be the following:
Note that the location from which can be retrieved the files needed in building is
Master build files
Note that in this location can be found build files for generic components in generic
directory, but also build files specific for each of TopCoder's clients to be used in building custom components.
3.1. Configure the environment.
You should read the component specification first, make sure in what environment the component will be run. It may include the following issues:
Platform - Windows, Linux, etc
Compiling Target - Java 1.3/1.4/1.5
Dependencies - Including TopCoder or third party components, required version of these components should be used.
Especially for custom ones, for example if the tests compiled successfully under Oracle 10.2, but failed under Oracle 10.1, and the required version is the latter, you should report it to PM. It is very important to respect the constraints imposed by the Component Specification regarding the Environment Requirements.
3.2 Remove useless files
Remove auto-generated files like :
- conf/putYourConfigFilesHere.txt
- test_files/putYourTestFilesHere.txt
- .txt files from ${srcmain}
- Thumbs.db (this files can be added by mistake in the submission, but they are useless)
Remove also the files which are not really needed by the distribution of the component. I mean here files like .txt files containing details about the final fixes, .log files.
Remove all mocked files, use real dependencies, you can find the dependencies from http://software.topcoder.com/
. If the dependencies have not been built yet, report it to PM. If the component could not compile and execute successfully using the real dependencies, report it to PM.
3.3. Deploy Dependent Components
In the file build-dependencies.xml there is a listing for each TopCoder component and version that is a dependency. The runtime jars for each of these components must be deployed to the TopCoder library location for the build to work. The pattern is ${tcs_libdir}/"component name"/"component version"/"component name".jar. For example using the above value for tcs_libdir, the current version (1.1.0) of typesafe enum component would be located at: c:/code/lib/topcoder-java/typesafe_enum/1.1.0/typesafe_enum.jar
These jars can either be downloaded and saved in the correct location - or by running the build for each dependent component.
3.4. External libraries directory structure.
TopCoder is not allowed to re-distribute the 3rd party libraries on which some of the components are dependent (like junit for example). This is the reason why attached to document you will find here
a listing of TopCoder's ${ext_libdir} directory. Please structure your ${ext_libdir} directory in the same way as TopCoder has structured these libraries to avoid having problems when integrating the component on the Bamboo server.Note that there will be other libraries added, when needed, to the external libraries directory on the Bamboo machine, so please check out from time to time if anything has updated on the 3rd party directory listing
.
4. Custom testing scenarios used in the build scripts
4.1. Performing initialization/cleanup operations when testing against a database
As you have seen in chapter 3 of this document in build-override.xml can be scripted custom testing scenarios for the components which need extra initializations/cleanup for the testing environment.
One of the most common types of components are the ones which are interacting with databases.Here will be detailed how to handle this kind of scenario. As an example will be used the component Auction Framework which can be found in TopCoder SVN repository here
.
Bellow you can see the content of the build-override.xml file for this component:
As you can see in the overriden test.setup and test.teardown overriden macrodef elements two files are reffered:
- test_files/dbsetup.sql
- test_files/dbteardown.sql
In order to provide you with the details needed to comprehend this kind of testing scenario the content of those two files will be presented here:
For having an example on how to setup/teardown the testing environment for a component that needs Informix Db Engine check out from Ban Management Persistence SVN Repository
the files:
- test_files/dbsetup.sql
- test_files/dbteardown.sql
which should give you a starting point on how to handle this thing.
For testing a component that needs Oracle db, please check the section 4.2.2 from the document http://www.topcoder.com/wiki/display/tc/.Net+Component+Build+Process
and you'll have the details necessary to complete this task.
So to summarize when encountering components which need db initialization / cleanup you must :
- create the .sql scripts for initialization/cleanup of the database. Note that the database name is not a common name, it is the build key (TCJAVA-23768027) of the Bamboo plan for the component(this way we ensure that it is unique and doesn't collide with the databases created by some other components). If the component requires more databases for testing, use the build key as a prefix for the name of the databases.
- add a build-override.xml file in which override test.setup and test.teardown macrodefs. In test.setup you must run the scripts used for initializing the database schema & its tables. In test_teardown macrodef you have to drop the database created in test.setup
5. Build the Component
From the command line the following ant targets are most useful:
- ant compile - build the component code
- ant compile_tests - builds the test code
- ant compile_targets - verify if the component sources compile for the target JDK
- ant test - runs the unit tests
- ant coveragereport - generates test coverage reports
- ant reports_all - builds the JUnit and Cobertura jars
- ant deploy-lib - tests the component and then moves the runtime jar to the standard library
- ant dist_tcs - moves the runtime jar as well as the jar containing the distribution of the component to the library directory.
- The library directory component will be ${tcs_libdir} for a generic component, but can also be the library directory for the client's components in case if a custom component is built.
6. Commit the modifications made on the component after the build is done to SVN
Please make sure, before commiting, that every change made to the component (from file additions to modifications or remove of useless files) to appear in the Commit dialog.
You should log the modifications you made when updating the svn, including trivial things like "Useless files are removed". Normally when the building of a component is done you should put a comment like "Build x.x.x.x successful" where x.x.x.x is the version for the component.
At the end of this process, the SVN file structure of the component to be built will look like this :

Be sure always to check if the file structure is similar to what can be see in the image presented earlier.
The file build-override.xml can be present in this file structure when, as it was previously stated, a custom test scenario is made or custom targets are needed in the build script.
In the case one or more of the conf/, test_reflib/, test_files/ directories are empty you don't need to add them to svn as they are useless in this case for the component.
You may also find some other files in the trunk/ of the component (like bamboo_build.xml, Changelog.txt, etc.). Please leave them as they are as they concern internal operations made at TopCoder.
In the image above you can see that some of the items are highlighted in yellow. Please pay extra-attention to having all these items in svn and updated correctly to match the component's needs.
Please feel free to comment any of the details presented in this tutorial if you feel that it can be polished to be easier to understand or if there is more information needed.