UNPKG

rescript

Version:
242 lines (218 loc) 6.99 kB
//@ts-check // For Windows, we distribute a prebuilt bsc.exe // To build on windows, we still need figure out constructing config.ml // from existing compiler // For other OSes, we detect // if there is other compiler installed and the version matches, // we get the config.ml from existing OCaml compiler and build whole_compiler // Otherwise, we build the compiler shipped with Buckle and use the // old compiler.ml // This will be run in npm postinstall, don't use too fancy features here var child_process = require("child_process"); var fs = require("fs"); var path = require("path"); var root_dir = path.join(__dirname, ".."); var lib_dir = path.join(root_dir, "lib"); var jscomp_dir = path.join(root_dir, "jscomp"); var supported_os = ["darwin", "freebsd", "linux", "openbsd", "win32"]; if (supported_os.indexOf(process.platform) < 0) { throw new Error("Not supported platform" + process.platform); } var is_windows = process.platform === "win32"; var bsc_exe = require("./bin_path").bsc_exe; var ninja_bin_filename = process.platform === "win32" ? "ninja.exe" : "ninja"; var ninja_bin_output = require("./bin_path").ninja_exe; var force_compiler_rebuild = process.argv.includes("-force-compiler-rebuild"); var force_lib_rebuild = process.argv.includes("-force-lib-rebuild"); /** * Make sure `ninja_bin_output` exists * The installation of `ninja.exe` is re-entrant, since we always pre-check if it is already installed * This is less problematic since `ninja.exe` is very stable */ function provideNinja() { var vendor_ninja_version = "1.9.0.git"; var ninja_source_dir = path.join(root_dir, "vendor", "ninja"); function build_ninja() { console.log(`building ninja`); ensureExists(ninja_source_dir); if (fs.existsSync(path.join(root_dir, "vendor", "ninja.tar.gz"))) { // Build from source on installation of the npm package // for platforms where we don't provide a pre-built binary. console.log("Extracting ninja sources..."); child_process.execSync(`tar xzf ../ninja.tar.gz`, { cwd: ninja_source_dir, stdio: [0, 1, 2], }); console.log("No prebuilt Ninja, building Ninja now"); var build_ninja_command = "python3 ./configure.py --bootstrap"; child_process.execSync(build_ninja_command, { cwd: ninja_source_dir, stdio: [0, 1, 2], }); fs.copyFileSync( path.join(ninja_source_dir, ninja_bin_filename), ninja_bin_output ); } else { // Build from source for "npm install" in local dev. require("../scripts/buildNinjaBinary"); fs.copyFileSync( path.join(root_dir, "ninja", ninja_bin_filename), ninja_bin_output ); } console.log("ninja binary is ready: ", ninja_bin_output); } // sanity check to make sure the binary actually runs. Used for Linux. Too many variants /** * * @param {string} binary_path */ function test_ninja_compatible(binary_path) { var version; try { version = child_process .execSync(JSON.stringify(binary_path) + " --version", { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"], // execSync outputs to stdout even if we catch the error. Silent it here }) .trim(); } catch (e) { console.log("ninja not compatible?", String(e)); return false; } return version === vendor_ninja_version; } if ( process.env.NINJA_FORCE_REBUILD === undefined && fs.existsSync(ninja_bin_output) && test_ninja_compatible(ninja_bin_output) ) { console.log( "ninja binary is already cached and installed: ", ninja_bin_output ); return; } build_ninja(); } /** * * @param {string} dir * TODO: `mkdirSync` may fail */ function ensureExists(dir) { if (!fs.existsSync(dir)) { fs.mkdirSync(dir); } } /** * @returns {string|undefined} */ function checkPrebuiltBscCompiler() { if (process.env.RESCRIPT_FORCE_REBUILD || force_compiler_rebuild) { return; } try { var version = String(child_process.execFileSync(bsc_exe, ["-v"])); var myOCamlVersion = version.substr( version.indexOf(":") + 1, version.lastIndexOf(" ") - version.indexOf(":") - 1 ); console.log("checkoutput:", version, "ocaml version", myOCamlVersion); console.log("Prebuilt compiler works good"); return myOCamlVersion; } catch (e) { console.log("No working prebuilt ReScript compiler"); if (is_windows) { throw new Error("no prebuilt bsc compiler on windows"); } return; } } /** * * @param {string} stdlib */ function buildLibs(stdlib) { ensureExists(lib_dir); ensureExists(path.join(lib_dir, "js")); ensureExists(path.join(lib_dir, "es6")); process.env.NINJA_IGNORE_GENERATOR = "true"; var releaseNinja = ` bsc = ${bsc_exe} stdlib = ${stdlib} subninja runtime/release.ninja subninja others/release.ninja subninja $stdlib/release.ninja ${process.env.RESCRIPT_FORCE_REBUILD ? "subninja test/build.ninja\n" : "\n"} o all: phony runtime others $stdlib `; var filePath = path.join(jscomp_dir, "release.ninja"); fs.writeFileSync(filePath, releaseNinja, "ascii"); var cleanArgs = ["-f", "release.ninja", "-t", "clean"]; child_process.execFileSync(ninja_bin_output, cleanArgs, { cwd: jscomp_dir, stdio: [0, 1, 2], shell: false, }); var buildArgs = ["-f", "release.ninja", "--verbose", "-k", "1"]; child_process.execFileSync(ninja_bin_output, buildArgs, { cwd: jscomp_dir, stdio: [0, 1, 2], shell: false, }); fs.unlinkSync(filePath); console.log("Build finished"); } /** * @returns {string} */ function provideCompiler() { var myVersion = checkPrebuiltBscCompiler(); if (myVersion !== undefined) { return myVersion; } else { var ocamlopt = "ocamlopt.opt"; myVersion = "4.06.1"; if (!require("./buildocaml.js").checkEnvCompiler()) { // no compiler available var prefix = require("./buildocaml.js").build(true); ocamlopt = `${prefix}/bin/${ocamlopt}`; } // Note this ninja file only works under *nix due to the suffix // under windows require '.exe' var releaseNinja = require("./ninjaFactory.js").libNinja({ ocamlopt: ocamlopt, INCL: myVersion, isWin: is_windows, }); var filePath = path.join(lib_dir, "release.ninja"); fs.writeFileSync(filePath, releaseNinja, "ascii"); child_process.execFileSync( ninja_bin_output, ["-f", "release.ninja", "-t", "clean"], { cwd: lib_dir, stdio: [0, 1, 2], } ); child_process.execFileSync( ninja_bin_output, ["-f", "release.ninja", "-v"], { cwd: lib_dir, stdio: [0, 1, 2], } ); fs.unlinkSync(filePath); return myVersion; } } provideNinja(); provideCompiler(); var stdlib = "stdlib-406"; if (process.env.RESCRIPT_FORCE_REBUILD || force_lib_rebuild) { buildLibs(stdlib); require("./installUtils.js").install(); }