Bazel中为指定共享库传递--no-as-needed链接选项的问题
解决Bazel中共享库链接时
--no-as-needed顺序问题 核心问题是Bazel原生规则的linkopts会被放在依赖库之后,无法实现--no-as-needed -lmylib1 -lmylib2的顺序要求,以下是两种可行方案:
方案一:直接在顶层目标中绑定选项与库
将--no-as-needed、库名、--as-needed打包成单个linkopt,强制链接器按指定顺序处理:
cc_binary( name = "libmylib1.so", srcs = ["lib1.cc"], linkshared = True, ) cc_binary( name = "libmylib2.so", srcs = ["lib2.cc"], linkshared = True, ) cc_test( name = "hello_world", srcs = ["hello_world.cc"], # 用逗号分隔选项和库名,链接器会自动展开为正确顺序 linkopts = [ "-Wl,--no-as-needed,-lmylib1,-lmylib2,--as-needed", ], deps = [":libmylib1.so", ":libmylib2.so"], )
这种方式利用了GCC链接器的语法:-Wl,option1,option2会被解析为传递给链接器的option1 option2,因此上述linkopt会被展开为--no-as-needed -lmylib1 -lmylib2 --as-needed,完全符合需求。
方案二:自定义Starlark规则封装顺序逻辑
如果需要复用这个逻辑,可以编写一个简单的自定义规则,自动为指定共享库添加前后缀链接选项:
def _no_as_needed_lib_impl(ctx): # 提取依赖中的共享库文件名,生成-lxxx格式的链接参数 lib_links = [] for dep in ctx.attr.deps: for file in dep.files.to_list(): # 从libxxx.so中提取xxx部分 lib_name = file.basename.split(".so")[0][3:] lib_links.append(f"-l{lib_name}") # 构造正确顺序的链接选项 linkopts = ["-Wl,--no-as-needed"] + lib_links + ["-Wl,--as-needed"] # 传递原有的编译和链接上下文 cc_infos = [dep[CcInfo] for dep in ctx.attr.deps] combined_cc_info = cc_common.merge_cc_infos(cc_infos = cc_infos) return [ combined_cc_info, # 传递自定义的链接选项 LinkerFlagsInfo(linkopts = linkopts), ] no_as_needed_lib = rule( implementation = _no_as_needed_lib_impl, attrs = { "deps": attr.label_list(providers = [CcInfo], mandatory = True), }, provides = [CcInfo, LinkerFlagsInfo], )
使用方式如下:
cc_binary( name = "libmylib1.so", srcs = ["lib1.cc"], linkshared = True, ) cc_binary( name = "libmylib2.so", srcs = ["lib2.cc"], linkshared = True, ) # 用自定义规则封装需要特殊处理的共享库 no_as_needed_lib( name = "mylib", deps = [":libmylib1.so", ":libmylib2.so"], ) cc_test( name = "hello_world", srcs = ["hello_world.cc"], deps = [":mylib"], )
这个规则会自动生成正确顺序的链接选项,无需在每个目标中重复编写复杂的linkopts。
为什么不需要虚假依赖
Bazel的链接命令构造逻辑是将依赖库放在linkopts之前,所以单纯添加linkopts无法改变顺序,但通过绑定选项与库或自定义规则注入选项的方式,可以绕过这个限制,完全不需要添加虚假依赖。
内容的提问来源于stack exchange,提问作者user826236
相关产品推荐
相关产品推荐

