<?xml version="1.0" encoding="UTF-8"?>

<!-- JOCL's main build file-->
<project name="JOCL" default="default" basedir=".">

    <description>Builds, tests, and runs the project JOCL.</description>

    <property file="${user.home}/jocl.properties"/>
    
    <import file="nbproject/build-impl.xml"/>

    <property name="rootrel.build" value="build"/>
    <property name="gluegen.root" value="../gluegen" />
    <property name="jogl.root" value="../jogl" />

    <property name="etc.build.dir" value="${basedir}/etc/build" />
    <property name="headers.dest" value="${basedir}/resources/includes/CL" />
    
    <tstamp>
        <format property="version.timestamp" pattern="yyyyMMdd"/>
    </tstamp>

    <property name="jocl.build.number" value="manual" />
    <property name="jocl.build.id"     value="${version.timestamp}" />
    <property name="jocl.build.branch" value="master" />
    <property name="jocl.build.commit" value="manual" />

    <!-- Pull in GlueGen cpptasks build file -->
    <import file="${gluegen.root}/make/gluegen-cpptasks.xml" />
    <import file="${gluegen.root}/make/jogamp-env.xml" />
    <import file="${gluegen.root}/make/jogamp-archivetasks.xml" />
    
    <condition property="build.archiveon" value="true">
        <isset property="c.dont.compile"/>
    </condition>
    
    <!-- -post-init is after all properties are imported -->
    <target name="-post-init" depends="jogamp.env.init,gluegen.cpptasks.detect.os">
        <property name="jocl.version" value="${jocl_base_version}-b${jocl.build.number}-${version.timestamp}" />
        <property name="dist.zip.name" value="jocl-${jocl.version}-${os.and.arch}"/>
    </target>
    
    <target name="-pre-compile" depends="detect-jdk,prepare-jdk5-build,prepare-jdk7-build,generate-binding"/>
    
    <target name="detect-jdk">
        <condition property="enable.jdk7.features">
            <or>
                <equals arg1="1.7" arg2="${javac.source}"/>
                <equals arg1="1.8" arg2="${javac.source}"/>
            </or>
        </condition>
    </target>
    
    <target name="prepare-jdk5-build" if="${enable.jdk7.features}">
        
        <echo message="JDK7 features enabled"/>
        
        <copy file="${basedir}/src/com/jogamp/common/AutoCloseable.jtemplate"
            tofile="${basedir}/gensrc/java/com/jogamp/common/AutoCloseable.java" overwrite="true">
            <filterchain>
                <replaceregex pattern="/\*extends java.lang.AutoCloseable\*/" replace="extends java.lang.AutoCloseable"/>
            </filterchain>
        </copy>
        
    </target>
    
    <target name="prepare-jdk7-build" unless="${enable.jdk7.features}">
        
        <echo message="JDK7 features dissabled"/>
        
        <copy file="${basedir}/src/com/jogamp/common/AutoCloseable.jtemplate"
            tofile="${basedir}/gensrc/java/com/jogamp/common/AutoCloseable.java" overwrite="true">
        </copy>
        
    </target>
        
    <target name="generate-binding" depends="prepare-build,preprocess-headers" unless="dont-generate">
    
        <path id="gluegen.classpath">
            <pathelement location="${file.reference.gluegen.jar}" />
            <pathelement location="${antlr.jar}" />
        </path>

        <taskdef name="gluegen" classname="com.jogamp.gluegen.ant.GlueGenTask" classpathref="gluegen.classpath" />

        <!--OpenCL Impl including OpenGL interoperability-->
        <dirset id="jocl.include.path" dir="${basedir}">
            <include name="resources/includes"/>
            <include name="resources/stubs_includes/jvm"/>
            <include name="resources/stubs_includes/gl"/>
            <include name="resources/stubs_includes/common"/>
        </dirset>

        <echo message=" - - - generate JOCL binding files - - - "/>

        <echo message="generate CL interface..."/>
        <gluegen src="resources/opencl.h"
                 config="resources/cl-if.cfg"
                 includeRefid="jocl.include.path"
                 emitter="com.jogamp.gluegen.JavaEmitter"
                 dumpCPP="false"
                 debug="false">
            <classpath refid="gluegen.classpath" />
        </gluegen>

        <echo message="generate CLGLI interface..."/>
        <gluegen src="resources/opencl.h"
                 config="resources/clgl-if.cfg"
                 includeRefid="jocl.include.path"
                 emitter="com.jogamp.gluegen.JavaEmitter"
                 debug="false">
            <classpath refid="gluegen.classpath" />
        </gluegen>

        <echo message="generate GLImpl..."/>
        <gluegen src="resources/opencl.h"
                 config="resources/cl-impl.cfg"
                 includeRefid="jocl.include.path"
                 emitter="com.jogamp.gluegen.procaddress.ProcAddressEmitter"
                 debug="false">
            <classpath refid="gluegen.classpath" />
        </gluegen>
        <echo message=" - - - JOCL binding files generated - - - "/>

    </target>

    <target name="prepare-build" depends="gluegen.properties.load.user">

        <property name="headers.orig" value="${basedir}/resources/includes/CL_orig" />

        <!--compile build utilities-->
        <mkdir dir="${etc.build.dir}"/>

        <javac destdir="${etc.build.dir}" classpath="${ant.core.lib}" source="1.5" debug="true" debuglevel="lines,vars,source" includeantruntime="false">
            <src path="${basedir}/etc/src"/>
        </javac>

        <taskdef name="update-headers"            classname="com.jogamp.ant.HeaderFileDownloader"     classpath="${etc.build.dir}"/>
        <taskdef name="uncomment-function-params" classname="com.jogamp.ant.FunctionParamUncommenter" classpath="${etc.build.dir}"/>

    </target>

    <target name="-post-compile" depends="c.compile.default" />

    <target name="-pre-jar">
        
        <copy file="${basedir}/manifest_template.mf" tofile="${rootrel.build}/manifest.mf">
            <filterset>
                <filter token="SPEC_VERSION" value="${jocl_base_version}"/>
                <filter token="VERSION"      value="${jocl.version}"/>
                <filter token="SCM_BRANCH"   value="${jocl.build.branch}"/>
                <filter token="SCM_COMMIT"   value="${jocl.build.commit}"/>
            </filterset>
        </copy>
        
    </target>

    <target name="-post-jar" depends="jar.natives,tag.build,package-dist,archive-dist"/>
        
    <target name="package-dist">
        <!-- don't know how to get rid of the NetBeans readme file -->
        <delete file="${dist.dir}/README.TXT"/>

        <!-- for local testing -->
        <property name="jocl.jnlp.codebase"     value="http://jogamp.org/deployment/webstart-next"/>
        <property name="gluegen.jnlp.codebase"  value="http://jogamp.org/deployment/webstart-next"/>

        <copy file="jocl.jnlp" tofile="${dist.jar.dir}/jocl.jnlp">
            <filterchain>
                <replacestring from="JOCL_CODEBASE_TAG"     to="${jocl.jnlp.codebase}"/>
                <replacestring from="GLUEGEN_CODEBASE_TAG"  to="${gluegen.jnlp.codebase}"/>
            </filterchain>
        </copy>
        
        <!-- add native dependencies to lib folder -->
        <copy file="${gluegen.root}/${rootrel.build}/gluegen-rt-natives-${os.and.arch}.jar" todir="${dist.dir}/lib"/>
        <copy file="${jogl.root}/${rootrel.build}/jogl/jogl-natives-${os.and.arch}.jar" todir="${dist.dir}/lib"/>
        <copy file="${jogl.root}/${rootrel.build}/nativewindow/nativewindow-natives-${os.and.arch}.jar" todir="${dist.dir}/lib"/>
        <copy file="${jogl.root}/${rootrel.build}/newt/newt-natives-${os.and.arch}.jar" todir="${dist.dir}/lib"/>
        
    </target>
        
    <target name="archive-dist" if="build.archiveon">
    
        <!-- zip distribution -->
        <mkdir dir="${dist.dir}/tmp/${dist.zip.name}"/>
        
        <!-- jars and jared natives -->
        <copy todir="${dist.dir}/tmp/${dist.zip.name}/jar" flatten="true">
            <fileset dir="${dist.dir}" includes="jocl.jar,jocl-natives-*.jar,lib/*.jar"/>
        </copy>
        <copy todir="${dist.dir}/tmp/${dist.zip.name}/jnlp-files">
            <fileset dir="." includes="*.jnlp"/>
        </copy>
        <copy todir="${dist.dir}/tmp/${dist.zip.name}">
            <fileset dir="." includes="README,LICENSE"/>
            <fileset dir="${dist.dir}" includes="*.properties"/>
        </copy>
        
        <!-- native files, TODO: remove when no longer needed -->
        <copy todir="${dist.dir}/tmp/${dist.zip.name}/lib" failonerror="false">
            <fileset dir="${basedir}/${rootrel.build}/natives/jocl" excludes="*.xml"/>
            <fileset dir="${jogl.root}/${rootrel.build}/lib" excludes="*.xml"/>
        </copy>
        
        <!-- zip/7z it -->
        <zip        basedir="${dist.dir}/tmp" destfile="${dist.dir}/${dist.zip.name}.zip"/>
        <archive.7z basedir="${dist.dir}/tmp" destfile="${dist.dir}/${dist.zip.name}.7z"  includes="*"/>
        
        <delete dir="${dist.dir}/tmp"/>
    </target>
    
    <target name="tag.build">
        <property file="${dist.jar.dir}/artifact.properties"/>
        <copy file="${jogl.root}/${rootrel.build}/artifact.properties" todir="${dist.jar.dir}" overwrite="true" failonerror="false"/>
        <echo file="${dist.jar.dir}/artifact.properties" message="jocl.build.number=${jocl.build.number}${line.separator}" append="true" />
        <echo file="${dist.jar.dir}/artifact.properties" message="jocl.build.id=${jocl.build.id}${line.separator}" append="true" />
        <echo file="${dist.jar.dir}/artifact.properties" message="jocl.build.branch=${jocl.build.branch}${line.separator}" append="true" />
        <echo file="${dist.jar.dir}/artifact.properties" message="jocl.build.commit=${jocl.build.commit}${line.separator}" append="true" />
    </target>

    <target name="jar.natives" unless="c.dont.compile">

        <jar basedir="${natives.jocl.dir}/${namespace}" excludes="*.xml"
             destfile="${dist.jar.dir}/jocl-natives-${os.and.arch}.jar"
             manifest="${rootrel.build}/manifest.mf" />

    </target>


    <target name="c.compile.default" depends="gluegen.cpptasks.detect.os, gluegen.cpptasks.detect.compiler, jocl.c.compile, c.rename.lib.mingw" />

    <target name="jocl.c.compile" depends="c.setup.build" unless="c.dont.compile">

        <echo message=" - - - compiling JOCL natives - - - "/>
        <echo message="${compiler.cfg.id}"/>
        <echo message="${linker.cfg.id}"/>

        <mkdir dir="${obj.jocl.dir}/${namespace}" />
        <mkdir dir="${natives.jocl.dir}/${namespace}" />
        
        <cc outtype="shared"
            objdir="${obj.jocl.dir}/${namespace}"
            outfile="${natives.jocl.dir}/${namespace}/${output.lib.name}"
            optimize="${c.compiler.optimise}"
            debug="${c.compiler.debug}"
            multithreaded="true"
            exceptions="false"
            rtti="false">

            <fileset dir="gensrc/native" includes="*.c"/>

            <compiler extends="${compiler.cfg.id}" >

                <includepath path="${java.includes.dir}"/>
                <includepath path="${java.includes.dir.platform}"/>

                <!-- TODO should we use our own or jogl's GL headers?  -->
                <includepath path="${basedir}/resources/includes"/>
            <!--
                <includepath path="${jogl.root}/make/stub_includes/opengl/GL3"/>
                <includepath path="${jogl.root}/make/stub_includes/opengl"/>
            -->

            </compiler>

            <linker extends="${linker.cfg.id}"/>

        </cc>

        <echo message=" - - - JOCL natives compiled - - - "/>

        <antcall target="gluegen.cpptasks.striplibs" inheritRefs="true">
            <param name="libdir" value="${natives.jocl.dir}/${namespace}"/>
        </antcall>

    </target>

    <!-- official OpenCL headers expect a different layout on mac...
         since we want to use the same headers for all platforms we move them a bit around -->
    <target name="mac.includepath.hack" if="isOSX">
        <delete dir="${basedir}/resources/includes/OpenCL" quiet="true"/>
        <copydir src="${basedir}/resources/includes/CL" dest="${basedir}/resources/includes/OpenCL"/>
    </target>

    <target name="c.setup.build" depends="gluegen.cpptasks.configure.compiler, gluegen.cpptasks.declare.compiler, c.configure.default, jocl.configure.linker, mac.includepath.hack">

        <property name="obj.dir" value="${build.dir}/obj"/>
        <property name="natives.dir" value="${build.dir}/natives"/>

        <property name="output.lib.name" value="jocl"/>
        <property name="obj.jocl.dir" value="${obj.dir}/${output.lib.name}"/>
        <property name="natives.jocl.dir" value="${build.dir}/natives/${output.lib.name}"/>

        <property name="c.compiler.optimise" value="none"/>
        <property name="c.compiler.debug" value="false"/>
        <property name="namespace" value=""/>

    </target>

    <!-- linker configuration -->
    <target name="jocl.configure.linker">
        
        <linker id="linker.cfg.linux.jocl" extends="linker.cfg.linux">
            <syslibset dir="/usr/lib"            libs="OpenCL"  if="static.binding" unless="opencl.lib32.dir"/>
            <syslibset dir="${opencl.lib32.dir}" libs="OpenCL"  if="opencl.lib32.dir"/>
        </linker>

        <linker id="linker.cfg.linux.amd64.jocl" extends="linker.cfg.linux.amd64" >
            <syslibset dir="/usr/lib"            libs="OpenCL"  if="static.binding" unless="opencl.lib64.dir"/>
            <syslibset dir="${opencl.lib64.dir}" libs="OpenCL"  if="opencl.lib64.dir"/>
        </linker>

        <linker id="linker.cfg.win32.mingw.jocl" extends="linker.cfg.win32.mingw">
            <linkerarg value="-Wl,--kill-at" /> <!-- remove @ from function names -->
            <syslibset dir="${opencl.lib32.dir}" libs="OpenCL" if="static.binding"/>
        </linker>

        <linker id="linker.cfg.win64.mingw.jocl" extends="linker.cfg.win64.mingw">
            <linkerarg value="-Wl,--kill-at" /> <!-- remove @ from function names -->
            <syslibset dir="${opencl.lib64.dir}" libs="OpenCL" if="static.binding"/>
        </linker>

        <linker id="linker.cfg.macosx.jocl" extends="linker.cfg.macosx">
            <linkerarg value="-framework OpenCL" if="static.binding"/>
        </linker>

    </target>

    <!-- configure for current platform -->
    <target name="c.configure.default" depends="c.configure.os" />
    <target name="c.configure.os"      depends="c.configure.win, c.configure.linux, c.configure.macosx" />
    <target name="c.configure.win"     depends="c.configure.win.mingw32, c.configure.win.mingw64" if="isWindows" />
    <target name="c.configure.linux"   depends="c.configure.linux.x86, c.configure.linux.amd64" if="isLinux" />

    <target name="c.configure.win.mingw32" if="isMingW32">
        <echo message="Win.Ming32W" />
        <property name="compiler.cfg.id"  value="${compiler.cfg.id.base}" />
        <property name="linker.cfg.id"    value="linker.cfg.win32.mingw.jocl" />
    </target>
    <target name="c.configure.win.mingw64" if="isMingW64">
        <echo message="Win.Ming64W" />
        <property name="compiler.cfg.id"  value="${compiler.cfg.id.base}" />
        <property name="linker.cfg.id"    value="linker.cfg.win64.mingw.jocl" />
    </target>
    <target name="c.configure.linux.x86" if="isLinuxX86">
        <echo message="Linux.x86" />
        <property name="compiler.cfg.id"  value="${compiler.cfg.id.base}" />
        <property name="linker.cfg.id"    value="linker.cfg.linux.jocl" />
    </target>
    <target name="c.configure.linux.amd64" if="isLinuxAMD64">
        <echo message="Linux.AMD64" />
        <property name="compiler.cfg.id"  value="${compiler.cfg.id.base}" />
        <property name="linker.cfg.id"    value="linker.cfg.linux.amd64.jocl" />
    </target>
    <target name="c.configure.macosx"      if="isOSX">
        <echo message="MacOS" />
        <property name="compiler.cfg.id"  value="${compiler.cfg.id.base}" />
        <property name="linker.cfg.id"    value="linker.cfg.macosx.jocl" />
    </target>

    <target name="-post-clean">
        <delete dir="gensrc"/>
        <delete dir="${etc.build.dir}"/>
        <delete dir="${headers.dest}"/>
    </target>

    <target name="update-headers" depends="prepare-build">

        <property name="registry.url" value="http://www.khronos.org/registry/cl/api/1.1/"/>

        <!-- download new headers from OpenCL registry if necessary -->
        <update-headers header="${headers.orig}/cl.h" url="${registry.url}cl.h"/>
        <update-headers header="${headers.orig}/cl_gl.h" url="${registry.url}cl_gl.h"/>
        <update-headers header="${headers.orig}/cl_gl_ext.h" url="${registry.url}cl_gl_ext.h"/>
        <update-headers header="${headers.orig}/cl_ext.h" url="${registry.url}cl_ext.h"/>
        <update-headers header="${headers.orig}/cl_platform.h" url="${registry.url}cl_platform.h"/>

    </target>

    <target name="preprocess-headers" depends="prepare-build">

        <mkdir dir="${headers.dest}"/>

        <!--uncomment function names in c headers and copy modified files into include path-->
        <uncomment-function-params src="${headers.orig}/cl.h" dest="${headers.dest}/cl.h"/>
        <uncomment-function-params src="${headers.orig}/cl_gl.h" dest="${headers.dest}/cl_gl.h"/>

        <!--nothing to uncomment in this headers-->
        <copy file="${headers.orig}/cl_platform.h" toDir="${headers.dest}" overwrite="true"/>
        <copy file="${headers.orig}/cl_ext.h" toDir="${headers.dest}" overwrite="true"/>
        <copy file="${headers.orig}/cl_gl_ext.h" toDir="${headers.dest}" overwrite="true"/>
        <copy file="${headers.orig}/cl_vendor_ext.h" toDir="${headers.dest}" overwrite="true"/>

    </target>

    <!--cut and paste from gluegen -->
    <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="${natives.jocl.dir}/${namespace}/libjocl.so" tofile="${natives.jocl.dir}/${namespace}/jocl.dll" />
    </target>

    <target name="-javadoc-build" depends="init,build-javadoc,archive-javadoc"/>
    
    <target name="build-javadoc">
        
        <mkdir dir="${dist.javadoc.dir}"/>

        <!-- copy gluegen and jogl doc next to the jocl doc for relative linking -->
        <copy todir="${dist.dir}/javadoc" failonerror="false">
            <fileset dir="${gluegen.root}/build/javadoc"/>
            <fileset dir="${jogl.root}/build/javadoc"/>
        </copy>

        <javadoc author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}"
            docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true"
            noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}"
            private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}"
            use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}"
            windowtitle="${javadoc.windowtitle}">

            <arg line="${javadoc.additionalparam} -J-Dnativetaglet.mapping=${basedir}/resources/native-taglet.properties"/>
            <taglet name="net.highteq.nativetaglet.NativeTaglet" path="${gluegen.root}/${rootrel.build}/gluegen.jar"/>

            <!-- relative linking between docs -->
            <link href="../../gluegen/javadoc"/>
            <link href="../../jogl/javadoc"/>

            <link href="http://download.oracle.com/javase/6/docs/api"/>

            <classpath>
                <pathelement path="${javac.classpath}"/>
            </classpath>
            
            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
                <filename name="**/*.java"/>
            </fileset>
            <fileset dir="${src.java.dir}" excludes="${excludes}" includes="${includes}">
                <filename name="**/*.java"/>
            </fileset>
            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
                <include name="**/*.java"/>
            </fileset>

            <excludepackage name="com.jogamp.opencl.impl"/>
        </javadoc>

    </target>
    
    <target name="archive-javadoc" if="build.archiveon">
        <zip destfile="${dist.dir}/jocl-javadoc.zip">
            <zipfileset dir="${dist.javadoc.dir}" prefix="jocl/javadoc"/>
        </zip>
        <archive.7z basedir="${dist.dir}/javadoc" destfile="${dist.dir}/jocl-javadoc.7z" includes="jocl/*"/>
    </target>

    <target name="test-file">
        <property name="javac.includes" value="${test.file}"/>
        <property name="test.includes" value="${test.file}"/>
        <antcall target="test-single" inheritall="true"/>
    </target>
    
    <!-- overwrites default target - watch out when build-impl.xml changes -->
    <target name="-post-test-run" depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests">
        <zip destfile="${dist.dir}/${dist.zip.name}-test-results-${build.node.name}.zip">
            <zipfileset dir="${build.test.results.dir}" prefix="${dist.zip.name}/test-results"/>
        </zip>
        <archive.7z basedir="${build.test.results.dir}" destfile="${dist.dir}/${dist.zip.name}-test-results-${build.node.name}.7z" includes="*"/>
        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
    </target>
    
    <target name="clean-jar-test" depends="clean,jar,test"/>

</project>