llvm自定义后端必须在cmake配置时通过- dllvm_targets_to_build="myarch;x86;arm"显式启用,且llvm/lib/target/myarch/cmakelists.txt中必须包含add_llvm_target(myarch myarchcodegen),同时需启用- dllvm_optimized_tablegen=on和- dllvm_enable_projects="clang"才能完整支持从c到汇编的端到端编译。

LLVM自定义后端必须注册到LLVM_TARGETS_TO_BUILD才参与构建
不加这一步,CMake会直接跳过你的后端目录,连编译错误都不会报——它根本“看不见”你写的MyArchTargetMachine.cpp或MyArch.td。官方构建系统只扫描llvm/lib/Target/下被显式启用的子目录,其他一概忽略。
正确做法是在调用cmake时传入:-DLLVM_TARGETS_TO_BUILD="MyArch;X86;ARM"(注意分号分隔,不能用空格或逗号)。
- 如果只写
MyArch,其他目标会被禁用,clang可能因缺少X86而无法生成可执行文件 - 名字必须和你新建的目录名完全一致(大小写敏感),比如
llvm/lib/Target/MyArch/→MyArch - 若构建时报
Unknown target 'MyArch',说明CMake没在llvm/lib/Target/里找到对应子目录,检查路径是否拼错、是否漏了CMakeLists.txt
llvm/lib/Target/MyArch/CMakeLists.txt必须调用add_llvm_target
这个文件不是可选的——哪怕只有一行,也得存在,并且必须包含add_llvm_target(MyArch MyArchCodeGen)。这是CMake识别“这是一个合法LLVM后端”的唯一入口点。
add_llvm_target的第二个参数是生成的库名,惯例为${TARGET_NAME}CodeGen,它会自动收集该目录下所有.cpp和.td文件并编译进libLLVMMyArchCodeGen.a。
- 漏掉
add_llvm_target:你的源文件不会被加入编译列表,链接时找不到MyArchTargetMachine符号 - 拼错库名(如写成
MyArchCodegen):后续clang链接时会报undefined reference to `llvm::MyArchTargetMachine::MyArchTargetMachine(...)` - 不要手动写
add_library:LLVM的构建系统依赖add_llvm_target注入的依赖规则和TableGen处理逻辑
TableGen依赖必须显式开启LLVM_OPTIMIZED_TABLEGEN
你的MyArch.td文件要能被正确处理,CMake必须先构建出llvm-tblgen工具。默认情况下,CMake会尝试复用系统已安装的llvm-tblgen,但自定义后端几乎必然失败——因为系统版本不认识你的新指令定义。
CMake 4.3.2 Windows x86_64 历史版本安装包,适合旧项目兼容、构建环境回退、CMakeLists.txt 迁移验证、Visual Studio/Ninja/Makefile 生成器测试和 C/C++ 项目维护。
强制使用本次构建生成的llvm-tblgen:-DLLVM_OPTIMIZED_TABLEGEN=On
- 不加这个选项:CMake可能静默跳过
.td处理,导致MyArchGenInstrInfo.inc等文件为空或缺失,编译时大量use of undeclared identifier - 加上后,构建过程会先编译
llvm/utils/TableGen,再用它生成你的后端头文件,顺序严格不可逆 - 搭配
-DCMAKE_BUILD_TYPE=Debug时建议同时加-DLLVM_ENABLE_ASSERTIONS=On,否则TableGen阶段的断言错误会被吞掉
Clang前端要识别你的后端,得把clang加进LLVM_ENABLE_PROJECTS
如果你的目标是用clang -target myarch-unknown-elf跑通整个流程,光有后端不够——clang必须知道这个target存在,且能调用对应的TargetMachine。
启用clang并让它感知你的后端:-DLLVM_ENABLE_PROJECTS="clang"(注意引号,Ninja生成器下无引号会解析失败)
- 不启用
clang:你只能用llc测试IR→汇编,没法从C源码开始端到端验证 -
clang子项目会读取llvm/lib/Target/MyArch/MyArchTargetMachine.h里的getTargetTriple()等接口,所以你的TargetMachine类必须导出完整符号 - 若
clang编译失败并提示no member named 'MyArch' in namespace 'llvm',大概率是MyArchTargetMachine.h没正确声明extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMyArchTargetInfo();这类初始化函数
最常被忽略的一点:所有改动必须在cmake配置阶段完成。一旦cmake执行完毕生成了build.ninja或Makefile,再修改CMakeLists.txt或LLVM_TARGETS_TO_BUILD值都不会生效——必须删掉整个构建目录重来。这不是缓存问题,是CMake对targets的拓扑关系在configure阶段就固化了。










