#!/usr/bin/env node import * as path from 'node:path'; import * as fs from 'node:fs'; import { info, err, run, createDir, getScriptsDir } from './lib/util.mjs'; import { parseOptions, Enum, Architectures } from './lib/options.mjs'; // CMake Options const cmakeArgPrefix = '-D'; const cmakeArgSeparator = '='; const cmakeOptions = new Map(); function parseCMakeOption(arg) { if (arg === null) { // Usage Text return `${cmakeArgPrefix}var${cmakeArgSeparator}value...`; } else if (arg.startsWith(cmakeArgPrefix)) { // Pass Build Option To CMake let parsedArg = arg.substring(cmakeArgPrefix.length); const parts = parsedArg.split(cmakeArgSeparator); if (parts.length !== 2) { err('Unable To Parse Build Option: ' + arg); } const name = parts[0]; const value = parts[1]; if (!/^[a-zA-Z_]+$/.test(name) || name.length === 0) { err('Invalid Build Option Name: ' + name); } cmakeOptions.set(name, value); return true; } else { // Unknown Option return false; } } // Options const PackageTypes = new Enum([ 'None', 'AppImage', 'Flatpak' ]); const options = parseOptions([ ['packageType', PackageTypes], ['architecture', Architectures] ], [ 'clean', 'install', 'debug' ], parseCMakeOption); // Check Options if (options.packageType === PackageTypes.Flatpak && options.architecture !== Architectures.Host) { err('Flatpak Builds Do Not Support Custom Toolchains'); } if (options.packageType === PackageTypes.AppImage && options.install) { err('AppImages Cannot Be Installed'); } // Folders const __dirname = getScriptsDir(); const root = path.join(__dirname, '..'); let build = path.join(root, 'build'); let out = path.join(root, 'out'); // Update Build Directory function specializeDir(dir) { // Use Unique Folder For Build Type return path.join(dir, options.packageType.name, options.architecture.name); } build = specializeDir(build); // Update Output Directory const useOutRoot = options.packageType === PackageTypes.AppImage; if (!useOutRoot) { out = specializeDir(out); } // Print Directories function printDir(name, dir) { info(name + ' Directory: ' + dir); } printDir('Build', build); printDir('Output', out); // Configure CMake Options function setupPackageTypeOption(type) { cmakeOptions.set(`MCPI_IS_${type.name.toUpperCase()}_BUILD`, options.packageType === type ? 'ON' : 'OFF'); } setupPackageTypeOption(PackageTypes.AppImage); setupPackageTypeOption(PackageTypes.Flatpak); const toolchainOption = 'CMAKE_TOOLCHAIN_FILE'; if (options.architecture !== Architectures.Host) { cmakeOptions.set(toolchainOption, path.join(root, 'cmake', 'toolchain', options.architecture.name + '-toolchain.cmake')); } else { cmakeOptions.delete(toolchainOption); } // Make Build Directory createDir(build, options.clean); if (!options.install) { createDir(out, !useOutRoot); } // Run CMake const configure = ['cmake', '-GNinja Multi-Config']; cmakeOptions.forEach((value, key) => { configure.push(cmakeArgPrefix + key + cmakeArgSeparator + value); }); configure.push('-S', root, '-B', build); run(configure); // Build const configArg = ['--config', options.debug ? 'Debug' : 'Release']; run(['cmake', '--build', build, ...configArg]); // Package if (options.packageType !== PackageTypes.AppImage) { if (!options.install) { process.env.DESTDIR = out; } run(['cmake', '--install', build, ...configArg]); } else { run(['cmake', '--build', build, '--target', 'package', ...configArg]); // Copy Generated Files const files = fs.readdirSync(build); for (const file of files) { if (file.includes('.AppImage')) { info('Copying: ' + file); const src = path.join(build, file); const dst = path.join(out, file); fs.copyFileSync(src, dst); } } }