view build.gradle @ 3195:0789f0934cbc

Fix RT-29250 - AIOOB exception from Java-based pisces dasher
author flar <James.Graham@oracle.com>
date Mon, 15 Apr 2013 03:13:42 -0700
parents b72d2d60fcb9
children 5461d6830812
line wrap: on
line source
/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

import java.util.concurrent.*

/**
 * The main build script for JavaFX.
 *
 * MUST FIX tasks to complete:
 *  - build check -- making sure the final artifact has the right bits
 *      - some things worth automatically sanity checking:
 *          - are there images in the javadocs?
 *          - are all of the expected dylibs etc there?
 *          - is jfxrt.jar there?
 *          - does jfxrt.jar contain stuff it shouldn't (doc-files, iml, etc)
 *          - does jfxrt.jar contain stuff it should (bss files, etc)
 *  - Perform sanity checking to make sure a JDK exists with javac, javah, etc
 *  - Support building with no known JDK location, as long as javac, javah, etc are on the path
 *  - Check all of the native flags. We're adding weight to some libs that don't need it, and so forth.
 *
 * Additional projects to work on as we go:
 *  - Add "developer debug". This is where the natives do not have debug symbols, but the Java code does
 *  - The genVSproperties.bat doesn't find the directory where RC.exe lives. So it is hard coded. Might be a problem.
 *  - special tasks for common needs, such as:
 *      - updating copyright headers
 *      - stripping trailing whitespace (?)
 *  - checkstyle
 *  - findbugs
 *  - re needs?
 *  - sqe testing
 *  - API change check
 *  - Pushing results to a repo?
 *  - partial builds for compileXXX shaders isn't working until after 2 compiles
 *  - ServiceWithSecurityManagerTest fails to complete when run from gradle.
 *  - Integrate Parfait reports for C code
 *  - FXML Project tests are not running
 */
defaultTasks = ["assemble"]

/******************************************************************************
 *                              Utility methods                               *
 *****************************************************************************/

/**
 * If the given named property is not defined, then this method will define
 * it with the given defaultValue. Any properties defined by this method can
 * be substituted on the command line by using -P, or by specifying a
 * gradle.properties file in the user home dir
 *
 * @param name The name of the property to define
 * @param defaultValue The default value to assign the property
 */
void defineProperty(String name, String defaultValue) {
    if (!project.hasProperty(name)) {
        project.ext.set(name, defaultValue);
    }
}

/**
 * If the given named property is not defined, then this method will attempt to
 * look up the property in the props map, and use the defaultValue if it cannot be found.
 *
 * @param name The name of the property to look up and/or define
 * @param props The properties to look for the named property in, if it has not already been defined
 * @param defaultValue The default value if the property has not been defined and the
 *                     props map does not contain the named property
 */
void defineProperty(String name, Properties props, String defaultValue) {
    if (!project.hasProperty(name)) {
        project.ext.set(name, props.getProperty(name, defaultValue));
    }
}

/**
 * Converts the simple name of a library to the full name. For example, on mac
 * the simple name "glass" becomes "libglass.dylib". On Linux or Solaris, it would
 * be "libglass.so", and on Windows "glass.dll".
 *
 * @param name The simple name of the library
 * @return The name of the shared library file
 */
String library(String name) {
    return "${IS_WINDOWS ? '' : 'lib'}$name.${IS_WINDOWS ? 'dll' : IS_MAC ? 'dylib' : 'so'}"
}

/******************************************************************************
 *                                                                            *
 *                   Definition of project properties                         *
 *                                                                            *
 *  All properties defined using ext. are immediately available throughout    *
 *  the script as variables that can be used. These variables are attached    *
 *  to the root project (whereas if they were defined as def variables then   *
 *  they would only be available within the root project scope).              *
 *                                                                            *
 *  All properties defined using the "defineProperty" method can be replaced  *
 *  on the command line by using the -P flag. For example, to override the    *
 *  location of the binary plug, you would specify -PBINARY_PLUG=some/where   *
 *                                                                            *
 *****************************************************************************/

// These variables indicate what the platform is that is doing the build. Is
// this build running on a Mac, Windows, or Linux machine? 32 or 64 bit?
ext.OS_NAME = System.getProperty("os.name").toLowerCase();
ext.OS_ARCH = System.getProperty("os.arch");
ext.IS_64 = OS_ARCH.toLowerCase().contains("64");
ext.IS_MAC = OS_NAME.contains("mac") || OS_NAME.contains("darwin");
ext.IS_WINDOWS = OS_NAME.contains("windows");
ext.IS_LINUX = OS_NAME.contains("linux");

// CompileTarget defines what we are trying to compile to. By default the CompileTarget
// will be the same as the platform running this build -- that is, Mac, Windows, or Linux.
// You may be performing a cross-compile (compiling for a platform other than the one
// you are using, such as iOS, ARM Hard Float (armhf) or ARM Soft Float (armvfp)
enum CompileTarget {
    MAC("mac", true),
    WIN("win", true),
    LINUX("linux", "gtk", true),
    IOS("ios", false),
    SWT("swt", true),
    ARM_HF("armhf", "lens", false),
    ARM_VFP("armvfp", "lens", false)

    final String name;
    final String glassName;
    final boolean isDesktop;

    CompileTarget(String name, boolean isDesktop) {
        this.name = name;
        this.glassName = name;
        this.isDesktop = isDesktop;
    }

    CompileTarget(String name, String glassName, boolean isDesktop) {
        this.name = name;
        this.glassName = glassName;
        this.isDesktop = isDesktop;
    }
}

// Check whether the COMPILE_TARGET property has been specified (if so, it was done by
// the user and not by this script). If it has been defined, then convert it from a
// String to a CompileTarget, and do some sanity checking.
if (hasProperty("COMPILE_TARGET")) {
    // Convert from whatever String was assigned to COMPILE_TARGET to an object
    for (CompileTarget target : CompileTarget.values()) {
        if (target.name.equals(COMPILE_TARGET.toLowerCase())) {
            COMPILE_TARGET = target;
            break;
        }
    }
} else {
    // Default to the right compile target for the platform
    ext.COMPILE_TARGET = IS_MAC ? CompileTarget.MAC : IS_WINDOWS ? CompileTarget.WIN : IS_LINUX ? CompileTarget.LINUX : null;
}

ext.GLASS_PLATFORM = COMPILE_TARGET.glassName;

// Get the JDK_HOME automatically based on the version of Java used to execute gradle. Or, if specified,
// use a user supplied JDK_HOME, BINARY_STUB, JAVAC, and/or JAVAH, all of which may be specified
// independently (or we'll try to get the right one based on other supplied info). There is a really
// odd situation on windows where you can have two JRE's on the same system(!!!):
//    c:\Program Files (x86)\Java\jdk1.8.0\jre
//    c:\Program Files (x86)\Java\jre8\
// Because of this, you may sometimes get the jdk's JRE (in which case the logic we used to have here
// was correct and consistent with all other platforms), or it might be the standalone JRE (for the love!).
// So what we have to do is add some special windows-only logic here to figure out the JDK based on the
// wrong JRE, if we happen to have gotten the wrong JRE.
ext.JAVA_HOME = System.getProperty("java.home");
def javaHomeFile = file(JAVA_HOME);
defineProperty("JDK_HOME",
        javaHomeFile.name == "jre" ?
        javaHomeFile.getParent().toString() :
        javaHomeFile.name.startsWith("jre") ?
        new File(javaHomeFile.getParent(), "jdk1.${javaHomeFile.name.substring(3)}.0").toString() :
        JAVA_HOME); // we have to bail and set it to something and this is as good as any!
defineProperty("JAVA", "$JDK_HOME/bin/java${IS_WINDOWS ? '.exe' : ''}");
defineProperty("JAVAC", "$JDK_HOME/bin/javac${IS_WINDOWS ? '.exe' : ''}");
defineProperty("JAVAH", "$JDK_HOME/bin/javah${IS_WINDOWS ? '.exe' : ''}");
defineProperty("JAVADOC", "$JDK_HOME/bin/javadoc${IS_WINDOWS ? '.exe' : ''}");
defineProperty("JDK_DOCS", "http://download.oracle.com/javase/7/docs/api");
defineProperty("BINARY_STUB", "file://$JDK_HOME/jre/lib/ext/jfxrt.jar");

// COMPILE_WEBKIT specifies whether to build all of webkit. COMPILE_GSTREAMER
// specifies whether to build GStreamer.
defineProperty("COMPILE_WEBKIT", "false")
defineProperty("COMPILE_GSTREAMER", "false")
COMPILE_WEBKIT = Boolean.parseBoolean(COMPILE_WEBKIT)
COMPILE_GSTREAMER = Boolean.parseBoolean(COMPILE_GSTREAMER)

// Define the SWT.jar that we are going to have to download during the build process based
// on what platform we are compiling from (not based on our target). SWT in particular is
// only used when we are compiling for desktop platforms.
ext.SWT_FILE_NAME = IS_MAC ? "org.eclipse.swt.cocoa.macosx.x86_64_3.7.2.v3740f.jar" :
    IS_WINDOWS && IS_64 ? "org.eclipse.swt.win32.win32.x86_64_3.7.2.v3740f.jar" :
    IS_WINDOWS && !IS_64 ? "org.eclipse.swt.win32.win32.x86_3.7.2.v3740f.jar" :
    IS_LINUX && IS_64 ? "org.eclipse.swt.gtk.linux.x86_64_3.7.2.v3740f.jar" :
    IS_LINUX && !IS_64 ? "org.eclipse.swt.gtk.linux.x86_3.7.2.v3740f.jar" : "";

// Specify the build configuration (Release or Debug) and whether we're checking warnings during compilation (LINT)
defineProperty("CONF", "Release");
ext.IS_DEBUG = CONF == "Debug";

