diff --git a/src/bin/build-llvm.ts b/src/bin/build-llvm.ts index 11737b9..57f17fa 100644 --- a/src/bin/build-llvm.ts +++ b/src/bin/build-llvm.ts @@ -5,8 +5,10 @@ import path from 'path'; import { buildPackage } from '../build/build.js'; import { randomUUID } from 'crypto'; import { arch } from 'os'; +import * as sunway from '../sunway.js'; +import chalk from 'chalk'; -const args = await yargs(hideBin(process.argv)) +const argv = await yargs(hideBin(process.argv)) .version("0.0.0") .option("src", { describe: "Source directory to llvm-project", @@ -21,20 +23,31 @@ const args = await yargs(hideBin(process.argv)) describe: "Install prefix", type: "string", }) - .option("msimd-math", { + .option("math-simd", { describe: "Add -msimd for libpgmath", type: "boolean", demandOption: true, }) + .option('mcpu', { + type: 'string', + description: '-mcpu option for compilers', + choices: ['8a', '6b', 'host'], + default: 'host', + }) .help() .parse(); -const src = path.resolve(args.src); -const build = args.build ?? path.resolve(src, "build"); -const prefix = args.prefix ?? path.resolve(src, "install", randomUUID()); +const src = path.resolve(argv.src); +const build = argv.build ?? path.resolve(src, "build"); +const prefix = argv.prefix ?? path.resolve(src, "install", randomUUID()); + +const cpuVariant = argv.mcpu === "host" ? sunway.getHostGeneration() : argv.platform as sunway.SunwayGeneration; + +console.log(`prefix: ${chalk.red(prefix)}`); +console.log(`mcpu: ${cpuVariant}`); const packages = llvmPackages({ - src: args.src, + src: argv.src, buildDir(packageName) { return path.join(build, packageName); }, @@ -44,7 +57,8 @@ const packages = llvmPackages({ buildPlatform: { arch: arch() }, hostPlatform: { arch: arch() }, }, - enableLibpgmathSIMD: args['msimd-math'] + mathSIMD: argv['math-simd'], + cpuVariant, }); for (const pkg of packages) { diff --git a/src/build/llvmPackages.ts b/src/build/llvmPackages.ts index 8ab4b94..670523c 100644 --- a/src/build/llvmPackages.ts +++ b/src/build/llvmPackages.ts @@ -1,9 +1,10 @@ import path from "path"; -import { GeneralVariable, LLVMVariable, command, variable } from "../commands/cmake.js"; +import { GeneralVariable, LLVMVariable, buildCompilerFlags, 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"; +import * as sunway from '../sunway.js'; export interface LLVMPackageOverrides { cmakeDefinitionOverrides?: { @@ -60,7 +61,9 @@ export interface LLVMPackageOptions { platform: PackagePlatform; - enableLibpgmathSIMD: boolean; + mathSIMD: boolean; + + cpuVariant: sunway.SunwayGeneration; }; export function llvmPackages({ @@ -70,7 +73,8 @@ export function llvmPackages({ buildDir, cmakeDefinitionOverrides, spawnOverrides, - enableLibpgmathSIMD = false, + mathSIMD, + cpuVariant, }: LLVMPackageOptions & LLVMPackageOverrides): PackageTask[] { const rm = "rm"; const cmake = "cmake"; @@ -107,6 +111,16 @@ export function llvmPackages({ await promisifySpawn(spawn(cmake, ["--build", build, "--target", "install"], spawnOptions)); }); + const mcpuFlag = sunway.mcpu(cpuVariant); + + // Shared flags for compiling libpgmath & cflang. + // The toolchain of these targets are clang. + const clangCXFlags = [ + "-Wno-sign-compare", + mcpuFlag, + ]; + + function mkLLVMPackage(): PackageTask { const build = buildDir('llvm'); return { @@ -139,18 +153,19 @@ export function llvmPackages({ await promisifySpawn(spawn(rm, ["-rf", build], spawnOptions)); // Flags shared between C and C++ compiler. - const cxFlags = ["-mlong-double-64"]; - if (enableLibpgmathSIMD) { - cxFlags.push("-msimd"); - } + const cxFlags = [ + ...clangCXFlags, + "-mlong-double-64", + ...mathSIMD ? ["-msimd"] : [], + ]; // Configure libpgmath. await promisifySpawn(spawn(cmake, command({ definitions: variable({ ...general, ...{ - CMAKE_C_FLAGS: cxFlags.join(" "), - CMAKE_CXX_FLAGS: cxFlags.join(" "), + CMAKE_C_FLAGS: buildCompilerFlags(cxFlags), + CMAKE_CXX_FLAGS: buildCompilerFlags(cxFlags), CMAKE_C_COMPILER: path.join(installPrefix, "bin", "clang"), CMAKE_CXX_COMPILER: path.join(installPrefix, "bin", "clang++"), } as GeneralVariable, @@ -172,12 +187,17 @@ export function llvmPackages({ name: "cflang", configurePhase: async () => { await promisifySpawn(spawn(rm, ["-rf", build], spawnOptions)); - + const cxFlags = [ + ...clangCXFlags, + ]; // Configure cflang. await promisifySpawn(spawn(cmake, command({ definitions: variable({ ...general, ...{ + CMAKE_C_FLAGS: buildCompilerFlags(cxFlags), + CMAKE_CXX_FLAGS: buildCompilerFlags(cxFlags), + CMAKE_Fortran_FLAGS: buildCompilerFlags([mcpuFlag]), CMAKE_C_COMPILER: path.join(installPrefix, "bin", "clang"), CMAKE_CXX_COMPILER: path.join(installPrefix, "bin", "clang++"), CMAKE_Fortran_COMPILER: path.join(installPrefix, "bin", "flang"), diff --git a/src/commands/cmake.ts b/src/commands/cmake.ts index 63db717..4117697 100644 --- a/src/commands/cmake.ts +++ b/src/commands/cmake.ts @@ -130,3 +130,27 @@ export function command(o: CMakeGenerateOptions): string[] { ...optFlag('-C', o.preloadCache), ]; } + + +/** + * Escapes a single C compiler flag argument to ensure CMake can parse it correctly. + * Handles spaces and double quotes by wrapping the argument in double quotes and escaping internal double quotes. + */ +function escapeCmakeFlag(arg: string): string { + // Escape internal double quotes as \" + let escaped = arg.replace(/"/g, '\\"'); + // If the argument contains spaces or originally has double quotes, wrap it in double quotes + if (escaped.includes(' ') || arg.includes('"')) { + escaped = `"${escaped}"`; + } + return escaped; +} + +/** + * Converts an array of strings into a single string suitable for CMAKE_C_FLAGS. + * @param flags The original array of compiler flags, e.g., ["-O2", "-DNAME=Hello World"] + * @returns The escaped string that can be directly passed to CMake + */ +export function buildCompilerFlags(flags: string[]): string { + return flags.map(escapeCmakeFlag).join(' '); +} \ No newline at end of file