在Makefile中调用GNU ar脚本遇问题,求更优解决方案
在Makefile中优雅处理GNU ar脚本合并静态库的方案
问题背景
需要合并两个静态库:自己通过Makefile生成的foo.a,以及CMake生成的the_cmake_library.a。最初尝试用here-doc写法调用ar的脚本模式失败,当前通过生成临时脚本文件的方式实现,但步骤繁琐,希望找到更简洁的方案。
最初的错误写法:
foo.a: foo.o $(AR) $(ARFLAGS) $@ $^ final_lib.a: foo.a the_cmake_library.a $(AR) -M <<CREATE $@ ADDLIB foo.a ADDLIB the_cmake_library.a SAVE END ranlib $@
报错原因:Makefile将CREATE识别为独立命令,而非here-doc的分界符——ar的脚本模式要求here-doc分界符是单独的字符串,且脚本每行必须以换行符结尾,不能像shell命令那样用分号分隔。
更优解决方案
方案1:修正here-doc写法(最直观)
利用shell的<<-'EOF'语法忽略开头的tab缩进(适配Makefile命令行必须用tab开头的规则),确保ar能正确解析每行脚本:
foo.a: foo.o $(AR) $(ARFLAGS) $@ $^ final_lib.a: foo.a the_cmake_library.a $(AR) -M <<-'EOF' CREATE $@ ADDLIB foo.a ADDLIB the_cmake_library.a SAVE END EOF ranlib $@
注意:EOF必须顶格书写,<<-'EOF'中的单引号会让shell忽略脚本行开头的tab,避免ar解析时出现多余缩进错误。
方案2:用printf+管道传递脚本(最简洁)
通过printf生成符合格式的脚本内容,直接管道传给ar -M,无需临时文件:
foo.a: foo.o $(AR) $(ARFLAGS) $@ $^ final_lib.a: foo.a the_cmake_library.a printf "CREATE %s\nADDLIB foo.a\nADDLIB the_cmake_library.a\nSAVE\nEND\n" "$@" | $(AR) -M ranlib $@
这种方式依赖POSIX标准的printf,兼容性好,且无需额外文件操作。
方案3:用Makefile define复用脚本(适合复杂场景)
如果需要复用ar脚本内容,可通过define定义脚本模板,再通过环境变量传递给shell:
define AR_MERGE_SCRIPT CREATE $@ ADDLIB foo.a ADDLIB the_cmake_library.a SAVE END endef export AR_MERGE_SCRIPT foo.a: foo.o $(AR) $(ARFLAGS) $@ $^ final_lib.a: foo.a the_cmake_library.a printf "%s" "$$AR_MERGE_SCRIPT" | $(AR) -M ranlib $@
export将定义的脚本内容传给shell,$$AR_MERGE_SCRIPT让shell读取环境变量,避免Makefile提前解析脚本中的变量。
内容的提问来源于stack exchange,提问作者Leonardo
相关产品推荐
相关产品推荐