// Defines the compiler warning levels to use. If empty, then no warnings are generated. If
// not empty, then the expected syntax is as a space or comma separated list of names, such
// as defined in the javac documentation.
defineProperty("LINT", "none");
ext.IS_LINT = LINT != "none";

defineProperty("DOC_LINT", "none");
ext.IS_DOC_LINT = DOC_LINT != "none";

// Specifies whether to use the "useDepend" option when compiling Java sources
defineProperty("USE_DEPEND", "false");
ext.USE_DEPEND = Boolean.parseBoolean(USE_DEPEND);

// Define the number of threads to use when compiling (specifically for native compilation)
defineProperty("NUM_COMPILE_THREADS", "${Runtime.runtime.availableProcessors()}");

// Now we need to define the native compilation tasks. The set of parameters to
// CC / LINK depends on the target platform (and also to some extent what platform
// you are compiling on). These settings are contained in various gradle files
// such as mac.gradle and linux.gradle and armhf.gradle. Additionally, the developer
// can specify COMPILE_FLAGS_FILE to be a URL or path to a different gradle file
// that will contain the appropriate flags.
defineProperty("COMPILE_FLAGS_FILE", "${COMPILE_TARGET.name}.gradle");
apply from: COMPILE_FLAGS_FILE;

// Define the programs to use for compiling and linking native code.
defineProperty("CC", "g++");
defineProperty("LINK", "g++");

// Define settings used when creating the VersionInfo. These settings are generally left alone
// by developers and set only from Hudson. We have to manually rev this version number from
// release to release.
defineProperty("HUDSON_JOB_NAME", "not_hudson");
defineProperty("HUDSON_BUILD_NUMBER","0000");
defineProperty("PROMOTED_BUILD_NUMBER", "00");
defineProperty("PRODUCT_NAME", "OpenJFX");
defineProperty("RAW_VERSION", "8.0.0");
defineProperty("RELEASE_NAME", "8.0");
defineProperty("RELEASE_MILESTONE", "ea");

/******************************************************************************
 *                                                                            *
 *                          Build Setup Sanity Checks                         *
 *                                                                            *
 *  Here we do a variety of checks so that if the version of Java you are     *
 *  building with is misconfigured, or you are using the wrong version of     *
 *  gradle, etc you will get some kind of helpful error / warning message     *
 *                                                                            *
 *****************************************************************************/

// Verify that the architecture & OS are supported configurations
if (!IS_MAC && !IS_WINDOWS && !IS_LINUX) logger.error("Unsupported build OS ${OS_NAME}")
if ((IS_WINDOWS && OS_ARCH != "i386" && OS_ARCH != "amd64" && OS_ARCH != "x86") || (IS_MAC && OS_ARCH != "x86_64")) {
    // TODO what are appropriate linux arch values?
    throw new Exception("Unknown and unsupported build architecture: $OS_ARCH")
}

// Sanity checking
if (COMPILE_TARGET == CompileTarget.MAC && !IS_MAC) throw new Exception("Must be on MacOSX to compile for MacOSX");
if (COMPILE_TARGET == CompileTarget.LINUX && !IS_LINUX) throw new Exception("Must be on Linux to compile for Linux");
if (COMPILE_TARGET == CompileTarget.WIN && !IS_WINDOWS) throw new Exception("Must be on Windows to compile for Windows");
if (COMPILE_TARGET == CompileTarget.IOS && !IS_MAC) throw new Exception("Must be on MacOSX to cross compile for iOS");
if (COMPILE_TARGET == CompileTarget.ARM_HF && !IS_LINUX) throw new Exception("Must be on Linux x86 to cross compile for ARM Hard Float");
if (COMPILE_TARGET == CompileTarget.ARM_VFP && !IS_LINUX) throw new Exception("Must be on Linux x86 to cross compile for ARM Soft Float");

// Sanity check that we're not building from a platform we didn't anticipate
if (COMPILE_TARGET == null) throw new Exception("Unable to determine compilation platform, or COMPILE_TARGET!");

// Make sure JAVA_HOME/bin/java exists
defineProperty("JAVA", "$JDK_HOME/bin/java");
if (!file("$JAVA").exists()) throw new Exception("Missing or incorrect path to 'java': '$JAVA'. Perhaps bad JDK_HOME? $JDK_HOME")
if (!file("$JAVAC").exists()) throw new Exception("Missing or incorrect path to 'javac': '$JAVAC'. Perhaps bad JDK_HOME? $JDK_HOME")
if (!file("$JAVAH").exists()) throw new Exception("Missing or incorrect path to 'javah': '$JAVAH'. Perhaps bad JDK_HOME? $JDK_HOME")
if (!file("$JAVADOC").exists()) throw new Exception("Missing or incorrect path to 'javadoc': '$JAVADOC'. Perhaps bad JDK_HOME? $JDK_HOME")
if (!file("$BINARY_STUB").exists()) logger.warn("Missing or incorrect path to 'jfxrt.jar': '$BINARY_STUB'. Perhaps bad JDK_HOME? $JDK_HOME")

// Verify that CONF is something useful
if (CONF != "Release" && CONF != "Debug") logger.warn("Unknown configuration CONF='$CONF'. Treating as 'Release'");

// If the number of compile threads is less than 1 then we have a problem!
if (Integer.parseInt(NUM_COMPILE_THREADS.toString()) < 1) {
    logger.warn("NUM_COMPILE_THREADS was specified as '$NUM_COMPILE_THREADS' which is less than the minimum value of 1. " +
            "Building with a value of 1 instead.")
    NUM_COMPILE_THREADS = 1;
}

// Check that Gradle 1.4 is in use. We haven't tried any other versions.
if (gradle.gradleVersion != "1.4") {
    logger.warn("Unsupported gradle version $gradle.gradleVersion in use. Only 1.4 is supported")
}

/******************************************************************************
 *                                                                            *
 *                      Logging of Properties and Settings                    *
 *                                                                            *
 *  Log some of the settings we've determined. We could log more here, it     *
 *  doesn't really hurt.                                                      *
 *                                                                            *
 *****************************************************************************/

logger.info("OS_NAME: $OS_NAME");
logger.info("OS_ARCH: $OS_ARCH");
logger.info("JAVA_HOME: $JAVA_HOME");
logger.info("JDK_HOME: $JDK_HOME");
logger.info("BINARY_STUB: ${file(BINARY_STUB)}");
logger.info("HUDSON_JOB_NAME: $HUDSON_JOB_NAME");
logger.info("HUDSON_BUILD_NUMBER: $HUDSON_BUILD_NUMBER");
logger.info("PROMOTED_BUILD_NUMBER: $PROMOTED_BUILD_NUMBER");
logger.info("PRODUCT_NAME: $PRODUCT_NAME");
logger.info("RAW_VERSION: $RAW_VERSION");
logger.info("RELEASE_NAME: $RELEASE_NAME");
logger.info("RELEASE_MILESTONE: $RELEASE_MILESTONE");

/******************************************************************************
 *                                                                            *
 *                Definition of Native Code Compilation Tasks                 *
 *                                                                            *
 *  Three custom tasks are defined here to aid in compiling native code. This *
 *  approach removes the need to use make files for any of the projects under *
 *  our control (webkit and gstreamer both still require 'make' to build).    *
 *                                                                            *
 *    - JavaHeaderTask is used to run javah. The JAVAH property will point at *
 *      the version of javah to be used (i.e.: a path to javah)               *
 *    - CCTask compiles native code. Specifically it will compile .m, .c,     *
 *      .cpp, or .cc files. It uses the headers provided by the               *
 *      JavaHeaderTask plus additional platform specific headers. It will     *
 *      compile into .obj files. The CC property defines the compiler to use  *
 *      On Windows it will also process resource files.                       *
 *    - LinkTask will perform native linking and create the .dll / .so /      *
 *      .dylib as necessary. It uses the linker defined by the LINK property  *
 *                                                                            *
 *****************************************************************************/

class JavaHeaderTask extends DefaultTask {
    @OutputDirectory File output;
    @InputDirectory File source;
    FileCollection classpath;
    private final PatternFilterable patternSet = new PatternSet();

    public JavaHeaderTask include(Iterable includes) {
        patternSet.include(includes);
        return this;
    }

    public JavaHeaderTask include(String... includes) {
        patternSet.include(includes);
        return this;
    }

    public JavaHeaderTask exclude(Iterable excludes) {
        patternSet.exclude(excludes);
        return this;
    }

    @TaskAction void runJavaH() {
        // For each .java file we need to figure out what class
        // the .java file belongs in and convert to a class name.
        List classNames = [];
        FileTree files = project.files(source).getAsFileTree().matching(patternSet);
        files.visit({ fileTreeElement ->
            if (!fileTreeElement.isDirectory() && fileTreeElement.getName().endsWith(".class")) {
                String path = fileTreeElement.getPath();
                String className = path.substring(0, path.length() - 6).replace("/", ".");
                boolean skip = false;
                int dollar = className.lastIndexOf('$');
                if (dollar > 0) {
                    String lastPart = className.substring(dollar + 1);
                    skip = lastPart.matches("[0123456789]*");
                }
                if (!skip) classNames.add(className)
            }
        })
        // Execute javah
        project.exec({
            commandLine("$project.JAVAH", "-J-Djava.ext.dirs=", "-d", "$output", "-classpath", "${classpath.asPath}");
            args(classNames);
        });
    }
}

class NativeCompileTask extends DefaultTask {
    @Optional String matches; // regex for matching input files
    List<String> params = new ArrayList<String>();
    List sourceRoots = new ArrayList();
    @OutputDirectory File output;
    private final PatternFilterable patternSet = new PatternSet();

    @InputFiles public void setSource(Object source) {
        sourceRoots.clear();
        sourceRoots.add(source);
    }

    public NativeCompileTask source(Object... sources) {
        for (Object source : sources) {
            sourceRoots.add(source);
        }
        return this;
    }

    public NativeCompileTask include(String... includes) {
        patternSet.include(includes);
        return this;
    }

