const fs = require("fs"); const path = require("path"); const os = require("os"); const cp = require("child_process"); const THIRD_PART_DIR = __dirname; const SOURCE_DIR = path.join(THIRD_PART_DIR, "_source"); const env = {}; function setEnv(key, value) { env[key] = value; } function rmEnv(key) { delete env[key]; } function appendEnv(key, value) { env[key] = env[key] ? `${env[key]}:${value}` : value; } function addPkgConfig(pathname) { appendEnv("PKG_CONFIG_PATH", pathname); } function addLibdir(dirname) { appendEnv("LD_LIBRARY_PATH", dirname); } /** * * @param {string} command * @param {string[]} args * @param {cp.SpawnSyncOptionsWithBufferEncoding} options */ function spawnSync(command, args, options) { return cp.spawnSync(command, args, { stdio: "inherit", ...options, env: { ...process.env, ...env, } }) } function pkgconfig(name, tag) { const args = [name]; if (tag.includes("l")) args.push("--libs"); if (tag.includes("i")) args.push("--cflags"); const res = spawnSync("pkg-config", args, { cwd: SOURCE_DIR, stdio: "pipe" }); assert(res.status == 0, `Failed to run pkg-config ${args}`); return res.stdout.toString().trim(); } function assert(val, msg) { if (!val) { console.error(msg); process.exit(1); } } function check(...paths) { return fs.existsSync(path.join(...paths)); } function wget(url, savename) { savename ??= path.basename(new URL(url).pathname); assert(0 == spawnSync("wget", [url, "-O", savename], { cwd: SOURCE_DIR }).status, "Failed to download from " + url); } function clone(repo, branch, dirname) { assert(0 == spawnSync("git", ["clone", repo, "-b", branch, dirname]).status, `Failed to clone ${repo}`); } function uncompress(filename) { if (filename.endsWith(".xz")) { assert(0 == spawnSync("xz", ["-f", "-d", filename], { cwd: SOURCE_DIR }).status, `Failed to uncompress ${filename}`); filename = filename.slice(0, -3); } if (filename.endsWith(".gz")) { assert(0 == spawnSync("gunzip", ["-f", filename], { cwd: SOURCE_DIR }).status, `Failed to uncompress ${filename}`); filename = filename.slice(0, -3); } if (filename.endsWith(".tar")) assert(0 == spawnSync("tar", ["-xvf", filename], { cwd: SOURCE_DIR }).status, `Failed to uncompress ${filename}`); if (filename.endsWith(".tgz")) assert(0 == spawnSync("tar", ["-xzvf", filename], { cwd: SOURCE_DIR }).status, `Failed to uncompress ${filename}`); } function configure(sourceDir, args) { const configureFile = path.join(sourceDir, "configure"); if (!fs.existsSync(configureFile)) { if (fs.existsSync(path.join(sourceDir, "configure.ac"))) assert(0 == spawnSync("autoconf", [], { cwd: sourceDir }).status, `Failed to configure ${sourceDir}`); } assert(0 == spawnSync(configureFile, [...args], { cwd: sourceDir }).status, `Failed to configure ${sourceDir}`); } function make(sourceDir) { assert(0 == spawnSync("make", ["-j", os.cpus().length.toString()], { cwd: sourceDir }).status, `Failed to make ${path.dirname(sourceDir)}`); assert(0 == spawnSync("make", ["install"], { cwd: sourceDir }).status, `Failed to make install ${path.dirname(sourceDir)}`); } function cmake(sourceDir, prefix, args) { assert(0 == spawnSync("cmake", [ "-B", path.join(sourceDir, "build"), sourceDir, `-DCMAKE_INSTALL_PREFIX=${prefix}`, `-DCMAKE_BUILD_TYPE=Release`, ...args, ], { cwd: sourceDir }).status, `Failed to cmake ${sourceDir}`); assert(0 == spawnSync("cmake", [ "--build", path.join(sourceDir, "build"), "--parallel", os.cpus().length.toString(), "--config", "Release", "--target", "install", ]).status, `Failed to make install ${path.dirname(sourceDir)}`); } function where(name) { if (os.platform() === "linux") { const out = spawnSync("whereis", ["-b", name], { stdio: "pipe" }).stdout.toString(); const bin = out.substring(out.indexOf(":") + 1).trim(); if (fs.existsSync(bin)) return bin; return null; } } //必要依赖 // if (os.platform() === "linux") { // if (where("apt-get")) { // assert(0 == spawnSync("apt-get", ["install", "-y", "m4", "libgnutls28-dev"]).status, "Failed to install dependencies"); // } // else if (where("pacman")) { // assert(0 == spawnSync("pacman", ["-S", "m4", "libgnutls-devel"]).status, "Failed to install dependencies") // } // } //libgme const LIBGME_SRC = path.join(SOURCE_DIR, "libgme-0.6.4"); const LIBGME_DIST = path.join(THIRD_PART_DIR, "libgme-0.6.4"); if (!check(LIBGME_SRC, "CMakeLists.txt")) clone("https://github.com/libgme/game-music-emu.git", "0.6.4", LIBGME_SRC); if (!check(LIBGME_DIST, "lib/libgme.a")) cmake(LIBGME_SRC, LIBGME_DIST, ["-DGME_BUILD_EXAMPLES=OFF"]); addPkgConfig(path.join(LIBGME_DIST, "lib/pkgconfig")); //libsndfile const LIBSNDFILE_SRC = path.join(SOURCE_DIR, "libsndfile-1.2.2"); const LIBSNDFILE_DIST = path.join(THIRD_PART_DIR, "libsndfile-1.2.2"); if (!check(LIBSNDFILE_SRC, "CMakeLists.txt")) clone("https://github.com/libsndfile/libsndfile.git", "1.2.2", LIBSNDFILE_SRC); if (!check(LIBSNDFILE_DIST, "lib/libsndfile.a")) cmake(LIBSNDFILE_SRC, LIBSNDFILE_DIST, []); addPkgConfig(path.join(LIBSNDFILE_DIST, "lib/pkgconfig")); //ladspa const LADSPA_SRC = path.join(SOURCE_DIR, "ladspa_sdk_1.17"); const LADSPA_DIST = path.join(THIRD_PART_DIR, "ladspa_sdk_1.17"); if (!check(LADSPA_SRC, "src/Makefile")) { wget("http://www.ladspa.org/download/ladspa_sdk_1.17.tgz"); uncompress("ladspa_sdk_1.17.tgz"); } if (!fs.existsSync(path.join(LADSPA_SRC, "src/Makefile.bak"))) fs.cpSync(path.join(LADSPA_SRC, "src/Makefile"), path.join(LADSPA_SRC, "src/Makefile.bak")); const makefile = fs.readFileSync(path.join(LADSPA_SRC, "src/Makefile.bak"), "utf8") .replace(/^(INSTALL_PLUGINS_DIR\s*=\s*)(.*)$/m, `$1${LADSPA_DIST}`) .replace(/^(INSTALL_INCLUDE_DIR\s*=\s*)(.*)$/m, `$1${LADSPA_DIST}/include`) .replace(/^(INSTALL_BINARY_DIR\s*=\s*)(.*)$/m, `$1${LADSPA_DIST}/bin`) .replace(/^(INCLUDES\s*=\s*.*)$/m, `$1 -I${path.join(LIBSNDFILE_DIST, "include")}`) .replace(/^(LIBRARIES\s*=\s*.*)$/m, `$1 -L${path.join(LIBSNDFILE_DIST, "lib")}`); fs.writeFileSync(path.join(LADSPA_SRC, "src/Makefile"), makefile); make(path.join(LADSPA_SRC, "src")); console.log(makefile) return // //GMP // const GMP_SRC = path.join(SOURCE_DIR, "gmp-6.3.0"); // const GMP_DIST = path.join(THIRD_PART_DIR, "gmp-6.3.0"); // if (!check(GMP_SRC, "configure")) { // wget("https://gmplib.org/download/gmp/gmp-6.3.0.tar.xz"); // uncompress("gmp-6.3.0.tar.xz"); // } // if (!check(GMP_DIST, "lib/libgmp.a")) { // configure(GMP_SRC, [`--prefix=${GMP_DIST}`, "--enable-cxx", "--enable-shared=no"]) // make(GMP_SRC); // } // addPkgConfig(path.join(GMP_DIST, "lib/pkgconfig")); // addLibdir(path.join(GMP_DIST, "lib")); // //nettle // const NETTLE_SRC = path.join(SOURCE_DIR, "nettle-3.10"); // const NETTLE_DIST = path.join(THIRD_PART_DIR, "nettle-3.10"); // if (!check(NETTLE_SRC, "configure")) { // wget("https://ftp.gnu.org/gnu/nettle/nettle-3.10.tar.gz"); // uncompress("nettle-3.10.tar.gz"); // } // if (!check(NETTLE_DIST, "lib/libnettle.a")) { // configure(NETTLE_SRC, [ // `--prefix=${NETTLE_DIST}`, // "--enable-public-key", // "--enable-mini-gmp", // `--libdir=${path.join(NETTLE_DIST, "lib")}` // ]); // make(NETTLE_SRC); // } // addPkgConfig(path.join(NETTLE_DIST, "lib/pkgconfig")); // //Libtasn1 // const LIBTASN1_SRC = path.join(SOURCE_DIR, "libtasn1-4.20.0"); // const LIBTASN1_DIST = path.join(THIRD_PART_DIR, "libtasn1-4.20.0"); // if (!check(LIBTASN1_SRC, "configure")) { // wget("https://ftp.gnu.org/gnu/libtasn1/libtasn1-4.20.0.tar.gz"); // uncompress("libtasn1-4.20.0.tar.gz"); // } // if (!check(LIBTASN1_DIST, "lib/libtasn1.a")) { // configure(LIBTASN1_SRC, [`--prefix=${LIBTASN1_DIST}`]); // make(LIBTASN1_SRC); // } // addPkgConfig(path.join(LIBTASN1_DIST, "lib/pkgconfig")); // //Libunistring // const LIBUNISTRING_SRC = path.join(SOURCE_DIR, "libunistring-1.3"); // const LIBUNISTRING_DIST = path.join(THIRD_PART_DIR, "libunistring-1.3"); // if (!check(LIBUNISTRING_SRC, "configure")) { // wget("https://ftp.gnu.org/gnu/libunistring/libunistring-1.3.tar.gz"); // uncompress("libunistring-1.3.tar.gz"); // } // if (!check(LIBUNISTRING_DIST, "lib/libunistring.a")) { // configure(LIBUNISTRING_SRC, [`--prefix=${LIBUNISTRING_DIST}`]); // make(LIBUNISTRING_SRC); // } // addPkgConfig(path.join(LIBUNISTRING_DIST, "lib/pkgconfig")); // const P11_KIT_SRC = path.join(SOURCE_DIR, "p11-kit-0.25.5"); // const P11_KIT_DIST = path.join(THIRD_PART_DIR, "p11-kit-0.25.5"); // if (!check(P11_KIT_SRC, "configure")) { // wget("https://github.com/p11-glue/p11-kit/releases/download/0.25.5/p11-kit-0.25.5.tar.xz"); // uncompress("p11-kit-0.25.5.tar.xz"); // } // configure(P11_KIT_SRC, [`--prefix=${P11_KIT_DIST}`]); // make(P11_KIT_SRC); // //https://github.com/p11-glue/p11-kit/releases/download/0.25.5/p11-kit-0.25.5.tar.xz // return; // // gnutls // const GNUTLS_SRC = path.join(SOURCE_DIR, "gnutls-3.7.11"); // const GNUTLS_DIST = path.join(THIRD_PART_DIR, "gnutls-3.7.11"); // if (!check(GNUTLS_SRC, "configure")) { // wget("https://www.gnupg.org/ftp/gcrypt/gnutls/v3.7/gnutls-3.7.11.tar.xz"); // uncompress("gnutls-3.7.11.tar.xz"); // } // if (!check(GNUTLS_DIST, "lib/libgnutls.a")) { // setEnv("GMP_LIBS", pkgconfig("gmp", "l")); // configure(GNUTLS_SRC, [ // `--prefix=${GNUTLS_DIST}`, "--with-included-unistring", // ]); // rmEnv("GMP_LIBS"); // make(GNUTLS_SRC); // } // addPkgConfig(path.join(GNUTLS_DIST, "lib/pkgconfig")); //FFmpeg const FFMPEG_SRC = path.join(SOURCE_DIR, "ffmpeg-7.1.1"); const FFMPEG_DIST = path.join(THIRD_PART_DIR, "ffmpeg-7.1.1"); if (!check(FFMPEG_SRC, "configure")) { wget("https://ffmpeg.org/releases/ffmpeg-7.1.1.tar.xz"); uncompress("ffmpeg-7.1.1.tar.xz"); } configure(FFMPEG_SRC, [ `--prefix=${FFMPEG_DIST}`, "--enable-static", "--enable-small", "--disable-x86asm", "--enable-gnutls", "--enable-libgme", "--enable-ladspa", ]);