import path from "path"; import { GeneralVariable, LLVMVariable, command, variable } from "../commands/cmake.js"; import { PackagePlatform, PackageTask } from "./build.js"; import { promisifySpawn } from "../cli.js"; import os from "os"; import { SpawnOptions, spawn } from "child_process"; export interface LLVMPackageOverrides { cmakeDefinitionOverrides?: { llvm?: Object, libpgmath?: Object, cflang?: Object, }; spawnOverrides?: (old: SpawnOptions) => SpawnOptions, } /** * Make sysroot options suitable for LLVM build. */ export function llvmBuildSysroot(prefix: string): LLVMPackageOverrides { return { cmakeDefinitionOverrides: { llvm: { CMAKE_C_COMPILER: path.resolve(prefix, 'usr', 'bin', 'gcc'), CMAKE_CXX_COMPILER: path.resolve(prefix, 'usr', 'bin', 'g++'), CMAKE_SYSROOT: prefix, }, libpgmath: { CMAKE_SYSROOT: prefix, }, cflang: { CMAKE_SYSROOT: prefix, }, }, spawnOverrides: o => ({ ...o, env: { ...o.env, LD_LIBRARY_PATH: [ path.resolve(prefix, 'lib'), path.resolve(prefix, 'usr', 'lib'), ].join(':') } }), }; } export interface LLVMPackageOptions { src: string; installPrefix: string; /** * Build directories suitable for these three packages. */ buildDir: (packageName: 'llvm' | 'libpgmath' | 'cflang') => string, platform: PackagePlatform; enableLibpgmathSIMD: boolean; }; export function llvmPackages({ src, installPrefix, platform, buildDir, cmakeDefinitionOverrides, spawnOverrides, enableLibpgmathSIMD = false, }: LLVMPackageOptions & LLVMPackageOverrides): PackageTask[] { const rm = "rm"; const cmake = "cmake"; const llvmVar: LLVMVariable = { LLVM_ENABLE_PROJECTS: ["clang", "clang-tools-extra", "lld", "openmp"], LLVM_TARGETS_TO_BUILD: ["Sw64"], LLVM_ENABLE_CLASSIC_FLANG: true, LIBOMP_ARCH: "Sw64", LIBOMP_USE_ITT_NOTIFY: false, }; const general: GeneralVariable = { CMAKE_BUILD_TYPE: "Release", CMAKE_INSTALL_PREFIX: installPrefix, }; const env = { ...process.env, MAKEFLAGS: ["-j", os.cpus().length].join(" "), }; const spawnOptions: SpawnOptions = (spawnOverrides || (o => o))({ stdio: "inherit", env, cwd: src, }); const mkBuildPhase = (build: string) => (async () => { await promisifySpawn(spawn(cmake, ["--build", build], spawnOptions)); }); const mkInstallPhase = (build: string) => (async () => { await promisifySpawn(spawn(cmake, ["--build", build, "--target", "install"], spawnOptions)); }); function mkLLVMPackage(): PackageTask { const build = buildDir('llvm'); return { name: "llvm", platform, configurePhase: async () => { // Configure await promisifySpawn(spawn(cmake, command({ definitions: variable({ ...llvmVar, ...general, ...cmakeDefinitionOverrides?.llvm || {}, }), generator: "Ninja", // LLVM cmake root is under /llvm directory pathToSource: path.join(src, "llvm"), pathToBuild: build, }), spawnOptions)); }, buildPhase: mkBuildPhase(build), installPhase: mkInstallPhase(build), }; } function mkLibpgmathPackage(): PackageTask { const build = buildDir('libpgmath'); return { name: "libpgmath", configurePhase: async () => { await promisifySpawn(spawn(rm, ["-rf", build], spawnOptions)); // Flags shared between C and C++ compiler. const cxFlags = ["-mlong-double-64"]; if (enableLibpgmathSIMD) { cxFlags.push("-msimd"); } // Configure libpgmath. await promisifySpawn(spawn(cmake, command({ definitions: variable({ ...general, ...{ CMAKE_C_FLAGS: cxFlags.join(" "), CMAKE_CXX_FLAGS: cxFlags.join(" "), CMAKE_C_COMPILER: path.join(installPrefix, "bin", "clang"), CMAKE_CXX_COMPILER: path.join(installPrefix, "bin", "clang++"), } as GeneralVariable, ...cmakeDefinitionOverrides?.libpgmath || {}, }), generator: "Ninja", pathToSource: path.join(src, "cflang", "runtime", "libpgmath"), pathToBuild: build, }), spawnOptions)); }, buildPhase: mkBuildPhase(build), installPhase: mkInstallPhase(build), }; } function mkCflangPackage(): PackageTask { const build = buildDir('cflang'); return { name: "cflang", configurePhase: async () => { await promisifySpawn(spawn(rm, ["-rf", build], spawnOptions)); // Configure cflang. await promisifySpawn(spawn(cmake, command({ definitions: variable({ ...general, ...{ CMAKE_C_COMPILER: path.join(installPrefix, "bin", "clang"), CMAKE_CXX_COMPILER: path.join(installPrefix, "bin", "clang++"), CMAKE_Fortran_COMPILER: path.join(installPrefix, "bin", "flang"), CMAKE_Fortran_COMPILER_ID: "Flang", } as GeneralVariable, // Flang specific variables. FLANG_INCLUDE_DOCS: true, FLANG_LLVM_EXTENSIONS: true, WITH_WERROR: false, LLVM_CONFIG: path.join(installPrefix, "bin", "llvm-config"), ...cmakeDefinitionOverrides?.cflang || {}, }), generator: "Unix Makefiles", pathToSource: path.join(src, "cflang"), pathToBuild: build, }), spawnOptions)); }, buildPhase: mkBuildPhase(build), installPhase: mkInstallPhase(build), }; } return [mkLLVMPackage(), mkLibpgmathPackage(), mkCflangPackage()]; }