    public NativeCompileTask include(Iterable<String> includes) {
        patternSet.include(includes);
        return this;
    }

    @TaskAction void compile() {
        // Get the existing native-dependencies file from build/dependency-cache and load its contents into
        // memory. If the file doesn't exist, then we will just have an empty dependency map.
        final Map<String, Map> dependencies = new ConcurrentHashMap<>();
        final File nativeDependenciesFile = project.file("$project.buildDir/dependency-cache/native-dependencies");
        if (nativeDependenciesFile.exists()) {
            nativeDependenciesFile.splitEachLine("\t", { strings ->
                dependencies.put(strings[0], ["DATE":Long.parseLong(strings[1]), "SIZE":Long.parseLong(strings[2])]);
            });
        }

        project.mkdir(output);
        // Combine the different source roots into a single FileCollection based on all files in each source root
        def allFiles = [];
        sourceRoots.each {
            println project.file(it).toString()
            allFiles += project.file(it).listFiles()
        }
        def source = project.files(allFiles);
        final Set<File> files = matches == null ? new HashSet<File>(source.files) : source.filter{it.name.matches(matches)}.files;
        boolean shouldCompileAnyway = false;
        final boolean forceCompile = shouldCompileAnyway;
        final ExecutorService executor = Executors.newFixedThreadPool(Integer.parseInt(project.NUM_COMPILE_THREADS.toString()));
        final CountDownLatch latch = new CountDownLatch(files.size());
        List futures = new ArrayList<Future>();
        files.each { File sourceFile ->
            futures.add(executor.submit(new Runnable() {
                @Override public void run() {
                    try {
                        final File outputFile = outputFile(sourceFile);
                        // If the source file is not listed in dependencies, then we must compile it.
                        // If the target file(s) (.rc or .cur in the case of resources, .pdb or .obj for sources)
                        //    do not exist, then compile.
                        // If the source file date or size differs from dependencies, then compile it.
                        final Map sourceFileData = dependencies.get(sourceFile.toString());
                        if (forceCompile || sourceFileData == null || !outputFile.exists() ||
                                !sourceFileData["DATE"].equals(sourceFile.lastModified()) ||
                                !sourceFileData["SIZE"].equals(sourceFile.length()))
                        {
                            doCompile(sourceFile, outputFile)
                        }
                        dependencies.put(sourceFile.toString(), ["DATE":sourceFile.lastModified(), "SIZE":sourceFile.length()]);
                    } finally {
                        latch.countDown();
                    }
                }
            }));
        }
        latch.await();
        // Looking for whether an exception occurred while executing any of the futures.
        // By calling "get()" on each future an exception will be thrown if one had occurred
        // on the background thread.
        futures.each {it.get();}

        // Update the native-dependencies file
        if (nativeDependenciesFile.exists()) nativeDependenciesFile.delete();
        nativeDependenciesFile.getParentFile().mkdirs();
        nativeDependenciesFile.createNewFile();
        dependencies.each { key, value ->
            nativeDependenciesFile << key << "\t" << value["DATE"] << "\t" << value["SIZE"] << "\n";
        }
    }

    protected void doCompile(File sourceFile, File outputFile){ }
    protected File outputFile(File sourceFile) { return null; }
}

class CompileResourceTask extends NativeCompileTask {
    protected File outputFile(File sourceFile) {
        final String outFileName = sourceFile.getName().substring(0, sourceFile.getName().lastIndexOf("."));
        return new File("$output/${outFileName}.res");
    }

    protected void doCompile(File sourceFile, File outputFile){
        project.exec({
            commandLine("$project.RC", "/nologo", "/fo$outputFile", "$sourceFile");
            environment(project.WINDOWS_NATIVE_COMPILE_ENVIRONMENT);
        });
    }
}

class CompileHLSLTask extends NativeCompileTask {
    protected File outputFile(File sourceFile) {
        new File("$output/${sourceFile.name.replace('.hlsl', '.obj')}");
    }

    protected void doCompile(File sourceFile, File outputFile){
        project.exec({
            commandLine = ["$project.FXC", "/nologo", "/T", "ps_3_0", "/Fo", "$outputFile", "$sourceFile"]
            environment(project.WINDOWS_NATIVE_COMPILE_ENVIRONMENT);
        });
    }
}

class CCTask extends NativeCompileTask {
    @Optional String compiler;
    @Optional List<String> linkerOptions = new ArrayList<String>();
    @Optional @InputDirectory File headers;
    @Optional Closure eachOutputFile; // will be given a File and must return a File
    @Optional boolean exe = false;

    protected File outputFile(File sourceFile) {
        final String outFileName = sourceFile.getName().substring(0, sourceFile.getName().lastIndexOf("."));
        new File("$output/${outFileName}.obj");
    }

    protected void doCompile(File sourceFile, File outputFile) {
        if (eachOutputFile != null) {
            outputFile = eachOutputFile(outputFile);
        }

        // or compile sources using CC
        final int lastDot = outputFile.name.lastIndexOf(".");
        final File pdbFile = new File("$output/${lastDot > 0 ? outputFile.name.substring(0, lastDot) + '.pdb' : outputFile.name + '.pdb'}");

        // TODO the PDB file is never being built -- maybe because it is only built during
        // debug builds, otherwise that flag is ignored "/Fd" or "-Fd"
        project.exec({
            commandLine("${compiler == null ? project.CC : compiler}");
            if (headers != null) args("-I$headers");

            // Add the source roots in as include directories
            sourceRoots.each { root ->
                final File file = root instanceof File ? (File) root : project.file(root)
                args("-I$file");
            }

            // Add in any additional compilation params
            if (params != null) {
                // A little hack. Only use the -std=c99 flag if compiling .c or .m
                if (sourceFile.name.endsWith(".cpp") || sourceFile.name.endsWith(".cc")) {
                    def stripped = params;
                    stripped.remove("-std=c99");
                    args(stripped)
                } else {
                    args(params)
                }
            };

            // Add the name of the source file to compile
            if (project.IS_WINDOWS) {
                if (exe) {
                    final File exeFile = new File("$output/${lastDot > 0 ? outputFile.name.substring(0, lastDot) + '.exe' : outputFile.name + '.exe'}");
                    args(/*"/Fd$pdbFile",*/ "/Fo$outputFile", "/Fe$exeFile", "$sourceFile")
                } else {
                    args(/*"/Fd$pdbFile",*/ "/Fo$outputFile", "$sourceFile");
                }
            } else {
                args("-Fd$pdbFile", "-o", "$outputFile", "$sourceFile");
            }

            // Add any optional linker options -- used now rarely but can be
            // used for any cc task which isn't going to be followed by a
            // link task
            if (linkerOptions != null && !linkerOptions.isEmpty()) {
                args(linkerOptions);
            }

            if (project.IS_WINDOWS){
                environment(project.WINDOWS_NATIVE_COMPILE_ENVIRONMENT);
            }
        });
    }
}

class LinkTask extends DefaultTask {
    List<String> linkParams = new ArrayList<String>();
    @InputDirectory File objectDir;
    @OutputFile File lib;
    @TaskAction void compile() {
        // Link & generate the library (.dll, .so, .dylib)
        lib.getParentFile().mkdirs();
        project.exec({
            commandLine("$project.LINK");
            args(objectDir.listFiles());
            if (project.IS_WINDOWS) {
                args("/out:$lib");
            } else {
                args("-o", "$lib");
            }
            if (project.IS_DEBUG && !project.IS_WINDOWS) args("-g");
            if (linkParams != null) args(linkParams);
            if (project.IS_WINDOWS){
                final String libPath = lib.toString();
                final String libPrefix = libPath.substring(0, libPath.lastIndexOf("."))
                args("/pdb:${libPrefix}.pdb",
                    "/map:${libPrefix}.map");
                environment(project.WINDOWS_NATIVE_COMPILE_ENVIRONMENT);
            }
        });
    }
}

/**
* Convenience lambda for creating javah, cc, link, and "native" tasks in the given project. These
* tasks are parameterized by name, so that we can produce, for example, javahGlass, ccGlass, etc
* named tasks.
*/
void addNative(Project project, String name) {
    def javahTask = project.task("javah$name", type: JavaHeaderTask, dependsOn: project.classes, group: "Build") {
        description = "Generates JNI Headers for $name"
        source = project.sourceSets.main.output.classesDir
        classpath = project.files(project.sourceSets.main.output.classesDir, project.files(project.BINARY_STUB))
        output = project.file("$project.buildDir/headers/$name")
    }
    def ccTask = project.task("cc$name", type: CCTask, dependsOn: javahTask, group: "Build") {
        description = "Compiles native sources for $name"
        matches = ".*\\.c|.*\\.cpp|.*\\.m|.*\\.cc"
        headers = project.file("$project.buildDir/headers/$name")
        output(file("$project.buildDir/native/$name"))
    }
    def linkTask = project.task("link$name", type: LinkTask, dependsOn: ccTask, group: "Build") {
        description = "Creates native dynamic library for $name"
        objectDir = file("$project.buildDir/native/$name")
    }
    if (IS_WINDOWS) {
        def rcTask = project.task("rc$name", type: CompileResourceTask, dependsOn: javahTask, group: "Build") {
            description = "Compiles native sources for $name"
            matches = ".*\\.rc|.*\\.cur"
            output(file("$project.buildDir/native/$name"))
        }
        linkTask.dependsOn rcTask;
    }
    project.task("native$name", dependsOn: linkTask, group: "Build") {
        description = "Generates JNI headers, compiles, and builds native dynamic library for $name"
    }
    project.assemble.dependsOn("native$name")
    project.task("cleanNative$name", group: "Build") << {
        project.delete("$project.buildDir/headers")
        project.delete("$project.buildDir/native")
        project.delete("$project.buildDir/libs/${COMPILE_TARGET.name}")
    }
}

/*****************************************************************************
*        Project definitions (dependencies, etc)                             *
*****************************************************************************/

