aboutsummaryrefslogtreecommitdiffstats
path: root/make/build.xml
diff options
context:
space:
mode:
Diffstat (limited to 'make/build.xml')
-rwxr-xr-xmake/build.xml530
1 files changed, 530 insertions, 0 deletions
diff --git a/make/build.xml b/make/build.xml
new file mode 100755
index 0000000..2dadefc
--- /dev/null
+++ b/make/build.xml
@@ -0,0 +1,530 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ - Ant build for GlueGen and corresponding ANT tasks. Also builds
+ - JOGL-specific BuildStaticGLInfo and its corresponding ANT task.
+ -
+ - This build has been tested with ANT 1.6.2 and ANTLR 2.7.4.
+ -
+ - Public targets:
+ - all: clean and build GlueGen and GlueGen Ant task
+ - clean: clean all built
+ -->
+<project name="GlueGen" basedir="." default="all">
+
+ <!-- This is the version of GleuGen you are building -->
+ <property name="gluegen_base_version" value="1.0b07"/>
+
+ <!-- On jpackage.org-compatible systems, antlr.jar can be found in /usr/share/java -->
+ <available property="antlr.jar" file="/usr/share/java/antlr.jar"
+ value="/usr/share/java/antlr.jar"/>
+
+ <target name="load.user.properties" unless="user.properties.file">
+ <!-- Load the user specified properties file that defines various host
+ - specific paths. The user will be notified if this is does not
+ - exist. -->
+ <property name="user.properties.file" value="${user.home}/gluegen.properties" />
+ <property file="${user.properties.file}" />
+ <echo message="Loaded ${user.properties.file}." />
+ <fail message="antlr.jar was not specified in gluegen.properties. Please see README.txt for instructions" unless="antlr.jar"/>
+ <echo message="antlr.jar=${antlr.jar}" />
+ </target>
+
+ <condition property="rootrel.build" value="build">
+ <not>
+ <isset property="rootrel.build"/>
+ </not>
+ </condition>
+
+ <target name="setup-excludes-1" if="gluegen.nsig">
+ <property name="gluegen.excludes" value="" />
+ </target>
+
+ <target name="setup-excludes-2" unless="gluegen.nsig">
+ <property name="gluegen.excludes" value="com/sun/gluegen/runtime/BufferFactoryInternal.java,com/sun/gluegen/nativesig/**" />
+ </target>
+
+ <target name="init.javame.cdc.fp" if="isCDCFP">
+ <property name="javac.bootclasspath.jar" value="lib/cdc_fp.jar" />
+ </target>
+
+ <target name="setup.javase" unless="isCDCFP">
+ <copy file="../src/java/com/sun/gluegen/runtime/BufferFactory.java.javase" tofile="../${rootrel.build}/gensrc/java/com/sun/gluegen/runtime/BufferFactory.java" />
+ <copy file="../src/java/com/sun/gluegen/runtime/StructAccessor.java.javase" tofile="../${rootrel.build}/gensrc/java/com/sun/gluegen/runtime/StructAccessor.java" />
+ </target>
+
+ <target name="setup.javame.cdc.fp" if="isCDCFP">
+ <copy file="../src/java/com/sun/gluegen/runtime/BufferFactory.java.javame_cdc_fp" tofile="../${rootrel.build}/gensrc/java/com/sun/gluegen/runtime/BufferFactory.java" />
+ <copy file="../src/java/com/sun/gluegen/runtime/StructAccessor.java.javame_cdc_fp" tofile="../${rootrel.build}/gensrc/java/com/sun/gluegen/runtime/StructAccessor.java" />
+ </target>
+
+ <target name="init" depends="load.user.properties,setup-excludes-1,setup-excludes-2,init.javame.cdc.fp">
+ <!-- Declare all paths and user defined variables. -->
+
+ <!-- The source directories. -->
+ <property name="src.java" value="../src/java" />
+ <property name="build" value="../${rootrel.build}" />
+
+ <!-- The generated source directories. -->
+ <property name="src.generated" value="../${rootrel.build}/gensrc" />
+ <property name="src.generated.java" value="../${rootrel.build}/gensrc/java" />
+
+ <!-- The compiler output directories. -->
+ <property name="classes" value="${build}/classes" />
+
+ <!-- Call the external config validator script to make sure the config is ok and consistent -->
+ <ant antfile="validate-properties.xml" inheritall="true"/>
+
+ <!-- Create the required output directories. -->
+ <mkdir dir="${src.generated.java}" />
+ <mkdir dir="${classes}" />
+
+ <!-- Set up compilation for either Java SE or Java ME / CDC / FP. -->
+ <antcall target="setup.javase" inheritRefs="true" />
+ <antcall target="setup.javame.cdc.fp" inheritRefs="true" />
+
+ <!-- Create the classpath for ANTLR. This requires the user-defined
+ - "antlr.jar" property. -->
+ <path id="antlr.classpath">
+ <pathelement location="${antlr.jar}" />
+ </path>
+
+ <!-- The location of the GlueGen source and the C grammar files. -->
+ <property name="gluegen" value="${src.java}/com/sun/gluegen" />
+ <property name="c.grammar" value="${gluegen}/cgram" />
+ <property name="j.grammar" value="${gluegen}/jgram" />
+
+ <!-- The resulting location of the generated Java files from the
+ - C grammar via ANTLR. -->
+ <property name="gluegen.build" value="${src.generated.java}/com/sun/gluegen" />
+ <property name="generated.java.from.c.grammar" value="${gluegen.build}/cgram" />
+ <property name="generated.java.from.j.grammar" value="${gluegen.build}/jgram" />
+ </target>
+
+ <!--
+ - Using ANTLR generate the specified Java files.
+ -
+ - @param target the grammar file to process
+ - @param output.dir the directory to write the generated files to. If
+ - the directory does not exist, it will be created.
+ -->
+ <target name="generate.grammar">
+ <!-- Generate the Java files -->
+ <antlr target="${output.dir}/${target}" outputdirectory="${output.dir}">
+ <classpath refid="antlr.classpath" />
+ </antlr>
+ </target>
+
+ <!--
+ - Using ANTLR generate the specified Java files with an overridden
+ - grammar file.
+ -
+ - @param target the grammar file to process
+ - @param glib the overridding grammar file
+ - @param output.dir the directory to write the generated files to. If
+ - the directory does not exist, it will be created.
+ -->
+ <target name="generate.c.grammar.glib">
+ <!-- Generate the Java files -->
+ <antlr target="${output.dir}/${target}" glib="${output.dir}/${glib}" outputdirectory="${output.dir}">
+ <classpath refid="antlr.classpath" />
+ </antlr>
+ </target>
+
+ <!-- Use GlueGen to generate the source code for the NativeLibrary
+ implementation. Note that to make the build process simpler (in
+ particular, the nightly builds) we do not do this every time we
+ run the build, but instead check in the generated sources to
+ the source tree. -->
+
+ <property name="gluegen.root" value="../" />
+ <import file="gluegen-cpptasks.xml" />
+ <target name="generate.nativelibrary.sources" depends="init" >
+ <!-- Define the appropriate include paths -->
+ <dirset id="stub.includes.fileset.windows" dir=".">
+ <include name="stub_includes/windows/**" />
+ </dirset>
+ <dirset id="stub.includes.fileset.unix" dir=".">
+ <include name="stub_includes/unix/**" />
+ </dirset>
+ <dirset id="stub.includes.fileset.macosx" dir=".">
+ <include name="stub_includes/macosx/**" />
+ </dirset>
+ <!-- Define the classpath we should use -->
+ <path id="gluegen.classpath" >
+ <pathelement location="${classes}" />
+ <pathelement location="${antlr.jar}" />
+ </path>
+ <!-- Define the GlueGen task we just built -->
+ <taskdef name="gluegen" classname="com.sun.gluegen.ant.GlueGenTask"
+ classpathref="gluegen.classpath" />
+
+ <!-- Execute it against all of the OSs' header files -->
+ <gluegen src="stub_includes/windows/dynamic-linker.h"
+ config="dynlink-windows.cfg"
+ includeRefId="stub.includes.fileset.windows"
+ emitter="com.sun.gluegen.JavaEmitter">
+ <classpath refid="gluegen.classpath" />
+ </gluegen>
+ <gluegen src="stub_includes/unix/dynamic-linker.h"
+ config="dynlink-unix.cfg"
+ includeRefId="stub.includes.fileset.unix"
+ emitter="com.sun.gluegen.JavaEmitter">
+ <classpath refid="gluegen.classpath" />
+ </gluegen>
+ <gluegen src="stub_includes/macosx/dynamic-linker.h"
+ config="dynlink-macosx.cfg"
+ includeRefId="stub.includes.fileset.macosx"
+ emitter="com.sun.gluegen.JavaEmitter">
+ <classpath refid="gluegen.classpath" />
+ </gluegen>
+ </target>
+
+ <!-- ================================================================== -->
+ <!--
+ - Set up java.home.dir appropriately on all platforms.
+ -->
+ <target name="setup.java.home.dir.nonmacosx" depends="load.user.properties" unless="isOSX">
+ <!-- java home dir is up one directory as java.home points to '<java-install-dir>/jre' -->
+ <property name="java.home.dir" value="${java.home}/.." />
+ </target>
+ <target name="setup.java.home.dir.macosx" depends="load.user.properties" if="isOSX">
+ <property name="java.home.dir" value="/System/Library/Frameworks/JavaVM.framework/Home" />
+ </target>
+ <target name="setup.java.home.dir" depends="setup.java.home.dir.nonmacosx,setup.java.home.dir.macosx" >
+ <property name="java.includes.dir" value="${java.home.dir}/include" />
+ </target>
+
+ <!-- ================================================================== -->
+ <!--
+ - Compile the native C code for GlueGen's dynamic linker interface.
+ -->
+
+ <target name="declare.win32.vc6" if="isVC6">
+ <echo message="Win32.VC6" />
+ <property name="compiler.cfg.id" value="compiler.cfg.win32.msvc" />
+ <property name="linker.cfg.id" value="linker.cfg.win32.msvc" />
+ </target>
+
+ <target name="declare.win32.vc7" if="isVC7">
+ <echo message="Win32.VC7" />
+ <property name="compiler.cfg.id" value="compiler.cfg.win32.msvc" />
+ <property name="linker.cfg.id" value="linker.cfg.win32.msvc" />
+ </target>
+
+ <target name="declare.win32.vc8" if="isVC8">
+ <echo message="Win32.VC8" />
+ <property name="compiler.cfg.id" value="compiler.cfg.win32.msvc" />
+ <property name="linker.cfg.id" value="linker.cfg.win32.msvc" />
+ </target>
+
+ <target name="declare.win32.vc8_x64" if="isVC8_X64">
+ <echo message="Win32.VC8_X64" />
+ <property name="compiler.cfg.id" value="compiler.cfg.win32.msvc" />
+ <property name="linker.cfg.id" value="linker.cfg.win32.msvc" />
+ </target>
+
+ <target name="declare.win32.vc9" if="isVC9">
+ <echo message="Win32.VC9" />
+ <property name="compiler.cfg.id" value="compiler.cfg.win32.msvc" />
+ <property name="linker.cfg.id" value="linker.cfg.win32.msvc" />
+ </target>
+
+ <target name="declare.win32.mingw" if="isMingW">
+ <echo message="Win32.MingW" />
+ <property name="compiler.cfg.id" value="compiler.cfg.win32.mingw" />
+ <property name="linker.cfg.id" value="linker.cfg.win32.mingw" />
+ </target>
+
+ <target name="declare.win32" depends="declare.win32.vc6,declare.win32.vc7,declare.win32.vc8,declare.win32.vc8_x64,declare.win32.vc9,declare.win32.mingw" if="isWindows" >
+ <property name="c.src.dir" value="windows" />
+ <property name="java.includes.dir.platform" value="${java.includes.dir}/win32" />
+ </target>
+
+ <target name="declare.linux.x86" if="isLinuxX86">
+ <echo message="Linux.x86" />
+ <property name="compiler.cfg.id" value="compiler.cfg.linux" />
+ <property name="linker.cfg.id" value="linker.cfg.linux" />
+ </target>
+
+ <target name="declare.linux.amd64" if="isLinuxAMD64">
+ <echo message="Linux.AMD64" />
+ <property name="compiler.cfg.id" value="compiler.cfg.linux.amd64" />
+ <property name="linker.cfg.id" value="linker.cfg.linux.amd64" />
+ </target>
+
+ <target name="declare.linux.ia64" if="isLinuxIA64">
+ <echo message="Linux.IA64" />
+ <property name="compiler.cfg.id" value="compiler.cfg.linux" />
+ <property name="linker.cfg.id" value="linker.cfg.linux" />
+ </target>
+
+ <target name="declare.linux" depends="declare.linux.x86,declare.linux.amd64,declare.linux.ia64" if="isLinux" >
+ <property name="c.src.dir" value="unix" />
+ <property name="java.includes.dir.platform" value="${java.includes.dir}/linux" />
+ </target>
+
+ <target name="declare.solaris32" if="isSolaris32Bit">
+ <echo message="Solaris" />
+ <property name="compiler.cfg.id" value="compiler.cfg.solaris" />
+ <property name="linker.cfg.id" value="linker.cfg.solaris" />
+ </target>
+
+ <target name="declare.solarisSparcv9" if="isSolarisSparcv9">
+ <echo message="SolarisSparcv9" />
+ <property name="compiler.cfg.id" value="compiler.cfg.solaris.sparcv9" />
+ <property name="linker.cfg.id" value="linker.cfg.solaris.sparcv9" />
+ </target>
+
+ <target name="declare.solarisAMD64" if="isSolarisAMD64">
+ <echo message="SolarisAMD64" />
+ <property name="compiler.cfg.id" value="compiler.cfg.solaris.amd64" />
+ <property name="linker.cfg.id" value="linker.cfg.solaris.amd64" />
+ </target>
+
+ <target name="declare.solaris" depends="declare.solaris32,declare.solarisSparcv9,declare.solarisAMD64" if="isSolaris" >
+ <property name="c.src.dir" value="unix" />
+ <property name="java.includes.dir.platform" value="${java.includes.dir}/solaris" />
+ </target>
+
+ <target name="declare.macosx" if="isOSX">
+ <echo message="MacOSX" />
+ <property name="compiler.cfg.id" value="compiler.cfg.macosx" />
+ <property name="linker.cfg.id" value="linker.cfg.macosx" />
+ <property name="c.src.dir" value="macosx" />
+ <property name="java.includes.dir.platform" value="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Headers" />
+ </target>
+
+ <target name="declare.freebsd" if="isFreeBSD">
+ <echo message="FreeBSD" />
+ <property name="compiler.cfg.id" value="compiler.cfg.freebsd" />
+ <property name="linker.cfg.id" value="linker.cfg.linux" />
+ <property name="c.src.dir" value="unix" />
+ <property name="java.includes.dir.freebsd" value="${java.includes.dir}/freebsd" />
+ </target>
+
+ <target name="declare.hpux" if="isHPUX">
+ <echo message="HP-UX" />
+ <property name="compiler.cfg.id" value="compiler.cfg.hpux" />
+ <property name="linker.cfg.id" value="linker.cfg.hpux" />
+ <property name="c.src.dir" value="unix" />
+ <property name="java.includes.dir.hpux" value="${java.includes.dir}/hp-ux" />
+ </target>
+
+ <target name="c.configure" depends="gluegen.cpptasks.detect.os,gluegen.cpptasks.detect.compiler,setup.java.home.dir,declare.win32,declare.linux,declare.solaris,declare.macosx,declare.freebsd,declare.hpux,gluegen.cpptasks.configure.compiler" unless="build.javaonly" >
+ <!-- Common properties -->
+ <property name="java.includes.dir" value="${java.home.dir}/include" /> <!-- NOTE: this MUST be relative for FileSet -->
+
+ <property name="c.compiler.src.files" value="src/native/${c.src.dir}/*.c" />
+
+ <property name="output.lib.name" value="gluegen-rt" />
+ </target>
+
+ <target name="c.rename.lib.mingw" if="isMingW">
+ <!-- FIXME: this is a hack; the cpptask should have an option to change the
+ suffix or at least understand the override from .so to .dll -->
+ <move file="../${rootrel.build}/obj/libgluegen-rt.so" tofile="../${rootrel.build}/obj/gluegen-rt.dll" />
+ </target>
+
+ <target name="c.rename.lib.macosx" if="isOSX">
+ <!-- FIXME: this is a hack; the cpptask should have an option to change the
+ suffix or at least understand the override from dylib to jnilib -->
+ <move file="../${rootrel.build}/obj/libgluegen-rt.dylib" tofile="../${rootrel.build}/obj/libgluegen-rt.jnilib" />
+ </target>
+
+ <target name="c.manifest" if="isVC8Family">
+ <!-- exec mt, the Microsoft Manifest Tool, to include DLL manifests in order to resolve the location of msvcr80.dll -->
+ <msvc.manifest objdir="../${rootrel.build}/obj" dllname="gluegen-rt" />
+ </target>
+
+ <target name="c.build" depends="c.configure" unless="build.javaonly" >
+ <fail message="Requires '${c.compiler.src.files}'" unless="c.compiler.src.files"/>
+ <fail message="Requires '${compiler.cfg.id}'" unless="compiler.cfg.id"/>
+ <fail message="Requires '${linker.cfg.id}'" unless="linker.cfg.id"/>
+ <fail message="Requires '${output.lib.name}'" unless="output.lib.name"/>
+
+ <echo message="Output lib name = ${output.lib.name}" />
+
+ <!-- NOTE: the value of the debug and optimise attributes will not be overridden if already set externally -->
+ <property name="c.compiler.debug" value="false" />
+ <!-- Optimise flags one of { none, size, speed, minimal, full, aggressive, extreme, unsafe } -->
+ <property name="c.compiler.optimise" value="none" />
+
+ <condition property="c.compiler.use-debug"><istrue value="${c.compiler.debug}"/></condition>
+
+ <mkdir dir="../${rootrel.build}/obj" />
+
+ <echo message="Compiling ${c.compiler.src.files}" />
+ <echo message="user.dir=${user.dir}" />
+
+ <cc outtype="shared"
+ objdir="../${rootrel.build}/obj"
+ outfile="../${rootrel.build}/obj/${output.lib.name}"
+ optimize="${c.compiler.optimise}"
+ debug="${c.compiler.debug}"
+ multithreaded="true"
+ exceptions="false"
+ rtti="false">
+
+ <!-- TODO: versioninfo companyname="java.net"
+ legalcopyright="Copyright"
+ productname="GlueGen"
+ productversion="x.y.z"
+ description="Description"
+ fileversion="x.y.z"
+ filecomments="File Comment" /-->
+
+ <fileset dir="..">
+ <patternset>
+ <include name="${c.compiler.src.files}" />
+ </patternset>
+ </fileset>
+
+ <compiler extends="${compiler.cfg.id}" >
+ <sysincludepath path="${java.includes.dir}"/>
+ <sysincludepath path="${java.includes.dir.platform}"/>
+ </compiler>
+
+ <linker extends="${linker.cfg.id}" />
+ </cc>
+
+ <antcall target="c.rename.lib.mingw" inheritRefs="true" />
+ <antcall target="c.rename.lib.macosx" inheritRefs="true" />
+ <antcall target="c.manifest" inheritRefs="true" />
+ <!-- Create Java Web Start jar file from built file -->
+ <jar destfile="../${rootrel.build}/gluegen-rt-natives-${os.and.arch}.jar">
+ <fileset dir="../${rootrel.build}/obj">
+ <include name="*gluegen-rt.${native.library.suffix}" />
+ </fileset>
+ </jar>
+ </target>
+
+ <target name="build.nativelibrary" unless="build.javaonly" >
+ <antcall target="c.build" inheritRefs="true" />
+ </target>
+
+
+ <target name="gluegen.rebuild.gluegen-rt" if="isCDCFP">
+ <!-- Re-build just the gluegen-rt.jar classes using the Java ME
+ boot classes, if they're in use. -->
+ <delete dir="../${rootrel.build}/classes/com/sun/gluegen/runtime" />
+ <javac destdir="${classes}"
+ source="1.4"
+ debug="true"
+ debuglevel="source,lines"
+ excludes="${gluegen.excludes}"
+ bootclasspath="${javac.bootclasspath.jar}">
+ <src path="${src.java}" />
+ <src path="${src.generated.java}" />
+ <classpath refid="antlr.classpath" />
+ </javac>
+ </target>
+
+ <!-- ================================================================== -->
+ <!--
+ - Build GlueGen.
+ -->
+ <target name="gluegen.build" depends="init">
+ <!-- Because ANTLR looks for importVocab files in the current
+ working directory, it likes to have all of its files,
+ including supergrammars, in one place, so copy all of the
+ grammars to the output directory up front so we don't put
+ temporary files into the source tree -->
+ <mkdir dir="${generated.java.from.c.grammar}" />
+ <copy todir="${generated.java.from.c.grammar}">
+ <fileset dir="${c.grammar}">
+ <include name="*.g" />
+ </fileset>
+ </copy>
+ <mkdir dir="${generated.java.from.j.grammar}" />
+ <copy todir="${generated.java.from.j.grammar}">
+ <fileset dir="${j.grammar}">
+ <include name="*.g" />
+ </fileset>
+ </copy>
+
+ <!-- Generate the Java files from the C grammar using ANTLR. -->
+ <antcall target="generate.grammar">
+ <param name="output.dir" value="${generated.java.from.c.grammar}" />
+ <param name="target" value="StdCParser.g" />
+ </antcall>
+ <antcall target="generate.c.grammar.glib">
+ <param name="output.dir" value="${generated.java.from.c.grammar}" />
+ <param name="target" value="GnuCParser.g" />
+ <param name="glib" value="StdCParser.g" />
+ </antcall>
+ <antcall target="generate.grammar">
+ <param name="output.dir" value="${generated.java.from.c.grammar}" />
+ <param name="target" value="GnuCTreeParser.g" />
+ </antcall>
+ <antcall target="generate.c.grammar.glib">
+ <param name="output.dir" value="${generated.java.from.c.grammar}" />
+ <param name="target" value="GnuCEmitter.g" />
+ <param name="glib" value="GnuCTreeParser.g" />
+ </antcall>
+ <antcall target="generate.c.grammar.glib">
+ <param name="output.dir" value="${generated.java.from.c.grammar}" />
+ <param name="target" value="HeaderParser.g" />
+ <param name="glib" value="GnuCTreeParser.g" />
+ </antcall>
+ <antcall target="generate.grammar">
+ <param name="output.dir" value="${generated.java.from.j.grammar}" />
+ <param name="target" value="JavaParser.g" />
+ </antcall>
+
+ <!-- Build GlueGen using the generated Java files along with the
+ - original source. -->
+ <javac destdir="${classes}"
+ source="1.4"
+ debug="true"
+ debuglevel="source,lines"
+ excludes="${gluegen.excludes}">
+ <src path="${src.java}" />
+ <src path="${src.generated.java}" />
+ <classpath refid="antlr.classpath" />
+ </javac>
+
+ <!-- Re-build just the gluegen-rt.jar classes using the Java ME
+ boot classes, if they're in use. -->
+ <antcall target="gluegen.rebuild.gluegen-rt" inheritRefs="true" />
+
+ <!-- Build the (native code) NativeLibrary support for
+ gluegen-rt.jar using the just-built GlueGen. -->
+ <antcall target="build.nativelibrary" inheritRefs="true" />
+
+ <!-- Build gluegen.jar. -->
+ <jar destfile="${build}/gluegen.jar" manifest="Manifest">
+ <fileset dir="${classes}">
+ <include name="**/*.class" />
+ </fileset>
+ </jar>
+
+ <!-- Build gluegen-rt.jar. -->
+ <copy file="Manifest-rt"
+ tofile="${build}/Manifest-rt.temp"
+ overwrite="true">
+ <filterset>
+ <filter token="BASEVERSION" value="${gluegen_base_version}"/>
+ </filterset>
+ </copy>
+ <jar destfile="${build}/gluegen-rt.jar" manifest="${build}/Manifest-rt.temp">
+ <fileset dir="${classes}">
+ <include name="com/sun/gluegen/runtime/*.class" />
+ <include name="com/sun/gluegen/runtime/opengl/*.class" />
+ </fileset>
+ </jar>
+
+ <!-- Copy antlr.jar into build directory for convenience so
+ gluegen.jar can be run via "java -jar". antlr.jar is
+ referenced via a Class-Path entry in the Manifest of
+ gluegen.jar. -->
+ <copy file="${antlr.jar}" todir="${build}" />
+ </target>
+
+ <target name="all" depends="gluegen.build" />
+
+ <target name="clean">
+ <delete includeEmptyDirs="true" quiet="true">
+ <fileset dir="../${rootrel.build}" />
+ </delete>
+ </target>
+</project>