/* * Copyright (c) 2015, 2024, 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. */ /* * This file defines build profiles for the JIB tool and others. * * A build profile defines a set of configuration options and external * dependencies that we for some reason or other care about specifically. * Typically, build profiles are defined for the build configurations we * build regularly. * * Contract against this file from the tools that use it, is to provide * a function on the form: * * getJibProfiles(input) * * which returns an object graph describing the profiles and their * dependencies. The name of the function is based on the name of this * file, minus the extension and the '-', camel cased and prefixed with * 'get'. * * * The parameter 'input' is an object that optionally contains some data. * Optionally because a tool may read the configuration for different purposes. * To initially get a list of available profiles, the active profile may not * yet be known for instance. * * Data that may be set on the input object: * * input.profile = * * If the active profile is set, the following data from it must also * be provided: * * input.profile * input.build_id * input.target_os * input.target_cpu * input.build_os * input.build_cpu * input.target_platform * input.build_platform * // The build_osenv_* variables describe the unix layer on Windows systems, * // i.e. Cygwin, which may also be 32 or 64 bit. * input.build_osenv * input.build_osenv_cpu * input.build_osenv_platform * input.build_osenv_version * * For more complex nested attributes, there is a method "get": * * input.get("", "") * * Valid attributes are: * install_path * download_path * download_dir * home_path * * * The output data generated by this configuration file has the following * format: * * data: { * // Identifies the version of this format to the tool reading it * format_version: "1.0", * * // Name of base outputdir. JIB assumes the actual output dir is formed * // by adding the configuration name: / * output_basedir: "build", * // Configure argument to use to specify configuration name * configuration_configure_arg: * // Make argument to use to specify configuration name * configuration_make_arg: * * profiles: { * : { * // Name of os the profile is built to run on * target_os; * // Name of cpu the profile is built to run on * target_cpu; * // Combination of target_os and target_cpu for convenience * target_platform; * // Name of os the profile is built on * build_os; * // Name of cpu the profile is built on * build_cpu; * // Combination of build_os and build_cpu for convenience * build_platform; * * // List of dependencies needed to build this profile * dependencies: * * // List of configure args to use for this profile * configure_args: * * // List of free form labels describing aspects of this profile * labels: * } * } * * // Dependencies use a Maven like deployment structure * dependencies: { * : { * // Organization part of path defining this dependency * organization: * // File extension for this dependency * ext: * // Module part of path for defining this dependency, * // defaults to * module: * // Revision part of path for defining this dependency * revision: * * // List of configure args to add when using this dependency, * // defaults to * // "--with-=input.get(" * * // Name of environment variable to set when using this dependency * // when running make * environment_name: * // Value of environment variable to set when using this dependency * // when running make * environment_value: * * // Value to add to the PATH variable when using this dependency, * // applies to both make and configure * environment_path: * } * * : { * // For certain dependencies where a legacy distribution mechanism is * // already in place, the "javare" server layout is also supported * // Indicate that an alternate server source and layout should be used * server: "javare" * * // For "javare", a combination of module, revision, * // build number (optional), files and checksum file is possible for * // artifacts following the standard layout. * module: * revision: * build_number: * checksum_file: * file: * * // For other files, use checksum path and path instead * checksum_path: * path: * } * } * } */ /** * Main entry to generate the profile configuration * * @param input External data to use for generating the configuration * @returns {{}} Profile configuration */ var getJibProfiles = function (input) { var data = {}; // Identifies the version of this format to the tool reading it. // 1.1 signifies that the publish, publish-src and get-src features are usable. // 1.2 signifies that artifact uploads should fail on missing artifacts by default. // 1.3 input.get(, "home_path") automatically goes down into a single top // dir just like default configure_args and environment_path variables. data.format_version = "1.3"; // Organization, product and version are used when uploading/publishing build results data.organization = ""; data.product = "jdk"; data.version = getVersion(); // The base directory for the build output. JIB will assume that the // actual build directory will be / data.output_basedir = "build"; // The configure argument to use to specify the name of the configuration data.configuration_configure_arg = "--with-conf-name="; // The make argument to use to specify the name of the configuration data.configuration_make_arg = "CONF_NAME="; // Exclude list to use when Jib creates a source bundle data.src_bundle_excludes = [ "build", "{,**/}webrev*", "{,**/}.hg", "{,**/}JTwork*", "{,**/}JTreport*", "{,**/}.git" ]; // Include list to use when creating a minimal jib source bundle which // contains just the jib configuration files. data.conf_bundle_includes = [ "make/conf/version-numbers.conf", ]; // Define some common values var common = getJibProfilesCommon(input, data); // Generate the profiles part of the configuration data.profiles = getJibProfilesProfiles(input, common, data); // Generate the dependencies part of the configuration data.dependencies = getJibProfilesDependencies(input, common, data); return data; }; /** * Generates some common values * * @param input External data to use for generating the configuration * @returns Common values */ var getJibProfilesCommon = function (input, data) { var common = {}; common.organization = "jpg.infra.builddeps"; common.build_id = getBuildId(input); common.build_number = input.build_number != null ? input.build_number : "0"; // List of the main profile names used for iteration common.main_profile_names = [ "linux-x64", "linux-x86", "macosx-x64", "macosx-aarch64", "windows-x64", "windows-x86", "windows-aarch64", "linux-aarch64", "linux-arm32", "linux-ppc64le", "linux-s390x", "linux-riscv64" ]; // These are the base settings for all the main build profiles. common.main_profile_base = { dependencies: ["boot_jdk", "gnumake", "jtreg", "jib", "autoconf", "jmh", "jcov"], default_make_targets: ["product-bundles", "test-bundles", "static-libs-bundles"], configure_args: concat( "--with-exclude-translations=es,fr,it,ko,pt_BR,sv,ca,tr,cs,sk,ja_JP_A,ja_JP_HA,ja_JP_HI,ja_JP_I,zh_TW,zh_HK", "--disable-jvm-feature-shenandoahgc", "--disable-cds-archive-coh", versionArgs(input, common)) }; // Extra settings for debug profiles common.debug_suffix = "-debug"; common.debug_profile_base = { configure_args: ["--enable-debug"], labels: "debug" }; // Extra settings for slowdebug profiles common.slowdebug_suffix = "-slowdebug"; common.slowdebug_profile_base = { configure_args: ["--with-debug-level=slowdebug"], labels: "slowdebug" }; // Extra settings for optimized profiles common.optimized_suffix = "-optimized"; common.optimized_profile_base = { configure_args: ["--with-debug-level=optimized"], labels: "optimized", }; // Extra settings for openjdk only profiles common.open_suffix = "-open"; common.open_profile_base = { configure_args: ["--enable-openjdk-only"], labels: "open" }; common.configure_args_64bit = ["--with-target-bits=64"]; common.configure_args_32bit = ["--with-target-bits=32"]; /** * Define common artifacts template for all main profiles * @param o - Object containing data for artifacts */ common.main_profile_artifacts = function (o) { var jdk_subdir = (o.jdk_subdir != null ? o.jdk_subdir : "jdk-" + data.version); var jdk_suffix = (o.jdk_suffix != null ? o.jdk_suffix : "tar.gz"); var pf = o.platform return { artifacts: { jdk: { local: "bundles/\\(jdk.*bin." + jdk_suffix + "\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin." + jdk_suffix, "bundles/" + pf + "/\\1" ], subdir: jdk_subdir, exploded: "images/jdk" }, test: { local: "bundles/\\(jdk.*bin-tests.tar.gz\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-tests.tar.gz", "bundles/" + pf + "/\\1" ], exploded: "images/test" }, test_demos: { local: "bundles/\\(jdk.*bin-tests-demos.tar.gz\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-tests-demos.tar.gz", "bundles/" + pf + "/\\1" ], exploded: "images/test" }, jdk_symbols: { local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-symbols.tar.gz", "bundles/" + pf + "/\\1" ], subdir: jdk_subdir, exploded: "images/jdk" }, static_libs: { local: "bundles/\\(jdk.*bin-static-libs.tar.gz\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-static-libs.tar.gz", "bundles/" + pf + "/\\1" ], subdir: jdk_subdir, }, } }; }; /** * Define common artifacts template for all debug profiles * @param o - Object containing data for artifacts */ common.debug_profile_artifacts = function (o) { var jdk_subdir = "jdk-" + data.version + "/fastdebug"; var jdk_suffix = (o.jdk_suffix != null ? o.jdk_suffix : "tar.gz"); var pf = o.platform return { artifacts: { jdk: { local: "bundles/\\(jdk.*bin-debug." + jdk_suffix + "\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-debug." + jdk_suffix, "bundles/" + pf + "/\\1" ], subdir: jdk_subdir, exploded: "images/jdk" }, test: { local: "bundles/\\(jdk.*bin-tests-debug.tar.gz\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-tests-debug.tar.gz", "bundles/" + pf + "/\\1" ], exploded: "images/test" }, jdk_symbols: { local: "bundles/\\(jdk.*bin-debug-symbols.tar.gz\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-debug-symbols.tar.gz", "bundles/" + pf + "/\\1" ], subdir: jdk_subdir, exploded: "images/jdk" }, static_libs: { local: "bundles/\\(jdk.*bin-static-libs-debug.tar.gz\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-static-libs-debug.tar.gz", "bundles/" + pf + "/\\1" ], subdir: jdk_subdir, }, } }; }; common.boot_jdk_version = "23"; common.boot_jdk_build_number = "37"; common.boot_jdk_home = input.get("boot_jdk", "install_path") + "/jdk-" + common.boot_jdk_version + (input.build_os == "macosx" ? ".jdk/Contents/Home" : ""); return common; }; /** * Generates the profiles part of the configuration. * * @param input External data to use for generating the configuration * @param common The common values * @returns {{}} Profiles part of the configuration */ var getJibProfilesProfiles = function (input, common, data) { var cross_compiling = input.build_platform != input.target_platform; // Main SE profiles var profiles = { "linux-x64": { target_os: "linux", target_cpu: "x64", dependencies: ["devkit", "gtest", "build_devkit", "graphviz", "pandoc", "tidy"], configure_args: concat( (input.build_cpu == "x64" ? common.configure_args_64bit : "--openjdk-target=x86_64-linux-gnu"), "--with-zlib=system", "--disable-dtrace", (isWsl(input) ? [ "--host=x86_64-unknown-linux-gnu", "--build=x86_64-unknown-linux-gnu" ] : [])), }, "linux-x86": { target_os: "linux", target_cpu: "x86", build_cpu: "x64", dependencies: ["devkit", "gtest", "libffi"], configure_args: concat(common.configure_args_32bit, [ "--with-jvm-variants=minimal,server", "--with-zlib=system", "--with-libffi=" + input.get("libffi", "home_path"), "--enable-libffi-bundling", "--enable-fallback-linker" ]) }, "macosx-x64": { target_os: "macosx", target_cpu: "x64", dependencies: ["devkit", "gtest", "graphviz", "pandoc", "tidy"], configure_args: concat(common.configure_args_64bit, "--with-zlib=system", "--with-macosx-version-max=11.00.00", "--enable-compatible-cds-alignment", // Use system SetFile instead of the one in the devkit as the // devkit one may not work on Catalina. "SETFILE=/usr/bin/SetFile"), }, "macosx-aarch64": { target_os: "macosx", target_cpu: "aarch64", dependencies: ["devkit", "gtest", "graphviz", "pandoc", "tidy"], configure_args: concat(common.configure_args_64bit, "--with-macosx-version-max=11.00.00"), }, "windows-x64": { target_os: "windows", target_cpu: "x64", dependencies: ["devkit", "gtest", "pandoc"], configure_args: concat(common.configure_args_64bit), }, "windows-x86": { target_os: "windows", target_cpu: "x86", build_cpu: "x64", dependencies: ["devkit", "gtest"], configure_args: concat(common.configure_args_32bit, "--enable-deprecated-ports"), }, "windows-aarch64": { target_os: "windows", target_cpu: "aarch64", dependencies: ["devkit", "gtest", "build_devkit"], configure_args: [ "--openjdk-target=aarch64-unknown-cygwin", ], }, "linux-aarch64": { target_os: "linux", target_cpu: "aarch64", dependencies: ["devkit", "gtest", "build_devkit", "graphviz", "pandoc", "tidy"], configure_args: [ "--with-zlib=system", "--disable-dtrace", "--enable-compatible-cds-alignment", ].concat(cross_compiling ? ["--openjdk-target=aarch64-linux-gnu"] : []), }, "linux-arm32": { target_os: "linux", target_cpu: "arm", build_cpu: "x64", dependencies: ["devkit", "gtest", "build_devkit"], configure_args: [ "--openjdk-target=arm-linux-gnueabihf", "--with-freetype=bundled", "--with-abi-profile=arm-vfp-hflt", "--disable-warnings-as-errors" ], }, "linux-ppc64le": { target_os: "linux", target_cpu: "ppc64le", build_cpu: "x64", dependencies: ["devkit", "gtest", "build_devkit"], configure_args: [ "--openjdk-target=ppc64le-linux-gnu", "--with-freetype=bundled", "--disable-warnings-as-errors" ], }, "linux-s390x": { target_os: "linux", target_cpu: "s390x", build_cpu: "x64", dependencies: ["devkit", "gtest", "build_devkit"], configure_args: [ "--openjdk-target=s390x-linux-gnu", "--with-freetype=bundled", "--disable-warnings-as-errors" ], }, "linux-riscv64": { target_os: "linux", target_cpu: "riscv64", build_cpu: "x64", dependencies: ["devkit", "gtest", "build_devkit"], configure_args: [ "--openjdk-target=riscv64-linux-gnu", "--with-freetype=bundled", "--disable-warnings-as-errors" ], }, }; // Add the base settings to all the main profiles common.main_profile_names.forEach(function (name) { profiles[name] = concatObjects(common.main_profile_base, profiles[name]); }); // Generate debug versions of all the main profiles common.main_profile_names.forEach(function (name) { var debugName = name + common.debug_suffix; profiles[debugName] = concatObjects(profiles[name], common.debug_profile_base); }); // Generate slowdebug versions of all the main profiles common.main_profile_names.forEach(function (name) { var debugName = name + common.slowdebug_suffix; profiles[debugName] = concatObjects(profiles[name], common.slowdebug_profile_base); }); // Generate optimized versions of all the main profiles common.main_profile_names.forEach(function (name) { var optName = name + common.optimized_suffix; profiles[optName] = concatObjects(profiles[name], common.optimized_profile_base); profiles[optName].default_make_targets = [ "hotspot" ]; }); // Generate testmake profiles for the main profile of each build host // platform. This profile only runs the makefile tests. // Ant is needed to run the idea project generator test. var testmakeBase = { dependencies: [ "ant" ], environment: { "ANT_HOME": input.get("ant", "home_path") } }; [ "linux-x64", "macosx-aarch64", "macosx-x64", "windows-x64", "linux-aarch64"] .forEach(function (name) { var maketestName = name + "-testmake"; profiles[maketestName] = concatObjects(profiles[name], testmakeBase); profiles[maketestName].default_make_targets = [ "test-make" ]; }); // Generate -gcov profiles [ "linux-aarch64", "linux-x64", "macosx-x64", "macosx-aarch64" ].forEach(function (name) { var gcovName = name + "-gcov"; profiles[gcovName] = clone(profiles[name]); profiles[gcovName].default_make_targets = ["product-bundles", "test-bundles"]; profiles[gcovName].configure_args = concat(profiles[gcovName].configure_args, ["--enable-native-coverage", "--disable-warnings-as-errors"]); }); // Profiles for building the zero jvm variant. These are used for verification. var zeroProfiles = { "linux-x64-zero": { target_os: "linux", target_cpu: "x64", dependencies: ["devkit", "gtest", "libffi"], configure_args: concat(common.configure_args_64bit, [ "--with-zlib=system", "--with-jvm-variants=zero", "--with-libffi=" + input.get("libffi", "home_path"), "--enable-libffi-bundling", ]) }, "linux-aarch64-zero": { target_os: "linux", target_cpu: "aarch64", dependencies: ["devkit", "gtest", "libffi"], configure_args: concat(common.configure_args_64bit, [ "--with-zlib=system", "--with-jvm-variants=zero", "--with-libffi=" + input.get("libffi", "home_path"), "--enable-libffi-bundling" ]) }, "linux-x86-zero": { target_os: "linux", target_cpu: "x86", build_cpu: "x64", dependencies: ["devkit", "gtest", "libffi"], configure_args: concat(common.configure_args_32bit, [ "--with-zlib=system", "--with-jvm-variants=zero", "--with-libffi=" + input.get("libffi", "home_path"), "--enable-libffi-bundling" ]) } } profiles = concatObjects(profiles, zeroProfiles); // Add the base settings to the zero profiles and generate debug profiles Object.keys(zeroProfiles).forEach(function (name) { var debugName = name + common.debug_suffix; profiles[name] = concatObjects(common.main_profile_base, profiles[name]); profiles[debugName] = concatObjects(profiles[name], common.debug_profile_base); }); // Define a profile with precompiled headers disabled. This is just used for // verification of this build configuration. var noPchProfiles = { "linux-x64-debug-nopch": { target_os: "linux", target_cpu: "x64", dependencies: ["devkit", "gtest"], configure_args: concat(common.configure_args_64bit, "--with-zlib=system", "--disable-precompiled-headers"), }, }; profiles = concatObjects(profiles, noPchProfiles); // Add base settings to noPch profiles Object.keys(noPchProfiles).forEach(function (name) { profiles[name] = concatObjects(common.main_profile_base, profiles[name]); profiles[name] = concatObjects(common.debug_profile_base, profiles[name]); // Override default make target with hotspot as that's the only part of // the build using precompiled headers. profiles[name].default_make_targets = ["hotspot"]; }); // Bootcycle profiles runs the build with itself as the boot jdk. This can // be done in two ways. Either using the builtin bootcycle target in the // build system. Or by supplying the main jdk build as bootjdk to configure. [ "linux-x64", "macosx-x64", "windows-x64", "linux-aarch64" ] .forEach(function (name) { var bootcycleName = name + "-bootcycle"; var bootcyclePrebuiltName = name + "-bootcycle-prebuilt"; // The base bootcycle profile just changes the default target // compared to the base profile profiles[bootcycleName] = clone(profiles[name]); profiles[bootcycleName].default_make_targets = [ "bootcycle-images" ]; // The prebuilt bootcycle variant modifies the boot jdk argument var bootcyclePrebuiltBase = { dependencies: [ name + ".jdk" ], configure_args: [ "--with-boot-jdk=" + input.get(name + ".jdk", "home_path"), ] } profiles[bootcyclePrebuiltName] = concatObjects(profiles[name], bootcyclePrebuiltBase); var bootJdkIndex = profiles[bootcyclePrebuiltName].dependencies.indexOf("boot_jdk"); delete profiles[bootcyclePrebuiltName].dependencies[bootJdkIndex]; profiles[bootcyclePrebuiltName].default_make_targets = [ "product-images" ]; }); // JCov profiles build JCov-instrumented JDK image based on images provided through dependencies. [ "linux-aarch64", "linux-x64", "macosx-x64", "macosx-aarch64", "windows-x64" ] .forEach(function (name) { var jcovName = name + "-jcov"; profiles[jcovName] = clone(common.main_profile_base); profiles[jcovName].target_os = profiles[name].target_os profiles[jcovName].target_cpu = profiles[name].target_cpu profiles[jcovName].default_make_targets = [ "jcov-bundles" ]; profiles[jcovName].dependencies = concat(profiles[jcovName].dependencies, [ name + ".jdk", "devkit" ]); profiles[jcovName].configure_args = concat(profiles[jcovName].configure_args, ["--with-jcov-input-jdk=" + input.get(name + ".jdk", "home_path")]); }); // Define artifacts for profiles var artifactData = { "linux-x64": { platform: "linux-x64", }, "linux-x86": { platform: "linux-x86", }, "macosx-x64": { platform: "macos-x64", jdk_subdir: "jdk-" + data.version + ".jdk/Contents/Home", }, "macosx-aarch64": { platform: "macos-aarch64", jdk_subdir: "jdk-" + data.version + ".jdk/Contents/Home", }, "windows-x64": { platform: "windows-x64", jdk_suffix: "zip", }, "windows-x86": { platform: "windows-x86", jdk_suffix: "zip", }, "windows-aarch64": { platform: "windows-aarch64", jdk_suffix: "zip", }, "linux-aarch64": { platform: "linux-aarch64", }, "linux-arm32": { platform: "linux-arm32", }, "linux-ppc64le": { platform: "linux-ppc64le", }, "linux-s390x": { platform: "linux-s390x", }, "linux-riscv64": { platform: "linux-riscv64", }, } // Generate common artifacts for all main profiles Object.keys(artifactData).forEach(function (name) { profiles[name] = concatObjects(profiles[name], common.main_profile_artifacts(artifactData[name])); }); // Generate common artifacts for all debug profiles Object.keys(artifactData).forEach(function (name) { var debugName = name + common.debug_suffix; profiles[debugName] = concatObjects(profiles[debugName], common.debug_profile_artifacts(artifactData[name])); }); // Define artifact just for linux-x64-zero, which is the only one we test on ["linux-x64"].forEach(function (name) { var o = artifactData[name] var pf = o.platform var jdk_subdir = (o.jdk_subdir != null ? o.jdk_subdir : "jdk-" + data.version); var jdk_suffix = (o.jdk_suffix != null ? o.jdk_suffix : "tar.gz"); var zeroName = name + "-zero"; profiles[zeroName].artifacts = { jdk: { local: "bundles/\\(jdk.*bin." + jdk_suffix + "\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-zero." + jdk_suffix, ], subdir: jdk_subdir, exploded: "images/jdk", }, test: { local: "bundles/\\(jdk.*bin-tests.tar.gz\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-zero-tests.tar.gz", ], exploded: "images/test" }, jdk_symbols: { local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-zero-symbols.tar.gz", ], subdir: jdk_subdir, exploded: "images/jdk" }, }; }); buildJdkDep = input.build_os + "-" + input.build_cpu + ".jdk"; docsProfiles = { "docs": { target_os: input.build_os, target_cpu: input.build_cpu, dependencies: [ "boot_jdk", "devkit", "graphviz", "pandoc", buildJdkDep, ], configure_args: concat( "--enable-full-docs", versionArgs(input, common), "--with-build-jdk=" + input.get(buildJdkDep, "home_path"), // Provide an explicit JDK for the docs-reference target to // mimic the running conditions of when it's run for real as // closely as possible. "--with-docs-reference-jdk=" + input.get(buildJdkDep, "home_path") ), default_make_targets: ["all-docs-bundles"], artifacts: { doc_api_spec: { local: "bundles/\\(jdk-" + data.version + ".*doc-api-spec.tar.gz\\)", remote: [ "bundles/common/jdk-" + data.version + "_doc-api-spec.tar.gz", "bundles/common/\\1" ], }, javase_doc_api_spec: { local: "bundles/\\(javase-" + data.version + ".*doc-api-spec.tar.gz\\)", remote: [ "bundles/common/javase-" + data.version + "_doc-api-spec.tar.gz", "bundles/common/\\1" ], }, reference_doc_api_spec: { local: "bundles/\\(jdk-reference-" + data.version + ".*doc-api-spec.tar.gz\\)", remote: [ "bundles/common/jdk-reference-" + data.version + "_doc-api-spec.tar.gz", "bundles/common/\\1" ], }, } } }; profiles = concatObjects(profiles, docsProfiles); // Generate open only profiles for all the main and debug profiles. // Rewrite artifact remote paths by adding "openjdk/GPL". common.main_profile_names.forEach(function (name) { var openName = name + common.open_suffix; profiles[openName] = concatObjects(profiles[name], common.open_profile_base); for (artifactName in profiles[openName].artifacts) { var artifact = profiles[openName].artifacts[artifactName]; artifact.remote = replaceAll( "bundles\/", "bundles/openjdk/GPL/", (artifact.remote != null ? artifact.remote : artifact.local)); } var debugName = name + common.debug_suffix; var openDebugName = name + common.open_suffix + common.debug_suffix; profiles[openDebugName] = concatObjects(profiles[debugName], common.open_profile_base); for (artifactName in profiles[openDebugName].artifacts) { var artifact = profiles[openDebugName].artifacts[artifactName]; artifact.remote = replaceAll( "bundles\/", "bundles/openjdk/GPL/", (artifact.remote != null ? artifact.remote : artifact.local)); } }); // For open profiles, the non-debug jdk bundles, need an "open" prefix on the // remote bundle names, forming the word "openjdk". See JDK-8188789. common.main_profile_names.forEach(function (name) { var openName = name + common.open_suffix; profiles[openName].artifacts["jdk"].remote = replaceAll( "\/jdk-", "/openjdk-", replaceAll("\/\\1", "/open\\1", profiles[openName].artifacts["jdk"].remote)); }); // Generate cmp-baseline profiles for each main profile and their // corresponding debug profile. This profile does a compare build run with no // changes to verify that the compare script has a clean baseline common.main_profile_names.forEach(function (name) { [ "", common.open_suffix ].forEach(function (suffix) { var cmpBaselineName = name + suffix + "-cmp-baseline"; profiles[cmpBaselineName] = clone(profiles[name + suffix]); // Only compare the images target. This should presumably be expanded // to include more build targets when possible. profiles[cmpBaselineName].default_make_targets = [ "images", "test-image" ]; if (name == "linux-x64") { profiles[cmpBaselineName].default_make_targets = concat(profiles[cmpBaselineName].default_make_targets, "docs"); } profiles[cmpBaselineName].make_args = [ "COMPARE_BUILD=CONF=" ]; profiles[cmpBaselineName].configure_args = concat( profiles[cmpBaselineName].configure_args, "--with-hotspot-build-time=n/a", "--disable-precompiled-headers"); // Do not inherit artifact definitions from base profile delete profiles[cmpBaselineName].artifacts; }); }); // Artifacts of JCov profiles [ "linux-aarch64", "linux-x64", "macosx-x64", "macosx-aarch64", "windows-x64" ] .forEach(function (name) { var o = artifactData[name] var jdk_subdir = "jdk-" + data.version; var jdk_suffix = (o.jdk_suffix != null ? o.jdk_suffix : "tar.gz"); var pf = o.platform var jcovName = name + "-jcov"; profiles[jcovName].artifacts = { jdk: { local: "bundles/\\(jdk-jcov.*bin." + jdk_suffix + "\\)", remote: [ "bundles/" + pf + "/jdk-jcov-" + data.version + "_" + pf + "_bin." + jdk_suffix ], subdir: jdk_subdir, exploded: "images/jdk-jcov" } }; }); // Artifacts of gcov (native-code-coverage) profiles [ "linux-aarch64", "linux-x64", "macosx-x64", "macosx-aarch64" ].forEach(function (name) { var o = artifactData[name] var pf = o.platform var jdk_subdir = (o.jdk_subdir != null ? o.jdk_subdir : "jdk-" + data.version); var jdk_suffix = (o.jdk_suffix != null ? o.jdk_suffix : "tar.gz"); var gcovName = name + "-gcov"; profiles[gcovName].artifacts = { jdk: { local: "bundles/\\(jdk.*bin." + jdk_suffix + "\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-gcov." + jdk_suffix, ], subdir: jdk_subdir, exploded: "images/jdk", }, test: { local: "bundles/\\(jdk.*bin-tests.tar.gz\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-gcov-tests.tar.gz", ], exploded: "images/test" }, jdk_symbols: { local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)", remote: [ "bundles/" + pf + "/jdk-" + data.version + "_" + pf + "_bin-gcov-symbols.tar.gz", ], subdir: jdk_subdir, exploded: "images/jdk" }, }; }); // Profiles used to run tests. var testOnlyProfiles = { "run-test": { target_os: input.build_os, target_cpu: input.build_cpu, dependencies: [ "jtreg", "gnumake", "boot_jdk", "devkit", "jib" ], labels: "test" } }; profiles = concatObjects(profiles, testOnlyProfiles); // Profiles used to run tests using Jib for internal dependencies. var testedProfile = input.testedProfile; if (testedProfile == null || testedProfile == "docs") { testedProfile = input.build_os + "-" + input.build_cpu; } var testedProfileJdk = testedProfile + ".jdk"; // Make it possible to use the test image from a different profile var testImageProfile; if (input.testImageProfile != null) { testImageProfile = input.testImageProfile; } else if (testedProfile.endsWith("-jcov")) { testImageProfile = testedProfile.substring(0, testedProfile.length - "-jcov".length); } else { testImageProfile = testedProfile; } var testedProfileTest = testImageProfile + ".test" var testOnlyMake = [ "test-prebuilt", "LOG_CMDLINES=true", "JTREG_VERBOSE=fail,error,time" ]; if (testedProfile.endsWith("-gcov")) { testOnlyMake = concat(testOnlyMake, "GCOV_ENABLED=true") } var testOnlyProfilesPrebuilt = { "run-test-prebuilt": { target_os: input.build_os, target_cpu: input.build_cpu, dependencies: [ "jtreg", "gnumake", "boot_jdk", "devkit", "jib", "jcov", testedProfileJdk, testedProfileTest, ], src: "src.conf", make_args: testOnlyMake, environment: { "BOOT_JDK": common.boot_jdk_home, "JT_HOME": input.get("jtreg", "home_path"), "JDK_IMAGE_DIR": input.get(testedProfileJdk, "home_path"), "TEST_IMAGE_DIR": input.get(testedProfileTest, "home_path"), "SYMBOLS_IMAGE_DIR": input.get(testedProfile + ".jdk_symbols", "home_path") }, labels: "test" } }; if (!testedProfile.endsWith("-jcov")) { testOnlyProfilesPrebuilt["run-test-prebuilt"]["dependencies"].push(testedProfile + ".jdk_symbols"); } var testOnlyProfilesPrebuiltDocs = { "run-test-prebuilt-docs": clone(testOnlyProfilesPrebuilt["run-test-prebuilt"]) }; testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].dependencies.push("docs.doc_api_spec", "tidy"); testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].environment["DOCS_JDK_IMAGE_DIR"] = input.get("docs.doc_api_spec", "install_path"); testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].environment["TIDY"] = input.get("tidy", "home_path") + "/bin/tidy"; testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].labels = "test-docs"; // If actually running the run-test-prebuilt profile, verify that the input // variable is valid and if so, add the appropriate target_* values from // the tested profile. Use testImageProfile value as backup. if (input.profile == "run-test-prebuilt" || input.profile == "run-test-prebuilt-docs") { if (profiles[testedProfile] == null && profiles[testImageProfile] == null) { error("testedProfile is not defined: " + testedProfile + " " + testImageProfile); } } function updateProfileTargets(profiles, testedProfile, testImageProfile, targetProfile, runTestProfile) { var profileToCheck = profiles[testedProfile] || profiles[testImageProfile]; if (profileToCheck != null) { targetProfile[runTestProfile]["target_os"] = profileToCheck["target_os"]; targetProfile[runTestProfile]["target_cpu"] = profileToCheck["target_cpu"]; } } updateProfileTargets(profiles, testedProfile, testImageProfile, testOnlyProfilesPrebuilt, "run-test-prebuilt"); updateProfileTargets(profiles, testedProfile, testImageProfile, testOnlyProfilesPrebuiltDocs, "run-test-prebuilt-docs"); profiles = concatObjects(profiles, testOnlyProfilesPrebuiltDocs); profiles = concatObjects(profiles, testOnlyProfilesPrebuilt); // On macosx add the devkit bin dir to the path in all the run-test profiles. // This gives us a guaranteed working version of lldb for the jtreg failure handler. if (input.build_os == "macosx") { macosxRunTestExtra = { dependencies: [ "lldb" ], environment_path: [ input.get("gnumake", "install_path") + "/bin", input.get("lldb", "install_path") + "/Xcode/Contents/Developer/usr/bin", ], }; profiles["run-test"] = concatObjects(profiles["run-test"], macosxRunTestExtra); profiles["run-test-prebuilt"] = concatObjects(profiles["run-test-prebuilt"], macosxRunTestExtra); } else if (input.build_os == "windows") { // On windows, add the devkit debugger to the path in all the run-test profiles // to make them available to the jtreg failure handler. var archDir = "x64"; if (input.build_arch == "aarch64") { archDir = "arm64" } windowsRunTestExtra = { environment_path: [ input.get("devkit", "install_path") + "/10/Debuggers/" + archDir ] } profiles["run-test"] = concatObjects(profiles["run-test"], windowsRunTestExtra); profiles["run-test-prebuilt"] = concatObjects(profiles["run-test-prebuilt"], windowsRunTestExtra); } // The profile run-test-prebuilt defines src.conf as the src bundle. When // running in Mach 5, this reduces the time it takes to populate the // considerably. But with just src.conf, we cannot actually run any tests, // so if running from a workspace with just src.conf in it, we need to also // get src.full as a dependency, and define the work_dir (where make gets // run) to be in the src.full install path. By running in the install path, // the same cached installation of the full src can be reused for multiple // test tasks. Care must however be taken not to pollute that work dir by // setting the appropriate make variables to control output directories. // // Use the existence of the top level README.md as indication of if this is // the full source or just src.conf. if (!new java.io.File(__DIR__, "../../README.md").exists()) { var runTestPrebuiltSrcFullExtra = { dependencies: "src.full", work_dir: input.get("src.full", "install_path"), } profiles["run-test-prebuilt"] = concatObjects(profiles["run-test-prebuilt"], runTestPrebuiltSrcFullExtra); profiles["run-test-prebuilt-docs"] = concatObjects(profiles["run-test-prebuilt-docs"], runTestPrebuiltSrcFullExtra); } // Generate the missing platform attributes profiles = generatePlatformAttributes(profiles); profiles = generateDefaultMakeTargetsConfigureArg(common, profiles); return profiles; }; /** * Generate the dependencies part of the configuration * * @param input External data to use for generating the configuration * @param common The common values * @returns {{}} Dependencies part of configuration */ var getJibProfilesDependencies = function (input, common) { var devkit_platform_revisions = { linux_x64: "gcc13.2.0-OL6.4+1.0", macosx: "Xcode14.3.1+1.0", windows_x64: "VS2022-17.6.5+1.0", linux_aarch64: "gcc13.2.0-OL7.6+1.0", linux_arm: "gcc8.2.0-Fedora27+1.0", linux_ppc64le: "gcc8.2.0-Fedora27+1.0", linux_s390x: "gcc8.2.0-Fedora27+1.0", linux_riscv64: "gcc11.3.0-Fedora_rawhide_68692+1.1" }; var devkit_platform = (input.target_cpu == "x86" ? input.target_os + "_x64" : input.target_platform); if (input.target_platform == "windows_aarch64") { devkit_platform = "windows_x64"; } else if (input.target_os == "macosx") { devkit_platform = "macosx"; } var devkit_cross_prefix = ""; if (!(input.target_os == "windows")) { if (input.build_platform != input.target_platform && input.build_platform != devkit_platform) { devkit_cross_prefix = input.build_platform + "-to-"; } } var boot_jdk_os = input.build_os; if (input.build_os == "macosx") { boot_jdk_os = "macos"; } var boot_jdk_platform = boot_jdk_os + "-" + input.build_cpu; var boot_jdk_ext = (input.build_os == "windows" ? ".zip" : ".tar.gz") // If running in WSL and building for Windows, it will look like Linux, // but we need a Windows boot JDK. if (isWsl(input) && input.target_os == "windows") { boot_jdk_platform = "windows-" + input.build_cpu; boot_jdk_ext = ".zip"; } var boot_jdk = { server: "jpg", product: "jdk", version: common.boot_jdk_version, build_number: common.boot_jdk_build_number, file: "bundles/" + boot_jdk_platform + "/jdk-" + common.boot_jdk_version + "_" + boot_jdk_platform + "_bin" + boot_jdk_ext, configure_args: "--with-boot-jdk=" + common.boot_jdk_home, environment_path: common.boot_jdk_home + "/bin" } var makeRevision = "4.0+1.0"; var makeBinSubDir = "/bin"; var makeModule = "gnumake-" + input.build_platform; if (input.build_os == "windows") { makeModule = "gnumake-" + input.build_osenv_platform; if (input.build_osenv == "cygwin") { var versionArray = input.build_osenv_version.split(/\./); var majorVer = parseInt(versionArray[0]); var minorVer = parseInt(versionArray[1]); if (majorVer > 3 || (majorVer == 3 && minorVer >= 3)) { makeRevision = "4.3+1.0"; } else { makeBinSubDir = "/cygwin/bin"; } } } var makeBinDir = input.get("gnumake", "install_path") + makeBinSubDir; var dependencies = { boot_jdk: boot_jdk, devkit: { organization: common.organization, ext: "tar.gz", module: "devkit-" + devkit_cross_prefix + devkit_platform, revision: devkit_platform_revisions[devkit_platform], environment: { "DEVKIT_HOME": input.get("devkit", "home_path"), } }, build_devkit: { organization: common.organization, ext: "tar.gz", module: "devkit-" + input.build_platform, revision: devkit_platform_revisions[input.build_platform], // Only set --with-build-devkit when cross compiling. configure_args: (input.build_cpu == input.target_cpu ? false : "--with-build-devkit=" + input.get("build_devkit", "home_path")) }, lldb: { organization: common.organization, ext: "tar.gz", module: "devkit-macosx" + (input.build_cpu == "x64" ? "_x64" : ""), revision: (input.build_cpu == "x64" ? "Xcode11.3.1-MacOSX10.15+1.2" : devkit_platform_revisions[devkit_platform]) }, jtreg: { server: "jpg", product: "jtreg", version: "7.4", build_number: "1", file: "bundles/jtreg-7.4+1.zip", environment_name: "JT_HOME", environment_path: input.get("jtreg", "home_path") + "/bin", configure_args: "--with-jtreg=" + input.get("jtreg", "home_path"), }, jmh: { organization: common.organization, ext: "tar.gz", revision: "1.37+1.0" }, jcov: { organization: common.organization, revision: "3.0-17-jdk-asm+1.0", ext: "zip", environment_name: "JCOV_HOME", }, gnumake: { organization: common.organization, ext: "tar.gz", revision: makeRevision, module: makeModule, configure_args: "MAKE=" + makeBinDir + "/make", environment: { "MAKE": makeBinDir + "/make" }, environment_path: makeBinDir }, autoconf: { organization: common.organization, ext: "tar.gz", revision: "2.69+1.0.1", module: (input.build_os == "windows" ? "autoconf-" + input.build_osenv_platform : "autoconf-" + input.build_platform), configure_args: "", environment_path: input.get("autoconf", "install_path") }, graphviz: { organization: common.organization, ext: "tar.gz", revision: "9.0.0+1.0", module: "graphviz-" + input.target_platform, configure_args: "DOT=" + input.get("graphviz", "install_path") + "/dot", environment_path: input.get("graphviz", "install_path") }, pandoc: { organization: common.organization, ext: "tar.gz", revision: "2.19.2+1.0", module: "pandoc-" + input.build_platform, configure_args: "PANDOC=" + input.get("pandoc", "install_path") + "/pandoc/pandoc", environment_path: input.get("pandoc", "install_path") + "/pandoc" }, // This adds java jib as a dependency for the test artifacts resolver jib: { organization: "com.oracle.java.jib", ext: "zip", classifier: "distribution", revision: "3.0-SNAPSHOT", environment_name: "JIB_HOME", environment_value: input.get("jib", "home_path") }, ant: { organization: common.organization, ext: "zip", revision: "1.7.1+1.0", configure_args: "", }, gtest: { organization: common.organization, ext: "tar.gz", revision: "1.14.0+1.0" }, libffi: { organization: common.organization, module: "libffi-" + input.target_platform, ext: "tar.gz", revision: "3.4.2+1.0" }, tidy: { organization: common.organization, ext: "tar.gz", revision: "5.9.20+1", environment_path: input.get("tidy", "home_path") + "/bin/tidy", configure_args: "TIDY=" + input.get("tidy", "home_path") + "/bin/tidy", module: "tidy-html-" + (input.target_os === "macosx" ? input.target_os : input.target_platform), }, }; return dependencies; }; /** * Generate the missing platform attributes for profiles * * @param profiles Profiles map to generate attributes on * @returns {{}} New profiles map with platform attributes fully filled in */ var generatePlatformAttributes = function (profiles) { var ret = concatObjects(profiles, {}); for (var profile in profiles) { if (ret[profile].build_os == null) { ret[profile].build_os = ret[profile].target_os; } if (ret[profile].build_cpu == null) { ret[profile].build_cpu = ret[profile].target_cpu; } ret[profile].target_platform = ret[profile].target_os + "_" + ret[profile].target_cpu; ret[profile].build_platform = ret[profile].build_os + "_" + ret[profile].build_cpu; } return ret; }; /** * The default_make_targets attribute on a profile is not a real Jib attribute. * This function rewrites that attribute into the corresponding configure arg. * Calling this function multiple times on the same profiles object is safe. * * @param common Common values * @param profiles Profiles map to rewrite profiles for * @returns {{}} New map of profiles with the make targets converted */ var generateDefaultMakeTargetsConfigureArg = function (common, profiles) { var ret = concatObjects(profiles, {}); for (var profile in ret) { if (ret[profile]["default_make_targets"] != null) { var targetsString = concat(ret[profile].default_make_targets).join(" "); // Iterate over all configure args and see if --with-default-make-target // is already there and change it, otherwise add it. var found = false; for (var i in ret[profile].configure_args) { var arg = ret[profile].configure_args[i]; if (arg != null && arg.startsWith("--with-default-make-target=")) { found = true; ret[profile].configure_args[i] = "--with-default-make-target=" + targetsString; } } if (!found) { ret[profile].configure_args = concat( ret[profile].configure_args, "--with-default-make-target=" + targetsString); } } } return ret; } var getBuildId = function (input) { if (input.build_id != null) { return input.build_id; } else { var topdir = new java.io.File(__DIR__, "../..").getCanonicalFile().getName(); var userName = java.lang.System.getProperty("user.name"); return userName + "." + topdir; } } /** * Deep clones an object tree. * * @param o Object to clone * @returns {{}} Clone of o */ var clone = function (o) { return JSON.parse(JSON.stringify(o)); }; /** * Concatenates all arguments into a new array * * @returns {Array.} New array containing all arguments */ var concat = function () { return Array.prototype.concat.apply([], arguments); }; /** * Takes a String or Array of Strings and does a replace operation on each * of them. * * @param pattern Pattern to look for * @param replacement Replacement text to insert * @param a String or Array of Strings to replace * @returns {Array} Either a new array or a new string depending on the input */ var replaceAll = function (pattern, replacement, a) { // If a is an array if (Array === a.constructor) { var newA = []; for (var i in a) { newA.push(a[i].replace(pattern, replacement)); } return newA; } else { return a.replace(pattern, replacement); } }; /** * Deep concatenation of two objects. For each node encountered, merge * the contents with the corresponding node in the other object tree, * treating all strings as array elements. * * @param o1 Object to concatenate * @param o2 Object to concatenate * @returns {{}} New object tree containing the concatenation of o1 and o2 */ var concatObjects = function (o1, o2) { if (o1 == null) { return clone(o2); } if (o2 == null) { return clone(o1); } var ret = {}; for (var a in o1) { if (o2[a] == null) { ret[a] = clone(o1[a]); } } for (var a in o2) { if (o1[a] == null) { ret[a] = clone(o2[a]); } else { if (typeof o1[a] == 'string') { ret[a] = clone([o1[a]].concat(o2[a])); } else if (Array.isArray(o1[a])) { ret[a] = clone(o1[a].concat(o2[a])); } else if (typeof o1[a] == 'object') { ret[a] = concatObjects(o1[a], o2[a]); } } } return ret; }; /** * Constructs the numeric version string from reading the * make/conf/version-numbers.conf file and removing all trailing ".0". * * @param feature Override feature version * @param interim Override interim version * @param update Override update version * @param patch Override patch version * @returns {String} The numeric version string */ var getVersion = function (feature, interim, update, patch, extra1, extra2, extra3) { var version_numbers = getVersionNumbers(); var version = (feature != null ? feature : version_numbers.get("DEFAULT_VERSION_FEATURE")) + "." + (interim != null ? interim : version_numbers.get("DEFAULT_VERSION_INTERIM")) + "." + (update != null ? update : version_numbers.get("DEFAULT_VERSION_UPDATE")) + "." + (patch != null ? patch : version_numbers.get("DEFAULT_VERSION_PATCH")) + "." + (extra1 != null ? extra1 : version_numbers.get("DEFAULT_VERSION_EXTRA1")) + "." + (extra2 != null ? extra2 : version_numbers.get("DEFAULT_VERSION_EXTRA2")) + "." + (extra3 != null ? extra3 : version_numbers.get("DEFAULT_VERSION_EXTRA3")); while (version.match(".*\\.0$")) { version = version.substring(0, version.length - 2); } return version; }; /** * Constructs the common version configure args based on build type and * other version inputs */ var versionArgs = function(input, common) { var args = []; if (common.build_number != 0) { args = concat(args, "--with-version-build=" + common.build_number); } if (input.build_type == "promoted") { args = concat(args, "--with-version-pre=" + version_numbers.get("DEFAULT_PROMOTED_VERSION_PRE"), "--without-version-opt"); } else if (input.build_type == "ci") { var ciBuildNumber = input.build_id_data.ciBuildNumber; var preString = input.build_id_data.projectName; if (preString == "jdk") { preString = version_numbers.get("DEFAULT_PROMOTED_VERSION_PRE"); } args = concat(args, "--with-version-pre=" + preString, "--with-version-opt=" + ciBuildNumber); if (input.target_os == "macosx") { args = concat(args, "--with-macosx-bundle-build-version=" + common.build_number + "." + ciBuildNumber); } } else { args = concat(args, "--with-version-opt=" + common.build_id); } var sourceDate if (input.build_id_data && input.build_id_data.creationTime) { sourceDate = Math.floor(Date.parse(input.build_id_data.creationTime)/1000); } else { sourceDate = "current"; } args = concat(args, "--with-source-date=" + sourceDate); return args; } // Properties representation of the make/conf/version-numbers.conf file. Lazily // initiated by the function below. var version_numbers; /** * Read the make/conf/version-numbers.conf file into a Properties object. * * @returns {java.utilProperties} */ var getVersionNumbers = function () { // Read version information from make/conf/version-numbers.conf if (version_numbers == null) { version_numbers = new java.util.Properties(); var stream = new java.io.FileInputStream(__DIR__ + "/version-numbers.conf"); version_numbers.load(stream); stream.close(); } return version_numbers; } /** * Returns true if running in Windows Subsystem for Linux. Jib does not yet * detect wsl as osenv, so fall back on linux with version containing Microsoft. */ var isWsl = function (input) { return ( input.build_osenv == "wsl" || (input.build_os == "linux" && java.lang.System.getProperty("os.version").toLowerCase().contains("microsoft"))); } var error = function (s) { java.lang.System.err.println("[ERROR] " + s); exit(1); };