allprojects {
    // We want to configure all projects as java projects and use the same compile settings
    // etc, except for the root project which we just want to ignore
    if (project == rootProject || project.name == "media" || project.name == "web") return
    // All of our projects are java projects
    apply plugin: "java"
    // TODO we will want to switch this to 1.8 soooooon
    sourceCompatibility = 1.7
    // The following block is a workaround for the fact that presently Gradle
    // can't set the -XDignore.symbol.file flag, because it appears that the
    // javac API is lacking support for it. So what we'll do is find any Compile
    // task and manually provide the options necessary to fire up the
    // compiler with the right settings.
    //
    // Also, we need to remove jfxrt.jar from the ext classpath (if it is there)
    // and instead each module that depends on closed bits is going to need to
    // add BINARY_STUB to its list of dependencies.
    tasks.withType(Compile) { compile ->
        // Defer actually creating builder-src until task execution
        doFirst {
            mkdir("$buildDir/builder-src");
        }
        // It looks like we have to use ant to compile instead of the built-in gradle
        // compiler stuff because otherwise it won't compile on CYGWIN
        // TODO need to file issue with Gradle
        compile.options.useAnt = true
        compile.options.debug = true // we always generate debugging info in the class files
        compile.options.debugOptions.debugLevel = IS_DEBUG ? "source,lines,vars" : "source,lines"
        compile.options.fork = true
        compile.options.forkOptions.executable = JAVAC
        compile.options.warnings = IS_LINT
        compile.options.useDepend = USE_DEPEND
        compile.options.compilerArgs = ["-Djava.ext.dirs=", "-XDignore.symbol.file", "-encoding", "UTF-8"]

        // Add in the -Xlint options
        if (IS_LINT) {
            LINT.split("[, ]").each { s ->
                compile.options.compilerArgs += "-Xlint:$s"
            }
        }

        // Somewhat dangerous in case there is a java source set other than "test" or "stub" or "main"!
        // Note that the compileFooJava task is automatically created whenever a source set is
        // defined. So the "test" source set automatically creates a "compileTestJava" task (among others).
        if (name == "compileTestJava") {
            classpath = sourceSets.test.compileClasspath + rootProject.files(rootProject.BINARY_STUB)
        } else if (name == "compileStubJava") {
            classpath = sourceSets.stub.compileClasspath + rootProject.files(rootProject.BINARY_STUB)
        } else {
            compile.options.compilerArgs += ["-s", "$buildDir/builder-src"]
            // Not everything needs the builder processor
            if (["graphics", "controls", "swing", "swt", "base", "fxml"].contains(project.name)){
                compile.options.compilerArgs += ["-processor", "javafx.builder.processor.BuilderProcessor"]
            }
            classpath = sourceSets.main.compileClasspath + rootProject.files(rootProject.BINARY_STUB)
        }
    }

    // Setup the repositories that we'll download libraries from. Maven Central is
    // just easy for most things. The custom "ivy" repo is for downloading SWT. The way it
    // works is to setup the download URL such that it will resolve to the actual jar file
    // to download. See SWT_FILE_NAME for the name of the jar that will be used as the
    // "artifact" in the pattern below.
    repositories {
        mavenCentral()
        ivy {
            url "http://download.eclipse.org/eclipse/updates/3.7/R-3.7.2-201202080800/plugins/"
            layout "pattern", {
                artifact "[artifact]"
            }
        }
    }

    // By default all of our projects require junit for testing so we can just
    // setup this dependency here.
    dependencies {
        testCompile("junit:junit:4.8.2");
    }

    // At the moment the ASM library shipped with Gradle that is used to
    // discover the different test classes fails on Java 8, so in order
    // to have sourceCompatibility set to 1.8 I have to also turn scanForClasses off
    // and manually specify the includes / excludes. At the moment we use
    // Java 7 but when we switch to 8 this will be needed, and probably again when
    // we start building with Java 9.
    test {
        jvmArgs("-Djava.ext.dirs=");
        classpath = classpath + rootProject.files(rootProject.BINARY_STUB);
        executable = JAVA;
        enableAssertions = true;
        testLogging.exceptionFormat = "full";
        scanForTestClasses = false;
        include("**/*Test.*");
        exclude("**/DepthTest.*");
        exclude("**/*Abstract*.*");
    }

    // Exclude any non-public-API classes from having javadoc generated. This block is used
    // when generating JavaDocs for a specific project. When generating the JavaDocs for the
    // entire SDK, a different javadoc command is used (see the javadoc task on the top level)
    javadoc {
        exclude("com/**/*", "javafx/scene/ParentDesignInfo*", "Compile*", "javafx/builder/**/*");
        executable = JAVADOC;
        options.windowTitle("JavaFX Project ${project.name} ${RELEASE_NAME}")
        options.links(JDK_DOCS);
        options.addBooleanOption("XDignore.symbol.file").setValue(true);
        options.addBooleanOption("Xdoclint:none").setValue(!IS_DOC_LINT);
        options.addBooleanOption("javafx").setValue(true);
        // All doc-files are located in src/main/docs because Gradle's javadoc doesn't copy
        // over the doc-files if they are embedded with the sources. I find this arrangement
        // somewhat cleaner anyway (never was a fan of mixing javadoc files with the sources)
        doLast {
            copy {
                from "src/main/docs"
                into "$buildDir/docs/javadoc"
            }
        }
    }
}

// The build-tools project contains the annotation processor that is used to generate the
// builders, the decora compiler used for effects, and various annotations we use for FXML
// etc. Nothing in build-tools should *ever* be shipped with the runtime.
project(":build-tools") {
    // Include the to-be-generated antlr source files int he source set. We will generate
    // the antlr sources first before compilation.
    sourceSets {
        main.java.srcDirs = ["src/main/java", "$buildDir/generated-src/antlr"]
    }

    // Workaround for lack of Antlr 3 support in Gradle. By defining a configuration,
    // we can then give it a class path and use that classpath to execute a java command
    getConfigurations().add("antlr3");

    dependencies {
        compile("org.antlr:antlr-runtime:3.4");
        antlr3("org.antlr:antlr-runtime:3.4",
               "org.antlr:stringtemplate:4.0.2@jar",
               "org.antlr:antlr:3.4@jar");
    }

    // This is the task that will call antlr to generate the sources
    task generateGrammarSource(type: JavaExec) {
        description = "Generate JSL parser from Antlr3 grammars"
        String dest = "$buildDir/generated-src/antlr/com/sun/scenario/effect/compiler"
        String src = "src/main/antlr"
        inputs.dir file(src)
        outputs.dir file(dest)
        def grammars = fileTree(src).include("**/*.g")
        main = "org.antlr.Tool"
        classpath = configurations.antlr3
        args = ["-o", dest, grammars.files].flatten()
    }

    // Configure the compileJava task so that it relies on the task for generating
    // the grammar source (gotta have it prior to compilation)
    compileJava {
        dependsOn(generateGrammarSource);
    }
}

// The "base" project is our first module and the most basic one required for
// all other modules. It is useful even for non-GUI applications.
project(":base") {
    dependencies {
        compile project(":build-tools")
    }

    // We need to take the VersionInfo.java file and replace the various
    // properties within it
    def replacements = ["BUILD_TIMESTAMP": new java.util.Date(),
        "HUDSON_JOB_NAME": HUDSON_JOB_NAME,
        "HUDSON_BUILD_NUMBER": HUDSON_BUILD_NUMBER,
        "PROMOTED_BUILD_NUMBER": PROMOTED_BUILD_NUMBER,
        "PRODUCT_NAME": PRODUCT_NAME,
        "RAW_VERSION": RAW_VERSION,
        "RELEASE_NAME": RELEASE_NAME,
        "RELEASE_MILESTONE": RELEASE_MILESTONE];
    task processVersionInfo(type: Copy, description: "Replace params in VersionInfo and copy file to destination") {
        doFirst { mkdir "$buildDir/generated-src/version-info" }
        from "src/main/version-info"
        into "$buildDir/generated-src/version-info/com/sun/javafx/runtime"
        filter {line->
            replacements.each() {k, v ->
                line = line.replace("@$k@", v.toString());
            }
            line
        }
    }

    // Make sure to include $buildDir/generated-src/version-info that we previously created.
    // We DO NOT want to include src/main/version-info
    sourceSets.main.java.srcDirs = ["src/main/java", "$buildDir/generated-src/version-info"]
    compileJava.dependsOn processVersionInfo
}

