diff --git a/commands.ts b/commands.ts deleted file mode 100644 index 0c90846..0000000 --- a/commands.ts +++ /dev/null @@ -1,147 +0,0 @@ -/** - * Command CLI generation - */ - - -/** - * Constructs a systemd-run command array. - * @param unit The systemd unit to run. - * @param workingDirectory The working directory for the systemd-run command. - * Defaults to the current working directory. - * @returns An array representing the systemd-run command. - */ -export function systemdRun(unit: string, workingDirectory: string = process.cwd()): string[] { - return [ - 'systemd-run', - '--user', - `--working-directory=${workingDirectory}`, - '--unit', - unit - ]; -} - -function undefList(opt: T | undefined, fn: (opt: T) => U) { - return opt === undefined ? [] : fn(opt) -} - -const optFlag = (flag: string, opt: string | undefined) => undefList(opt, opt => [flag, opt]) - -/** - * Generate a switch flag, like "--rebuild", "--nobuild" - */ -const optSwitch = (flag: string, opt: boolean | undefined) => undefList(opt, opt => opt ? [flag] : []) - - -export module SPECCommands { - - interface SPECOptions { - /** - * Config file, used for compiling flags, compiler versions, etc. - */ - config?: string - - /** - * SPEC workload scale for each benchmark - */ - workload?: "test" | "train" | "ref" - - /** - * Selected benchmarks - */ - benchmarks?: string[] - - buildType?: "nobuild" | "rebuild" | "plain", - } - - export function runcpuOptions(o: SPECOptions): string[] { - return [ - ...optFlag("-c", o.config), - ...optFlag("-i", o.workload), - ...undefList(o.buildType, opt => { - switch (opt) { - case "nobuild": - return ["--nobuild"] - case "rebuild": - return ["--rebuild"] - case "plain": - return [] - } - }), - ...undefList(o.benchmarks, bench => bench) - ] - } -} - -export module CompilerCommands { - - export interface GeneralOptions { - output?: string; - - outputKind?: "exe" | "object" | "assembly" | "preprocessed" - } - - export function generalCommand(options: GeneralOptions) { - return [ - ...optFlag("-o", options.output), - ...undefList(options.outputKind, (opt) => { - switch (opt) { - case "object": - return ["-c"] - case "exe": - return [] - case "assembly": - return ["-S"] - case "preprocessed": - return ["-E"] - } - }) - ] - } - - export interface PreprocessorOptions { - includeDirs?: string[]; - } - - export function preprocessorCommand(options: PreprocessorOptions) { - return [ - ...undefList(options.includeDirs, dirs => dirs.flatMap(name => ["-I", name])) - ] - } - - - /** - * CLI options used for llvm-extract executable. - */ - export interface ExtractOptions { - /** - * Functions to extract. - */ - func?: string[]; - - /** - * Basic block specifiers. - */ - bb?: string[]; - - output?: string; - - /** - * Input file name. If unspecified, llvm-extract reads from stdin - */ - input?: string; - - asm?: boolean; - } - - export function extractCommand(options: ExtractOptions): string[] { - return [ - ...undefList(options.func, func => func.flatMap(name => ["--func", name])), - ...undefList(options.bb, bb => bb.flatMap(name => ["--bb", name])), - ...optFlag("-o", options.output), - ...optSwitch("-S", options.asm), - ...undefList(options.input, input => [input]) - ]; - } - - -} diff --git a/commands/cmake.ts b/commands/cmake.ts new file mode 100644 index 0000000..e494410 --- /dev/null +++ b/commands/cmake.ts @@ -0,0 +1,127 @@ +import { optFlag, undefList } from "./common" + +export type CMakeDefinition = { + name: string, + value: string, + type?: CMakeVariableType +} + +export type CMakeVariableType = "BOOL" | "FILEPATH" | "PATH" | "STRING" | "INTERNAL" + +/** + * General CMake variables. + */ +export interface GeneralVariable { + CMAKE_BUILD_TYPE?: "Debug" | "Release" | "RelWithDebInfo" | "MinSizeRel" + BUILD_SHARED_LIBS?: boolean, + CMAKE_INSTALL_PREFIX?: string, + CMAKE_SYSROOT?: string, + CMAKE_C_COMPILER?: string, + CMAKE_CXX_COMPILER?: string, +} + +/** + * CMake variables suitable for LLVM project. + */ +export interface LLVMVariable { + LLVM_TARGETS_TO_BUILD?: string[] + LLVM_ENABLE_CLASSIC_FLANG?: boolean, + LLVM_ENABLE_PROJECTS?: ("clang" | "openmp" | "lld" | "clang-tools-extra")[] + LIBOMP_ARCH?: "Sw64" + LIBOMP_USE_ITT_NOTIFY?: boolean + LIBOMP_ENABLE_SHARED?: boolean + OPENMP_ENABLE_LIBOMPTARGET?: boolean +} + +export interface CFlangCMakeVariable { + FLANG_INCLUDE_DIRS?: boolean + FLANG_LLVM_EXTENSIONS?: boolean + WITH_WERROR?: boolean + LLVM_CONFIG?: string +} + +/** + * Generate cmake definitions, take care of funny cmake string lists. + * + * @param object A set of cmake variables to generate + * @returns A list of cmake definitions, could be passed to CLI + */ +export function variable(object: Object): CMakeDefinition[] { + return Object.entries(object).map(([k, v]) => { + if (typeof v === "boolean") { + return { + name: k, + value: v ? "ON" : "OFF", + type: "BOOL" + } + } else if (typeof v === "object" && Array.isArray(v)) { + return { + name: k, + value: v.join(";"), + type: "STRING" + } + } else { + return { + name: k, + value: v, + type: "STRING" + } + } + } + ) +} + + +/** + * Options for "Generate a Project Buildsystem" + * @see https://cmake.org/cmake/help/latest/manual/cmake.1.html#generate-a-project-buildsystem + */ +export interface CMakeGenerateOptions { + pathToBuild?: string + pathToSource?: string + + /** + * Pre-load a script to populate the cache. + * When CMake is first run in an empty build tree, it creates a + * CMakeCache.txt file and populates it with customizable settings for the project. + * This option may be used to specify a file from which to load cache entries + * before the first pass through the project's CMake listfiles. + * The loaded entries take priority over the project's default values. + * The given file should be a CMake script containing set() commands that use the CACHE option, + * not a cache-format file. + */ + preloadCache?: string + + + definitions?: CMakeDefinition[] + + /** + * Specify a build system generator. + * + * CMake may support multiple native build systems on certain platforms. + * A generator is responsible for generating a particular build system. + * Possible generator names are specified in the [cmake-generators(7)](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#manual:cmake-generators(7)) manual. + */ + generator?: "Unix Makefiles" | "Ninja" + + /** + * Specify the cross compiling toolchain file, equivalent to setting CMAKE_TOOLCHAIN_FILE variable. + * Relative paths are interpreted as relative to the build directory, + * and if not found, relative to the source directory. + * + * New in version 3.21. + */ + toolchain?: string +} + +export function command(o: CMakeGenerateOptions): string[] { + return [ + ...optFlag("-G", o.generator), + ...undefList(o.definitions, defs => defs.flatMap(def => [ + "-D", + `${def.name}${def.type ? `:${def.type}` : ""}=${def.value}` + ])), + ...optFlag("-B", o.pathToBuild), + ...optFlag("-S", o.pathToSource), + ] +} diff --git a/commands/common.ts b/commands/common.ts new file mode 100644 index 0000000..34e5195 --- /dev/null +++ b/commands/common.ts @@ -0,0 +1,10 @@ +export function undefList(opt: T | undefined, fn: (opt: T) => U) { + return opt === undefined ? [] : fn(opt) +} + +export const optFlag = (flag: string, opt: string | undefined) => undefList(opt, opt => [flag, opt]) + +/** + * Generate a switch flag, like "--rebuild", "--nobuild" + */ +export const optSwitch = (flag: string, opt: boolean | undefined) => undefList(opt, opt => opt ? [flag] : []) diff --git a/commands/compiler.ts b/commands/compiler.ts new file mode 100644 index 0000000..63aa039 --- /dev/null +++ b/commands/compiler.ts @@ -0,0 +1,70 @@ +import { optFlag, optSwitch, undefList } from "./common"; + +export interface GeneralOptions { + output?: string; + + outputKind?: "exe" | "object" | "assembly" | "preprocessed" +} + +export function generalCommand(options: GeneralOptions) { + return [ + ...optFlag("-o", options.output), + ...undefList(options.outputKind, (opt) => { + switch (opt) { + case "object": + return ["-c"] + case "exe": + return [] + case "assembly": + return ["-S"] + case "preprocessed": + return ["-E"] + } + }) + ] +} + +export interface PreprocessorOptions { + includeDirs?: string[]; +} + +export function preprocessorCommand(options: PreprocessorOptions) { + return [ + ...undefList(options.includeDirs, dirs => dirs.flatMap(name => ["-I", name])) + ] +} + + +/** +* CLI options used for llvm-extract executable. +*/ +export interface ExtractOptions { + /** + * Functions to extract. + */ + func?: string[]; + + /** + * Basic block specifiers. + */ + bb?: string[]; + + output?: string; + + /** + * Input file name. If unspecified, llvm-extract reads from stdin + */ + input?: string; + + asm?: boolean; +} + +export function extractCommand(options: ExtractOptions): string[] { + return [ + ...undefList(options.func, func => func.flatMap(name => ["--func", name])), + ...undefList(options.bb, bb => bb.flatMap(name => ["--bb", name])), + ...optFlag("-o", options.output), + ...optSwitch("-S", options.asm), + ...undefList(options.input, input => [input]) + ]; +} diff --git a/commands/spec.ts b/commands/spec.ts new file mode 100644 index 0000000..9b83291 --- /dev/null +++ b/commands/spec.ts @@ -0,0 +1,38 @@ +import { optFlag, undefList } from "./common" + +interface SPECOptions { + /** + * Config file, used for compiling flags, compiler versions, etc. + */ + config?: string + + /** + * SPEC workload scale for each benchmark + */ + workload?: "test" | "train" | "ref" + + /** + * Selected benchmarks + */ + benchmarks?: string[] + + buildType?: "nobuild" | "rebuild" | "plain", +} + +export function runcpuOptions(o: SPECOptions): string[] { + return [ + ...optFlag("-c", o.config), + ...optFlag("-i", o.workload), + ...undefList(o.buildType, opt => { + switch (opt) { + case "nobuild": + return ["--nobuild"] + case "rebuild": + return ["--rebuild"] + case "plain": + return [] + } + }), + ...undefList(o.benchmarks, bench => bench) + ] +} diff --git a/compiler.ts b/compiler.ts index 4cc03ea..8c135a3 100644 --- a/compiler.ts +++ b/compiler.ts @@ -1,10 +1,9 @@ import child_process from "child_process" -import { PlatformPath } from "path" import path from "path" // FIXME: these imports basically looks ugly. import { LLVM_EXTRACT, PREFIX, SYSROOT_PREFIX, FLANG } from "./environment"; -import { CompilerCommands } from "./commands"; +import { ExtractOptions, extractCommand } from "./commands/compiler"; /** @@ -36,10 +35,10 @@ export function functionList(module: string) { /** * Extract one function using llvm-extract */ -export async function extract(options: CompilerCommands.ExtractOptions) { +export async function extract(options: ExtractOptions) { let process = child_process.spawn( LLVM_EXTRACT, - CompilerCommands.extractCommand(options), + extractCommand(options), { stdio: "inherit" } ) const exitcode = await new Promise((resolve, reject) => { process.on('close', resolve) })