记录 llvm 获取 tag 的脚本与 lldb 不兼容问题解决过程
不兼容问题描述
负责 llvm 研发的同事在 cmake 脚本里补充了一个小功能,来获取 llvm 仓库的版本号 tag,实现原理是在官方的生成版本脚本里添加了一个 tag 变量,该 tag 变量值通过执行命令 git describe --contains HEAD
来获取。但是实现过程中,在代码里包含了 ${LLVM_SOURCE_DIR}
路径变量,编译 llvm 时不会报错,但当编译 lldb 时这个 cmake 脚本就会报错,提示找不到这个路径变量,从而产生了不兼容问题。
尝试解决方案
尝试了两个解决方法,实验后发现都不可行。
尝试了在构建 lldb 的时候,手动指定这个变量值 - DLLVM_SOURCE_DIR=path/to/llvm/source,但是并不能传递过去,分析发现,该变量值需要通过调用该脚本的那个调用者传递,而不能通过最外层构建 lldb 时传递。
把
${LLVM_SOURCE_DIR}
改成 llvm 项目里更常见的变量${LLVM_ROOT_SRC}
,还是不识别。
深入分析问题
发现添加该功能时,修改的脚本是:llvm-project/llvm/cmake/modules/GenerateVersionFromVCS.cmake,该脚本是属于工具类脚本,可以指定输入参数后进行调用。
1 | # CMake script that writes version control information to a header. |
经过分析发现,这个脚本里的变量都是通过输入参数解析传递过来的,llvm 编译时之所以能识别到 ${LLVM_SOURCE_DIR}
路径变量,是因为这里通过 -DLLVM_SOURCE_DIR
指定了传参:
1 | set(generate_vcs_version_script "${LLVM_CMAKE_PATH}/GenerateVersionFromVCS.cmake") |
而在 lldb 源码只指定 -DLLDB_SOURCE_DIR
传参,故而识别不到 -DLLVM_SOURCE_DIR
,lldb 里是这样调用脚本的:
1 | add_custom_command(OUTPUT "${version_inc}" |
最终解决方案
分析了 cmake 脚本传参的特点,发现 NAMES
参数取值可能是 LLDB
单个形式或者 LLVM;CLANG
列表形式,于是通过 list(GET NAMES 0 current_name)
获取参数 NAMES
的第一个参数。然后再把 ${LLVM_ROOT_SRC}
换成 ${${current_name}_SOURCE_SRC}
就可以了。
学习 cmake 语法
在这个过程中,自己查阅资料,也学习了一些 cmake 语法知识。
通过 execute_process 可以在 cmake 里面执行 shell 命令或脚本,OUTPUT_VARIABLE 参数对应输出的内容。例如:
execute_process (COMMAND echo “Hello World” OUTPUT_VARIABLE output)// 执行命令 echo “Hello World”,输出到 output
cmake 中字符串可以通过 string 进行操作。例如:
string (SUBSTRING “Hello World” 0 5 S_sub)// 获取索引 0,长度 5 的子串 Hello
- 通过 list 命令来处理 cmake 中的字符串列表。例如:
list (GET input_list 0 element_0)// 获取列表 input_list 中索引 0 的元素,输出到 element_0