// The graphics module is needed for any graphical JavaFX application. It requires
// the base module and includes the scene graph, layout, css, prism, windowing, etc.
// This is a fairly complicated module. There are many different types of native components
// that all need to be compiled.
project(":graphics") {
    sourceSets {
        main
        test
        stub
    }

    dependencies {
        compile project(":base"), project(":build-tools")
        compile ":$SWT_FILE_NAME:"
        stubCompile "junit:junit:4.8.2", project(":base").sourceSets.test.output, sourceSets.main.output
    }

    // The graphics project needs to completely replace the "test" task because the
    // tests have been split among the normal tests and the stub tests. I want to make sure
    // that invoking "graphics:test" runs both of these tasks, rather than only one of them.
    tasks.replace("test")
    test {
        group = "Verification"
        description = "Runs all the unit tests for Graphics"
    }
    task testWithoutStub(type: Test, dependsOn: ":graphics:compileJava", group: "Verification") {
        jvmArgs "-Djava.ext.dirs="
        classpath = sourceSets.test.runtimeClasspath + rootProject.files(rootProject.BINARY_STUB)
    }
    task testWithStub(type: Test, dependsOn: [":graphics:compileJava"], group: "Verification") {
        jvmArgs "-Djava.ext.dirs=", "-Djavafx.toolkit=com.sun.javafx.pgstub.StubToolkit", "-DCSS_META_DATA_TEST_DIR=${file('$buildDir/classes/main/javafx')}"
        classpath = sourceSets.stub.runtimeClasspath + sourceSets.main.runtimeClasspath + rootProject.files(rootProject.BINARY_STUB)
        testClassesDir = file("$buildDir/classes/stub")
        testResultsDir = file("$buildDir/stub-results")
        testReportDir = file("$buildDir/reports/stub")
    }
    [testWithoutStub, testWithStub].each { test ->
        test.enableAssertions = true
        test.testLogging.exceptionFormat = "full"
        test.scanForTestClasses = false
        test.include "**/*Test.*"
        test.exclude "**/*Abstract*.*"
    }
    test.dependsOn testWithoutStub, testWithStub

    // Add the tasks for native compilation of Glass
    addNative(project, "Glass");
    javahGlass.include("com/sun/glass/events/**",
                "com/sun/glass/ui/*",
                "com/sun/glass/ui/$GLASS_PLATFORM/*",
                "com/sun/glass/ui/accessible/$GLASS_PLATFORM/*");
    ccGlass.params.addAll(GLASS_CC_FLAGS);
    ccGlass.source(file("src/main/native-glass/$GLASS_PLATFORM"));
    linkGlass.linkParams.addAll(GLASS_LINK_FLAGS);
    linkGlass.lib = file("$project.buildDir/libs/${COMPILE_TARGET.name}/${library('glass')}");

    // Add the tasks for native compilation of Decora
    addNative(project, "Decora");
    javahDecora.include("com/sun/scenario/effect/**/*");
    ccDecora.params.addAll(DECORA_CC_FLAGS);
    ccDecora.source(file("src/main/native-decora"));
    linkDecora.linkParams.addAll(DECORA_LINK_FLAGS);
    linkDecora.lib = file("$project.buildDir/libs/${COMPILE_TARGET.name}/${library('decora-sse')}");

    // Add the tasks for native compilation of Prism
    addNative(project, "Prism")
    javahPrism.include("com/sun/prism/impl/**/*", "com/sun/prism/PresentableState*");
    ccPrism.compiler = PRISM_CC;
    ccPrism.params.addAll(CC_FLAGS);
    ccPrism.source(file("src/main/native-prism"));
    linkPrism.linkParams.addAll(PRISM_LINK_FLAGS);
    linkPrism.lib = file("$project.buildDir/libs/${COMPILE_TARGET.name}/${library('prism-common')}");

    // Add the tasks for native compilation of Prism Software Pipeline
    addNative(project, "PrismSW")
    javahPrismSW.include "com/sun/pisces/**/*"
    ccPrismSW.compiler = PRISM_SW_CC;
    ccPrismSW.params.addAll(PRISM_SW_CC_FLAGS);
    ccPrismSW.source(file("src/main/native-prism-sw"));
    linkPrismSW.linkParams.addAll(PRISM_SW_LINK_FLAGS);
    linkPrismSW.lib = file("$project.buildDir/libs/${COMPILE_TARGET.name}/${library('prism-sw')}");

    // Create a single "native" task which will depend on all the individual native tasks for graphics
    task("native", dependsOn: [nativeGlass, nativePrism, nativePrismSW, nativeDecora]) {
        group = "Build"
        description = "Compiles and Builds all native libraries for Graphics"
    }
}

project(":controls") {
    dependencies {
        compile project(":build-tools"), project(":base"), project(":graphics"), project(":designTime")
        testCompile project(":graphics").sourceSets.stub.output
    }

    test {
        jvmArgs "-Djavafx.toolkit=com.sun.javafx.pgstub.StubToolkit"
        // TODO fix the Controls tests so that we can run them all in one VM
        // This is highly unfortunate, test execution time goes from 7 sec to 2 min 8 sec
        // however there are 8 failing tests when we don't fork. Need to fix those tests.
        forkEvery = 1
    }

    // TODO Css2Bin really should be moved out and put into build-tools if it can be
    // TODO could change script to dynamically locate all .css files and create bss for them, probably better
    // TODO also not sure there is any benefit to having css files in the jfxrt.jar at all
    processResources << {
        ["$buildDir/resources/main/com/sun/javafx/scene/control/skin/caspian/caspian.css",
        "$buildDir/resources/main/com/sun/javafx/scene/control/skin/caspian/embedded-qvga.css",
        "$buildDir/resources/main/com/sun/javafx/scene/control/skin/caspian/embedded.css",
        "$buildDir/resources/main/com/sun/javafx/scene/control/skin/caspian/fxvk.css",
        "$buildDir/resources/main/com/sun/javafx/scene/control/skin/caspian/highcontrast.css",
        "$buildDir/resources/main/com/sun/javafx/scene/control/skin/modena/modena.css",
        "$buildDir/resources/main/com/sun/javafx/scene/control/skin/modena/touch.css"].each { css ->
            javaexec {
                classpath "$buildDir/classes/main"
                main = "com.sun.javafx.css.parser.Css2Bin"
                args css
            }
        }
    }
}

project(":swing") {
    // Skip Swing compilation when not on a compile target for MAC, WIN, LINUX
    if(COMPILE_TARGET != CompileTarget.WIN && COMPILE_TARGET != CompileTarget.MAC && COMPILE_TARGET != CompileTarget.LINUX) {
        tasks { enabled = false; }
    }

    dependencies {
        compile project(":build-tools"), project(":base"), project(":graphics")
    }
}

project(":swt") {
    // Skip SWT compilation when not on a compile target for MAC, WIN, LINUX
    if(COMPILE_TARGET != CompileTarget.WIN && COMPILE_TARGET != CompileTarget.MAC && COMPILE_TARGET != CompileTarget.LINUX) {
        tasks { enabled = false; }
    }

    dependencies {
        compile project(":build-tools"), project(":base"), project(":graphics")
        compile ":$SWT_FILE_NAME:"
    }
}

project(":fxml") {
    dependencies {
        compile project(":build-tools"), project(":base"), project(":graphics"),
                project(":controls"), project(":swt"), project(":swing")
        testCompile project(":graphics").sourceSets.stub.output
    }
    test {
        // StubToolkit is not *really* needed here, but because some code inadvertently invokes performance
        // tracker and this attempts to fire up the toolkit and this looks for native libraries and fails,
        // we have to use the stub toolkit for now.
        jvmArgs "-Djavafx.toolkit=com.sun.javafx.pgstub.StubToolkit"
    }
}

project(":designTime") {
    dependencies {
        compile project(":graphics")
    }
}

project(":graphics:effects-jsl") {
    dependencies {
        compile project(":graphics")
    }

    task compileJSL(description: "Compile Java Shader Language (JSL) files") { }
    classes.dependsOn compileJSL

    [[fileName: "ColorAdjust", generator: "CompileJSL", outputs: "-all"],
     [fileName: "Brightpass", generator: "CompileJSL", outputs: "-all"],
     [fileName: "SepiaTone", generator: "CompileJSL", outputs: "-all"],
     [fileName: "PerspectiveTransform", generator: "CompileJSL", outputs: "-all"],
     [fileName: "DisplacementMap", generator: "CompileJSL", outputs: "-all"],
     [fileName: "InvertMask", generator: "CompileJSL", outputs: "-all"],
     [fileName: "Blend", generator: "CompileBlend", outputs: "-all"],
     [fileName: "PhongLighting", generator: "CompilePhong", outputs: "-all"],
     [fileName: "LinearConvolve", generator: "CompileLinearConvolve", outputs: "-hw"],
     [fileName: "LinearConvolveShadow", generator: "CompileLinearConvolve", outputs: "-hw"]].each { settings ->
        task "compile$settings.fileName"(dependsOn: compileJava, type: JavaExec) {
            description = "Generate $settings.fileName shader from JSL"
            mkdir "modules/graphics/effects-jsl/build/generated-src/jsl"
            def destinationDir = "$buildDir/generated-src/jsl"
            def sourceDir = "src/main/java"
            inputs.file("$sourceDir/${settings.fileName}.jsl");
            if (IS_WINDOWS) outputs.file("$destinationDir/decora-d3d/build/gensrc/com/sun/scenario/effect/impl/hw/d3d/hlsl/${settings.fileName}.hlsl");
            outputs.file("$destinationDir/decora-es2/build/gensrc/com/sun/scenario/effect/impl/es2/glsl/${settings.fileName}.frag");
            outputs.file("$destinationDir/decora-jsw/build/gensrc/com/sun/scenario/effect/impl/sw/java/JSW${settings.fileName}.java");
            outputs.file("$destinationDir/decora-prism-ps/build/gensrc/com/sun/scenario/effect/impl/prism/ps/PPS${settings.fileName}.java");
            outputs.file("$destinationDir/decora-sse/build/gensrc/com/sun/scenario/effect/impl/sw/sse/SSE${settings.fileName}.java");
            outputs.file("$destinationDir/decora-sse-native/build/gensrc/SSE${settings.fileName}.cc");
            main = settings.generator
            classpath = configurations.compile
            classpath += files("modules/graphics/effects-jsl/build/classes/main")
            args = ["-i", sourceDir, "-o", destinationDir, "-pkg", "com/sun/scenario/effect", "$settings.outputs", "$settings.fileName"].flatten()
        }
        compileJSL.dependsOn "compile$settings.fileName"
    }

    task compileDecoraJava(dependsOn: compileJSL, type: JavaCompile) {
        description = "Compile Java-based Decora-JSL files"
        classpath = configurations.compile
        source = ["$buildDir/generated-src/jsl/decora-jsw/build/gensrc",
                "$buildDir/generated-src/jsl/decora-prism-ps/build/gensrc",
                "$buildDir/generated-src/jsl/decora-sse/build/gensrc"]
        destinationDir = file("$buildDir/classes/main")
    }
    classes.dependsOn compileDecoraJava

    if (IS_WINDOWS){
        task compileDecoraHLSL(dependsOn: compileJSL, type: CompileHLSLTask) {
            description = "Compile Decora HLSL files into .obj files"
            matches = ".*\\.hlsl"
            source "$buildDir/generated-src/jsl/decora-d3d/build/gensrc/com/sun/scenario/effect/impl/hw/d3d/hlsl/"
            output file("$buildDir/hlsl")
        }
        classes.dependsOn compileDecoraHLSL
    }

    task copyShaders(dependsOn: compileJSL, type: Copy, description: "Copy hlsl / frag shaders to $buildDir/resources/main") {
        from("$buildDir/generated-src/jsl/decora-d3d/build/gensrc") {
            include "**/*.hlsl"
        }
        from("$buildDir/generated-src/jsl/decora-es2/build/gensrc") {
            include("**/*.frag")
        }
        into "$buildDir/resources/main"
    }
    processResources.dependsOn copyShaders
}

