如何在Bazel构建的Android Kernel项目Makefile中添加-emit-llvm并修复llvm-nm失败问题
一、先修复Makefile中LLVM变量被覆盖的问题
你看到输出======================1======,说明LLVM变量被Bazel的构建上下文覆盖成了1,而非你硬写的/usr/bin/。Bazel构建Kernel时会通过内置规则或--define参数传递LLVM相关变量,直接在Makefile硬编码赋值会被覆盖,正确做法是通过Bazel传递工具链路径:
1. 通过Bazel传递LLVM工具链路径
启动Bazel构建时,用--define参数指定LLVM前缀:
bazel build //path/to/your:kernel_target --define=llvm_prefix=/usr/bin/
也可以在项目根目录的.bazelrc中添加全局配置,避免每次手动输入:
build --define=llvm_prefix=/usr/bin/
2. 修改Makefile接收Bazel传递的变量
把原有Makefile代码改成如下,用?=保证Bazel传递的变量优先生效:
# 优先使用Bazel传递的llvm_prefix定义,未定义时才使用默认值 LLVM ?= $(llvm_prefix) ifneq ($(LLVM),) $(info ======================$(LLVM)======) ifneq ($(filter %/,$(LLVM)),) LLVM_PREFIX := $(LLVM) else ifneq ($(filter -%,$(LLVM)),) LLVM_SUFFIX := $(LLVM) endif endif
二、添加-emit-llvm生成LLVM IR
要生成LLVM中间表示,需将-emit-llvm和对应输出控制flag添加到编译参数中:
1. 全局添加编译flag
找到Kernel Makefile中定义KBUILD_CFLAGS的位置,追加以下配置:
# 生成文本格式的LLVM IR文件(.ll后缀) KBUILD_CFLAGS += -emit-llvm -S # 如果需要生成字节码格式的IR文件(.bc后缀),替换为: # KBUILD_CFLAGS += -emit-llvm -c
2. 针对特定模块添加flag
如果只需为某个模块生成IR,可在对应模块的规则中单独指定:
obj-y += my_custom_module.o my_custom_module.o: CFLAGS += -emit-llvm -S
三、修复llvm-nm失败的问题
报错llvm-nm failed的核心原因是Bazel沙箱隔离环境中找不到LLVM工具,或工具链版本不兼容,可按以下步骤解决:
确保沙箱能访问LLVM工具:
在.bazelrc中添加沙箱挂载规则,允许访问系统LLVM工具路径:build --sandbox_add_mount=/usr/bin/llvm-nm build --sandbox_add_mount=/usr/bin/clang # 按需添加其他LLVM工具,如llvm-as、llvm-link等指定LLVM工具版本后缀:
如果你的LLVM工具带版本后缀(如llvm-nm-14),通过Bazel传递后缀参数:bazel build //path/to/your:kernel_target --define=llvm_suffix=-14或在Makefile中补充:
LLVM_SUFFIX ?= -14检查工具链完整性:
确认/usr/bin/下存在完整的LLVM工具集,且版本符合Android Kernel要求(通常为LLVM 14及以上)。定位脚本报错原因:
临时修改common/scripts/check-local-export脚本,添加echo $PATH和which llvm-nm命令,查看沙箱内的环境路径和工具存在情况,精准定位问题。
内容的提问来源于stack exchange,提问作者John

