Skip to content

编译器选项解析

option 模块提供主流 C/C++ 工具链的完整选项表解析,数据源自 LLVM 的选项定义。它可以解析、查询、重写和跨工具链转换编译器选项。

支持的选项表

选项表工具链
"clang"Clang/GCC 驱动选项
"nvcc"NVIDIA CUDA 编译器
"lld-elf"LLD 链接器 (ELF/Linux)
"lld-coff"LLD 链接器 (COFF/Windows)
"lld-macho"LLD 链接器 (Mach-O/macOS)
"lld-mingw"LLD 链接器 (MinGW)
"lld-wasm"LLD 链接器 (WebAssembly)
"llvm-lib"LLVM 库管理器
"llvm-dlltool"LLVM DLL 工具

收集解析结果

将参数数组中的所有选项解析为结构化数据:

js
import { option } from "catter";

const args = ["-std=c++20", "-O2", "-c", "main.cc", "-o", "main.o"];
const items = option.collect("clang", args);

if (typeof items === "string") {
  throw new Error(`Parse error: ${items}`);
}

for (const item of items) {
  const meta = option.info("clang", item);
  io.println(`${meta.prefixedKey} => ${item.values.join(", ")}`);
}

流式解析

使用回调而非收集方式进行解析:

js
import { option } from "catter";

option.parse("clang", args, (result) => {
  if (typeof result === "string") {
    io.println(`Error: ${result}`);
    return false; // 停止解析
  }
  io.println(`Option: ${result.key}, values: ${result.values}`);
  return true; // 继续
});

选项查询

获取已解析选项的元数据:

js
const items = option.collect("clang", ["-std=c++20"]);
if (Array.isArray(items)) {
  const info = option.info("clang", items[0]);
  io.println(info.prefixedKey); // "-std="
  io.println(info.kind);       // OptionKindClass.JoinedClass
  io.println(info.help);       // 来自 LLVM 选项表的帮助文本
}

渲染选项

将解析后的选项项转换回命令行字符串:

js
const str = option.stringify("clang", item);
io.println(str); // 例如 "-std=c++20"

别名解析

将别名选项转换为规范形式:

js
const items = option.collect("nvcc", ["-ofoo.o"]);
if (Array.isArray(items)) {
  option.convertToUnalias("nvcc", items[0]);
  io.println(items[0].key); // "--output-file"
}

注意:convertToUnalias() 会原地修改传入的 item 对象并返回,方便链式调用。

重写参数

替换或删除参数数组中的选项:

js
import { option } from "catter";

const rewritten = option.replace("clang", ["-Iold", "-O0", "main.cc"], (result) => {
  if (typeof result === "string") {
    throw new Error(result);
  }

  // 替换头文件搜索路径
  if (result.key === "-I") {
    return { ...result, values: ["new-include"] };
  }

  // 移除优化选项(返回字符串以替换该段)
  if (result.key === "-O") {
    return "-O2";
  }

  // 返回 undefined 保持不变
});

io.println(rewritten); // "-Inew-include -O2 main.cc"

回调可以返回:

返回值效果
undefined保持原始文本
OptionItem替换为渲染后的选项
string替换为该字符串
string[]替换为合并后的数组
booleantrue 继续,false 停止

跨选项表转换

将参数从一个选项表转换到另一个,仅保留在目标表中有效的选项:

js
import { option } from "catter";

const nvccArgs = ["--gpu-architecture=sm_70", "-std=c++17", "-O2"];
const clangArgs = option.table2table("nvcc", "clang", nvccArgs);

if (typeof clangArgs === "string") {
  throw new Error(clangArgs);
}

io.println(clangArgs.join(" ")); // 两个表中都有效的选项

该函数先用源表解析参数,将其拆分为逐选项的片段,然后用目标表重新解析每个片段。解析为 UnknownClass 或匹配排除 ID 的片段会被丢弃。

OptionItem 结构

每个解析后的选项表示为 OptionItem

字段类型描述
keystring选项键(如 "-std=""-c""-I"
valuesstring[]选项值数组
idnumber选项表中的数字 ID
unaliasnumber | undefined如果是别名,则为规范选项的 ID
indexnumber在原始 args 中的位置

OptionInfo 结构

option.info() 返回的元数据:

字段类型描述
idnumber数字选项 ID
prefixedKeystring完整选项字符串(如 "-std="
kindOptionKindClass选项类型(见下文)
groupnumber分组 ID
aliasnumber别名目标 ID
aliasArgsstring[]解析别名时追加的参数
flagsnumber选项标志位
visibilitynumber平台可见性掩码
paramnumber多参数选项的参数个数
helpstring来自 LLVM 表的帮助文本
meta_varstring帮助文本中的占位符标签

选项类型

OptionKindClass 枚举描述了选项如何消费参数:

类型描述
FlagClass无值(如 -c-v
JoinedClass值直接连接在键后面(如 -std=c++20
SeparateClass值在下一个参数中(如 -o main.o
JoinedOrSeparateClass连接或分离均可(如 -Ipath-I path
CommaJoinedClass逗号分隔的值连接在键后面
RemainingArgsClass消费所有剩余参数
RemainingArgsJoinedClass键 + 剩余参数
MultiArgClass固定数量的分离值参数
ValuesClass多个分离的值
InputClass位置输入(源文件)
UnknownClass未识别的选项
GroupClass选项分组(非实际选项)

可见性过滤

解析时可以按平台可见性过滤选项。这对于处理平台特定选项(如 MSVC 风格的 /TC)很有用:

js
import { option } from "catter";

// 使用默认可见性解析(所有选项可见)
const items = option.collect("clang", args);

// 使用显式可见性掩码过滤平台特定选项
const clItems = option.collect("clang", args, ClangVisibility.CLOption);

每个选项表导出自己的可见性常量(如 ClangVisibility.DefaultVisClangVisibility.CLOption)。