project(":graphics:prism-jsl") {
    dependencies {
        compile project(":graphics")
    }

    task compileJSL(description: "Compile Java Shader Language (JSL) files") {}
    classes.dependsOn compileJSL

    def destDir = "$buildDir/generated-src/jsl"
    def sourceDir = "src/main/java"
    def inputFiles = fileTree(dir: sourceDir)
    inputFiles.include "**/*.jsl"

    inputFiles.each { file ->
        def taskName = file.name.substring(0, file.name.length() - 4);
        task "compile$taskName"(type: JavaExec) {
            // TODO need to fix bootclasspath
            dependsOn compileJava;
            dependsOn processResources;
            mkdir "modules/graphics/prism-jsl/build/generated-src/jsl"
            inputs.file(file);
            if (IS_WINDOWS) outputs.dir("$destDir/prism-d3d/build/gensrc/com/sun/prism/d3d/hlsl/");
            outputs.dir("$destDir/prism-es2/build/gensrc/com/sun/prism/es2/glsl/");
            outputs.dir("$destDir/prism-ps/build/gensrc/com/sun/prism/shader/");
            main = "CompileJSL"
            classpath = configurations.compile
            classpath += files("modules/graphics/prism-jsl/build/classes/main", "modules/graphics/prism-jsl/build/resources/main")
            args = ["-i", sourceDir, "-o", destDir, "-pkg", "com/sun/prism", "-d3d", "-es2", "-name", "$file"].flatten()
            maxHeapSize = "256m"
        }
        compileJSL.dependsOn "compile$taskName"
    }

    task compilePrismJSLJava(dependsOn: compileJSL, type: JavaCompile) {
        description = "Compile Java-based Prism-JSL files"
        classpath = configurations.compile
        source = "$buildDir/generated-src/jsl/prism-ps/build/gensrc"
        destinationDir = file("$buildDir/classes/main")
    }
    classes.dependsOn compilePrismJSLJava

    if (IS_WINDOWS){
        task compilePrismHLSL(dependsOn: compileJSL, type: CompileHLSLTask) {
            description = "Compile Prism HLSL files into .obj files"
            matches = ".*\\.hlsl"
            source "$buildDir/generated-src/jsl/prism-d3d/build/gensrc/com/sun/prism/d3d/hlsl/"
            output file("$buildDir/hlsl")
        }
        classes.dependsOn compilePrismHLSL
    }

    task copyPrismShaders(dependsOn: compileJSL, type: Copy, description: "Copy hlsl / frag shaders to $buildDir/resources/main") {
        from("$buildDir/generated-src/jsl/prism-d3d/build/gensrc") {
            include "**/*.hlsl"
        }
        from("$buildDir/generated-src/jsl/prism-es2/build/gensrc") {
            include("**/*.frag")
        }

        into "$buildDir/resources/main"
    }
    classes.dependsOn copyPrismShaders
}

project(":fxpackager") {
    // fxpackager has a dependency on ant in order to build the ant jar,
    // and as such needs to point to the apache binary repository
    repositories {
        maven {
            url "https://repository.apache.org"
        }
    }

    dependencies {
        compile "org.apache.ant:ant:1.8.2"
    }

    // When producing the jar, we need to relocate a few class files
    // from their normal location to a resources/classes or resources/web-files
    // location
    jar {
        includeEmptyDirs = false
        archiveName = "ant-javafx.jar"
        eachFile { FileCopyDetails details ->
            if (details.path.startsWith("com/javafx/main")) {
                details.path = "resources/classes/$details.path"
            } else if (details.path.startsWith("web-files")) {
                details.path = "resources/$details.path"
            }
        }
    }

    // The "man" task will create a $buildDir/man containing the man
    // files for the system being built
    task man(type: Copy) {
        includeEmptyDirs = false
        enabled = IS_LINUX || IS_MAC
        from "src/main/man"
        into "$buildDir/man"
        exclude "**/*.html"
        if (IS_MAC) exclude "**/ja_JP.UTF-8/**"
    }
    processResources.dependsOn man

    // Compile the native launchers. These are included in ant-javafx.jar
    if (IS_WINDOWS) {
        task compileWinLauncher(type: CCTask, group: "Build") {
            description = "Compiles native sources for the application co-bundle launcher";
            matches = "WinLauncher\\.cpp";
            params.addAll(LAUNCHER_CC_FLAGS);
            output(file("$buildDir/native/WinLauncher"));
            source(file("src/main/native/launcher/win"));
            exe = true;
            linkerOptions.addAll(LAUNCHER_LINK_FLAGS);
            doLast {
                copy {
                    from "$buildDir/native/WinLauncher/WinLauncher.exe"
                    into "$buildDir/classes/main/com/sun/javafx/tools/resource/windows"
                }
            }
        }
        task compileIconSwap(type: CCTask, group: "Build") {
            description = "Compiles native sources for the application co-bundle launcher"
            matches = "IconSwap\\.cpp"
            params.addAll(ICON_LAUNCHER_CC_FLAGS)
            output(file("$buildDir/native/IconSwap"))
            source file("src/main/native/launcher/win")
            exe = true
            linkerOptions.addAll(ICON_LAUNCHER_LINK_FLAGS)
            doLast {
                copy {
                    from "$buildDir/native/IconSwap/IconSwap.exe"
                    into "$buildDir/classes/main/com/sun/javafx/tools/resource/windows"
                }
            }
        }
        task compileLauncher(dependsOn: [compileWinLauncher, compileIconSwap])
    } else {
        task compileLauncher(type: CCTask, group: "Build") {
            description = "Compiles native sources for the application co-bundle launcher"
            if (IS_MAC) {
                matches = ".*\\.m"
                output(file("$buildDir/classes/main/com/sun/javafx/tools/resource/mac"))
                params.addAll(LAUNCHER_CC_FLAGS);
                source file("src/main/native/launcher/mac")
                eachOutputFile = { f ->
                    return new File(f.getParent(), "JavaAppLauncher")
                }
            } else {
                matches = ".*\\.c"
                output(file("$buildDir/classes/main/com/sun/javafx/tools/resource/linux"))
                params.addAll(LAUNCHER_CC_FLAGS)
                linkerOptions.addAll(LAUNCHER_LINK_FLAGS)
                source file("src/main/native/launcher/linux")
                eachOutputFile = { f ->
                    return new File(f.getParent(), "JavaAppLauncher")
                }
            }
        }
    }
    jar.dependsOn compileLauncher;

    // Builds the javafxpackager executable. For everything other than windows,
    // this is simply moving the existing shell script and ensuring it has proper
    // permissions. For Windows, this includes compiling the native executable
    if (IS_WINDOWS){
        task buildJavaFXPackager(type: CCTask, group: "Build") {
            description = "Compiles native sources for javafxpackager.exe"
            matches = "javafxpackager\\.cpp"
            params.addAll(["/nologo", "/W3", "/EHsc", "/MT", "/GS",
                    "/DWIN32", "/D_LITTLE_ENDIAN", "/DWIN32_LEAN_AND_MEAN",
                    "/D_WIN32_WINDOWS=0X0500", "/D_WIN32_WINNT=0X0500",
                    "/I$JDK_HOME/include", "/I$JDK_HOME/include/win32", "/arch:SSE", "/fp:fast",
                    "/O2", "-c"])
            output(file("$buildDir/native/javafxpackager"))
            source file("src/main/native/javafxpackager/win")
            doLast {
                mkdir "$buildDir/native"
                exec({
                    commandLine("$RC", "/nologo", "/l", "0x409", "/r", "/dJFX_DVERSION=8", "/dJFX_VERSION=8",
                            "/fo$buildDir/native/javafxpackager/javafxpackager.res",
                            "src/main/native/javafxpackager/win/javafxpackager.rc");
                    environment(WINDOWS_NATIVE_COMPILE_ENVIRONMENT);
                });
            }
            doLast {
                mkdir "$buildDir/javafxpackager"
                exec({
                    commandLine("$LINK", "/nologo", "/opt:REF", "/incremental:no", "/manifest", "kernel32.lib", "advapi32.lib",
                            "/out:$buildDir/native/javafxpackager/javafxpackager.exe",
                            "$buildDir/native/javafxpackager/javafxpackager.obj",
                            "$buildDir/native/javafxpackager/javafxpackager.res")
                    environment(WINDOWS_NATIVE_COMPILE_ENVIRONMENT)
                })
            }
            doLast {
                copy {
                    from file("src/main/native/javafxpackager/win/javafxpackager.manifest")
                    into file("$buildDir/native/javafxpackager")
                }
                // TODO, not sure MT.exe is actually being used currently, so for now skipping.
//                exec({
//                    commandLine("$MT -nologo -manifest $buildDir/native/javafxpackager/javafxpackager.manifest")
//                    environment(WINDOWS_NATIVE_COMPILE_ENVIRONMENT)
//                })
                copy {
                    from file("$buildDir/native/javafxpackager/javafxpackager.exe")
                    into file("$buildDir/javafxpackager")
                }
            }
        }
    } else {
        task buildJavaFXPackager(group: "Build") << {
            copy {
                from "src/main/native/javafxpackager/shell"
                into "$buildDir/javafxpackager"
                fileMode = 0755
            }
        }
    }

    jar.dependsOn buildJavaFXPackager
}

/******************************************************************************
 *                                                                            *
 *                             Top Level Tasks                                *
 *                                                                            *
 *  These are the tasks which are defined only for the top level project and  *
 *  not for any sub projects. These are generally the entry point that is     *
 *  used by Hudson and by the continuous build system.                        *
 *                                                                            *
 *****************************************************************************/

task clean() {
    group = "Basic"
    description = "Deletes the build directory and the build directory of all sub projects"
    getSubprojects().each { subProject ->
        dependsOn(subProject.getTasksByName("clean", true));
    }
    doLast {
        delete(buildDir);
    }
}

// The jfxrt task is responsible for creating the jfxrt.jar. A developer may
// have multiple SDK's on their system at any one time, depending on which
// cross compiles they have done. For example, I might have:
//      build/mac-sdk/rt/lib/ext/jfxrt.jar
//      build/ios-sdk/rt/lib/ext/jfxrt.jar
//      build/win-sdk/rt/lib/ext/jfxrt.jar
//      build/armhf-sdk/rt/lib/ext/jfxrt.jar
//
// and so forth. This arrangement allows for multiple independent SDKs to
// exist on a developer's system.
task jfxrt(type: Jar) {
    group = "Basic"
    description = "Creates the jfxrt.jar"
    archiveName = "build/${COMPILE_TARGET.name}-sdk/rt/lib/ext/jfxrt.jar";
    includeEmptyDirs = false
    from("modules/base/build/classes/main",
         "modules/base/build/resources/main",
         "modules/graphics/build/classes/main",
         "modules/graphics/build/resources/main",
         "modules/controls/build/classes/main",
         "modules/controls/build/resources/main",
         "modules/fxml/build/classes/main",
         "modules/fxml/build/resources/main",
         "modules/graphics/effects-jsl/build/classes/main",
         "modules/graphics/effects-jsl/build/resources/main",
         "modules/graphics/prism-jsl/build/classes/main",
         "modules/graphics/prism-jsl/build/resources/main");
    exclude("Compile*", // the Decora compiler classes must be excluded
            "js/**/*", // er...
            "PrismLoaderBackend*", // More decora stuff
            "**/*.stg",    // any glue files for decora must be excluded
            "**/*.java");  // Builder java files are in build/classes and should be excluded

    // We only need to include Swing & SWT when we're building for one of the desktop
    // compile targets (mac, win, linux, swt), not when we're building for iOS etc.
    if (COMPILE_TARGET.isDesktop) {
        from("modules/swing/build/classes/main",
             "modules/swing/build/resources/main",
             "modules/swt/build/classes/main",
             "modules/swt/build/resources/main");
    }

    // Filter out platform specific Java sources (glass) when compiling for other targets
    if (COMPILE_TARGET != CompileTarget.WIN) exclude("**/*.hlsl", "com/sun/glass/ui/win",
            "com/sun/glass/ui/accessible/win", "com/sun/prism/d3d",
            "com/sun/prism/es2/gl/win", "com/sun/prism/null3d", "com/sun/scenario/effect/impl/hw/d3d");
    if (COMPILE_TARGET != CompileTarget.IOS) exclude("com/sun/glass/ui/ios");
    if (COMPILE_TARGET != CompileTarget.MAC) exclude("com/sun/glass/events/mac",
            "com/sun/glass/ui/mac", "com/sun/glass/ui/accessible/mac");
    if (COMPILE_TARGET != CompileTarget.LINUX) exclude("com/sun/glass/ui/gtk");
    if (COMPILE_TARGET != CompileTarget.LINUX &&
            COMPILE_TARGET != CompileTarget.ARM_HF &&
            COMPILE_TARGET != CompileTarget.ARM_VFP) exclude("com/sun/glass/ui/lens",
                "com/sun/prism/es2/gl/eglfb", "com/sun/prism/es2/gl/eglx11",
                "com/sun/prism/es2/gl/x11");
    if (COMPILE_TARGET != CompileTarget.ARM_HF && COMPILE_TARGET != CompileTarget.ARM_VFP)
        exclude("com/sun/prism/es2/gl/eglfb", "com/sun/prism/es2/gl/eglx11");
    if (COMPILE_TARGET != CompileTarget.SWT) exclude("com/sun/glass/ui/swt");

    dependsOn(subprojects.collect { project -> project.getTasksByName("assemble", true)});
}

task javadoc(type: Javadoc) {
    group = "Basic"
    description = "Generates the JavaDoc for all the public API"
    executable = JAVADOC
    def projectsToDocument = [
            project(":base"), project(":graphics"), project(":controls"),
            project(":swing"), project(":swt"), project(":fxml")]
    source(projectsToDocument.collect({
        [it.sourceSets.main.java, "$it.buildDir/builder-src"]
    }));
    setDestinationDir(new File(buildDir, 'javadoc'));
    // Might need a classpath
    classpath = files(projectsToDocument.collect { project ->
        project.sourceSets.main.compileClasspath
    });
    exclude("com/**/*", "javafx/scene/ParentDesignInfo*", "Compile*", "javafx/builder/**/*");
    options.windowTitle("JavaFX ${RELEASE_NAME}")
    options.links(JDK_DOCS);
    options.addBooleanOption("XDignore.symbol.file").setValue(true);
    options.addBooleanOption("Xdoclint:none").setValue(!IS_DOC_LINT);
    options.addBooleanOption("javafx").setValue(true);
    doLast {
        projectsToDocument.each { p ->
            copy {
                from "$p.projectDir/src/main/docs"
                into "$buildDir/javadoc"
            }
        }
    }

    dependsOn(projectsToDocument.collect { project -> project.getTasksByName("classes", true)});
}

// The 'sdk' task will build the rest of the SDK, and depends on the 'jfxrt' task. After
// executing this task the sdk bundle for the current COMPILE_TARGET will be fully created.
task sdk {
    group = "Basic"
    description = "Creates an SDK"
    doLast {
        // Copy all of the .dll / .so / .dylib native libraries into build/sdk/rt/lib/
        copy {
            from("modules/graphics/build/libs/${COMPILE_TARGET.name}/${library('decora-sse')}",
                 "modules/graphics/build/libs/${COMPILE_TARGET.name}/${library('prism-common')}",
                 "modules/graphics/build/libs/${COMPILE_TARGET.name}/${library('prism-sw')}",
                 "modules/graphics/build/libs/${COMPILE_TARGET.name}/${library('glass')}");
            if (IS_WINDOWS) {
                rename("lib(.*).dll", "\$1.dll");
            }
            if (COMPILE_TARGET == CompileTarget.MAC || COMPILE_TARGET == CompileTarget.IOS) {
                into("build/${COMPILE_TARGET.name}-sdk/rt/lib");
            } else if (COMPILE_TARGET == CompileTarget.WIN) {
                into("build/${COMPILE_TARGET.name}-sdk/rt/bin");
            } else {
                into("build/${COMPILE_TARGET.name}-sdk/rt/lib/$OS_ARCH");
            }
        }

        // Create the javafx.properties file
        final File javafxProperties = file("build/${COMPILE_TARGET.name}-sdk/rt/lib/javafx.properties");
        javafxProperties << "javafx.runtime.version=$RAW_VERSION";

        // Copy over the javadocs that were generated. This is done rather than just generating
        // the docs into the "right place" because for a cross-compile you only need one set of
        // docs but need to have a copy in each created sdk
        copy {
            from("build/javadoc");
            into("build/${COMPILE_TARGET.name}-sdk/docs/api");
        }

        // Copy over the fxpackager and rename as ant-javafx.jar
        copy {
            from "modules/fxpackager/build/libs"
            into "build/${COMPILE_TARGET.name}-sdk/lib"
        }

        // Copy over the FXPackager man files
        copy {
            from "modules/fxpackager/build/man"
            into "build/${COMPILE_TARGET.name}-sdk/man"
        }

        // Copy over the javafxpackager executable
        copy {
            from "modules/fxpackager/build/javafxpackager"
            into "build/${COMPILE_TARGET.name}-sdk/bin"
        }
    }
    dependsOn(jfxrt);
    dependsOn(javadoc);
}

/******************************************************************************
 *                                                                            *
 *                 Generation of NetBeans Project Files                       *
 *                                                                            *
 *  This next section is responsible for setting up the work for generation   *
 *  of NetBeans project files. The developer needs to invoke                  *
 *                                                                            *
 *      gradle netbeans                                                       *
 *                                                                            *
 *  and all necessary project files will be generated. Note that unlike       *
 *  Eclipse and IDEA, NetBeans natively understands Gradle build files so     *
 *  the project files generated for NetBeans is limited to just shared        *
 *  configuration files. Make sure you have the latest stable release of      *
 *                                                                            *
 *  http://plugins.netbeans.org/plugin/44510/gradle-support                   *
 *                                                                            *
 *  for your version of the IDE.                                              *
 *                                                                            *
 *****************************************************************************/

/*
  <built-in-tasks>
    <task>
      <display-name>build</display-name>
      <non-blocking>yes</non-blocking>
      <task-names>
        <name must-exist="no">build</name>
      </task-names>
      <task-args>
        <arg>-PSUPPLEMENTAL_BUILD_FILE=../rt-closed/closed-build.gradle</arg>
      </task-args>
      <task-jvm-args/>
    </task>
  </built-in-tasks>
  <common-tasks>
    <task>
      <display-name>sdk</display-name>
      <non-blocking>no</non-blocking>
      <task-names>
        <name must-exist="yes">tasks</name>
      </task-names>
      <task-args>
        <arg>-PSUPPLEMENTAL_BUILD_FILE=../rt-closed/closed-build.gradle</arg>
      </task-args>
      <task-jvm-args/>
    </task>
  </common-tasks>

 */

task netBeans() {
    description = "Creates the NetBeans project files for JavaFX"
    group = "IDE"

    doLast {
        File nbGradleProperties = file(".nb-gradle-properties")
        if (nbGradleProperties.exists()) nbGradleProperties.delete()
        nbGradleProperties.createNewFile()
        nbGradleProperties <<
"""<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<gradle-project-properties>
  <!--DO NOT EDIT THIS FILE! - Used by the Gradle plugin of NetBeans.-->
  <source-encoding>UTF-8</source-encoding>
  <target-platform-name>j2se</target-platform-name>
  <target-platform>1.7</target-platform>
  <source-level>1.7</source-level>
  <script-platform>
    <spec-name>j2se</spec-name>
    <spec-version>1.8</spec-version>
  </script-platform>
  <gradle-home>?VER=1.4</gradle-home>
  <license-header>
    <name>OpenJFX</name>
    <template>.nb-openjfx-template-license</template>
    <property name="organization">OpenJFX</property>
  </license-header>
</gradle-project-properties>"""

        File nbGradleTemplate = file(".nb-openjfx-template-license")
        if (nbGradleTemplate.exists()) nbGradleTemplate.delete()
        nbGradleTemplate.createNewFile()
        nbGradleTemplate <<
"""My License will reign supreme!"""
    }
}

task cleanNetBeans() {
    description = "Deletes generated NetBeans files"
    group = "IDE"
    doLast {
        file(".nb-gradle-properties").delete()
    }
}

/******************************************************************************
 *                                                                            *
 *                   Generation of IDEA Project Files                         *
 *                                                                            *
 *  This next section is responsible for setting up the work for generation   *
 *  of IntelliJ IDEA project files. The developer needs to invoke             *
 *                                                                            *
 *      gradle idea                                                           *
 *                                                                            *
 *  and all necessary project files will be generated.                        *
 *                                                                            *
 *****************************************************************************/

allprojects {
    apply plugin: 'idea'
    if (project == rootProject || project.name == "media" || project.name == "web") return

    // Configure all projects to include $buildDir/builder-src in the generated IDEA project files.
    // Also need to un-exclude the build-dir since we put stuff in it, and then re-exclude other stuff
    configurations {
      binaryStub
      binaryStub.extendsFrom(compile)
    }

    dependencies {
      binaryStub rootProject.files(rootProject.BINARY_STUB)
    }

    idea {
        module {
            inheritOutputDirs = true;
            sourceDirs += new File(buildDir, "builder-src");
            excludeDirs -= buildDir;
            excludeDirs += [
                    new File(buildDir, "classes"),
                    new File(buildDir, "dependency-cache"),
                    new File(buildDir, "libs"),
                    new File(buildDir, "resources"),
                    new File(buildDir, "tmp")];
            scopes.COMPILE.plus += configurations.binaryStub

            // Some hackery. I have to make sure the binary stub is the VERY LAST entry
            // in the class path or things will be somewhat unpredictable
            iml {
                withXml { xmlProvider ->
                    def root = xmlProvider.asNode();
                    // Find the <root url=".../jfxrt.jar!/" />. Walk up 3 steps to <orderEntry>
                    def orderEntry = root.depthFirst().find { it.name() == "root" }.parent().parent().parent(); // && it.@url.contains(rootProject.files(rootProject.BINARY_STUB))
                    if (orderEntry.name() != "orderEntry") throw new Exception("Couldn't find the order entry");
                    // Move that <orderEntry> to be the last child of its parent.
                    def parent = orderEntry.parent();
                    parent.remove(orderEntry);
                    parent.append(orderEntry);
                }
            }
        }
    }
}

/**
 * I want to keep all the project files and out directory and such all hidden from the filesystem
 * for the most part, so we don't have a lot of .iml files strewn about. So what we will do is
 * to redirect all of the .iml files into a .idea directory on the root project level, and stash the
 * out/ for all the projects there as well as the project module definition files.
 */
idea {
    project {
        jdkName = "JavaFX 1.7"
        languageLevel = "1.7"
        wildcards += ["?*.css", "?*.bss", "?*.glsl", "?*.frag", "?*.ttf", "?*.txt", "?*.fxml"]
        ipr {
            withXml { xmlProvider ->
                def root = xmlProvider.asNode();
                def doc = root.depthFirst();

                // Set the copyright
                def copyrightManager = doc.find { it.name() == "component" && it.@name == "CopyrightManager" };
                copyrightManager.@default="OpenJFX";
                def module2copyright = copyrightManager.get("module2copyright");
                module2copyright.replaceNode {
                    copyright {
                        option(name: "notice", value:
"""Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.

This code is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 only, as
published by the Free Software Foundation.  Oracle designates this
particular file as subject to the "Classpath" exception as provided
by Oracle in the LICENSE file that accompanied this code.

This code is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
version 2 for more details (a copy is included in the LICENSE file that
accompanied this code).

You should have received a copy of the GNU General Public License version
2 along with this work; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.

Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
or visit www.oracle.com if you need additional information or have any
questions.""");
                        option(name: "keyword", value: "Copyright");
                        option(name: "allowReplaceKeyword", value: "");
                        option(name: "myName", value: "OpenJFX");
                        option(name: "myLocal", value: "true");
                    }
                }

                // Remove some setting and change the project output directory
                def projectRootManager = doc.find { it.name() == "component" && it.@name == "ProjectRootManager" };
                projectRootManager.attributes.remove("assert-jdk-15");
                projectRootManager.children()[0].@url = "file://\$PROJECT_DIR\$/.idea-out";

                // Add in some custom dictionary stuff so that people get fewer green-squigglies
                // in their code. Nothing like a green squiggly to ruin my day.
                copyrightManager.plus {
                    component(name: "ProjectDictionaryState") {
                        dictionary(name: "javafx") {
                            words {
                                w (text: "backoff")
                                w (text: "blhr")
                                w (text: "blvr")
                                w (text: "brhr")
                                w (text: "brvr")
                                w (text: "gradle")
                                w (text: "gzip")
                                w (text: "halignment")
                                w (text: "interpolator")
                                w (text: "jfxrt")
                                w (text: "multithreaded")
                                w (text: "redoable")
                                w (text: "resized")
                                w (text: "squigglies")
                                w (text: "subclassing")
                                w (text: "timeline")
                                w (text: "timeline's")
                                w (text: "tlhr")
                                w (text: "tlvr")
                                w (text: "trhr")
                                w (text: "trvr")
                                w (text: "unmanaged")
                                w (text: "unselect")
                                w (text: "urlencoded")
                                w (text: "valignment")
                            }
                        }
                    }
                }

                // Setup some common project settings like tabs vs. spaces
                copyrightManager.plus {
                    component(name: "CodeStyleSettingsManager") {
                        option(name: "PER_PROJECT_SETTINGS") {
                            value {
                                ADDITIONAL_INDENT_OPTIONS(fileType: "java") {
                                    option (name: "IDENT_SIZE", value: "4")
                                    option (name: "CONTINUATION_INDENT_SIZE", value: "8")
                                    option (name: "TAB_SIZE", value: "4")
                                    option (name: "USE_TAB_CHARACTER", value: "false")
                                    option (name: "SMART_TABS", value: "false")
                                    option (name: "LABEL_INDENT_SIZE", value: "0")
                                    option (name: "LABEL_INDENT_ABSOLUTE", value: "false")
                                    option (name: "USE_RELATIVE_INDENTS", value: "false")
                                }
                                ADDITIONAL_INDENT_OPTIONS(fileType: "xml") {
                                    option (name: "IDENT_SIZE", value: "4")
                                    option (name: "CONTINUATION_INDENT_SIZE", value: "8")
                                    option (name: "TAB_SIZE", value: "4")
                                    option (name: "USE_TAB_CHARACTER", value: "false")
                                    option (name: "SMART_TABS", value: "false")
                                    option (name: "LABEL_INDENT_SIZE", value: "0")
                                    option (name: "LABEL_INDENT_ABSOLUTE", value: "false")
                                    option (name: "USE_RELATIVE_INDENTS", value: "false")
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

project(":build-tools") {
    // Add antlr to the sources for IDEA
    idea {
        module {
            sourceDirs += file("$buildDir/generated-src/antlr")
        }
    }
}

project(":base") {
    // Add in the version-info generated sources for IDEA projects
    idea {
        module {
            sourceDirs += file("$buildDir/generated-src/version-info")
        }
    }
}

project(":graphics") {
    idea {
        module {
            sourceDirs += [new File(buildDir, "headers"),
                    file("src/main/native-decora"),
                    file("src/main/native-glass/gtk"),
                    file("src/main/native-glass/ios"),
                    file("src/main/native-glass/lens"),
                    file("src/main/native-glass/mac"),
                    file("src/main/native-glass/win"),
                    file("src/main/native-prism"),
                    file("src/main/native-prism-sw")]
            excludeDirs += new File(buildDir, "native");
            testSourceDirs += [file("src/stub/java"), file("src/stub/resources")];
        }
    }
}

project(":controls") {
    idea {
        module {
            sourceDirs += file("src/main/dt");
        }
    }
}

project(":graphics:effects-jsl") {
    idea {
        module {
            sourceDirs += file("$buildDir/generated-src/jsl")
        }
    }
}

project(":graphics:prism-jsl") {
    idea {
        module {
            sourceDirs += file("$buildDir/generated-src/jsl")
        }
    }
}

cleanIdeaWorkspace.group = "IDE"
cleanIdeaWorkspace.description = "Deletes the javafx.ipw file"

/******************************************************************************
 *                                                                            *
 *                         SUPPLEMENTAL_BUILD_FILE                            *
 *                                                                            *
 * This next section should remain at the end of the build script. It allows  *
 * for a "supplemental" gradle file to be used to extend the normal build     *
 * structure. For example, this is used for passing a supplemental gradle     *
 * file for producing official JavaFX builds.                                 *
 *                                                                            *
 *****************************************************************************/

if (hasProperty("SUPPLEMENTAL_BUILD_FILE")) {
    apply from: SUPPLEMENTAL_BUILD_FILE
}