提问人:Fanke Tong 提问时间:11/17/2023 最后编辑:Fanke Tong 更新时间:11/18/2023 访问量:34
Bash 调用的 Clang 和 ClangTool 有什么区别?
What's the difference between Clang invoked by Bash and the ClangTool?
问:
原始问题
我按照教程创建了一个名为分析libpng源代码的工具:ast_extract
llvm::cl::OptionCategory ASTExtractCategory("ASTExtract tool options");
llvm::Expected<clang::tooling::CommonOptionsParser> optionParser = clang::tooling::CommonOptionsParser::create(argc, argv, ASTExtractCategory);
clang::tooling::ClangTool tool(optionParser->getCompilations(), optionParser->getCompilations().getAllFiles());
但是,该工具会遇到无法找到“stddef.h”文件的问题,如以下错误消息所示:
1 error generated.
Error while processing /data/tfk/study/PUT/libpng/pngmem.c.
In file included from contrib/libtests/pngvalid.c:27:
/usr/include/signal.h:301:11: fatal error: 'stddef.h' file not found
301 | # include <stddef.h>
| ^~~~~~~~~~
我可以通过添加一个额外的参数来暂时解决这个问题,例如.但是,在使用 Bash 时,我可以简单地从中复制命令行,而不会遇到任何问题:ast_extract --extra-arg='-I/data/tfk/llvm/lib/clang/17/include'
compile_commands.json
clang -c -DHAVE_CONFIG_H -I. -g -O2 -fPIC -DPIC -o .libs/pngmem.o pngmem.c
如何修改工具以消除对额外参数的需要?ast_extract
更新
感谢斯科特!我已经通过将以下规则合并到 CMakeLists.txt 中成功地实现了上述第一个解决方案
# Install the compiler header files that libtool cannot find (such as stddef.h)
set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_SOURCE_DIR})
install(TARGETS ast_extract DESTINATION bin)
install(DIRECTORY ${LLVM_INCLUDE_DIR}/../lib/clang/${LLVM_VERSION_MAJOR}/include DESTINATION lib/clang/${LLVM_VERSION_MAJOR})
message(STATUS "LLVM_INCLUDE_DIRS: ${LLVM_INCLUDE_DIRS}")
message(STATUS "CLANG_INCLUDE_DIRS: ${CLANG_INCLUDE_DIRS}")
尽管我尽了最大努力尽量减少硬编码,但通往 stddef.h () 的路径似乎有些繁琐。${LLVM_INCLUDE_DIR}/../lib/clang/${LLVM_VERSION_MAJOR}/include
我很好奇是否有直接对应于所需路径的 CMake 变量?
答:
简而言之,区别在于 invoked 的编译器头(包括 )在文件系统中附近,而您的 LibTooling 可执行文件则没有。clang
bash
stddef.h
解析 C++ 需要的不仅仅是一个可以读取 C++ 语法的程序。它还需要某些头文件,这些头文件在逻辑上是编译器的一部分,而不是 C 库的一部分; 是前者之一,而(说)是后者之一。如果使用 LibTooling 创建解析 C++ 的可执行文件,则如果没有编译器标头,它是不完整的,就像视频游戏可执行文件缺少其艺术资源一样。(就像视频游戏可以将其艺术打包到可执行文件中一样,LibTooling 可执行文件可以将编译器头文件嵌入其中,但不幸的是,LibTooling API 的设置并不容易做到这一点。stddef.h
stdio.h
那么 LibTooling 程序如何找到它的编译器头呢?有几个 API 接受类似 -的数组,包括代码中使用的数组 clang::tooling::CommonOptionsParser::create
。这些 API 安排查找相对于该数组中的编译器标头,本质上是 .因此,您需要确保该目录存在并填充了所有必需的文件。argv
argv[0]
$(argv[0])/../lib/clang/$(version)/include
解决方案:正确的方法是让您的工具具有“安装”步骤或类似步骤,将 Clang 编译器标头以及可执行文件复制到后者将运行的位置。您需要复制 中的每个文件。lib/clang/$(version)/include
但是,由于这有点烦人,我通常做的是让我传递一个开关,该开关提供我正在使用的 Clang 安装目录的路径,然后在我的 C++ 代码中,我只需将 shell 传入的替换为 ,有效地欺骗 Clang API 以模拟自己。然后,API 将找到与查找相同的编译器标头。这当然意味着我的工具只有在该位置安装了兼容版本时才有效,因此它适用于实验和一次性开发,但如果工具要被其他人安装和使用,则不应该这样做。一个完整的例子在我的print-clang-ast
工具中。Makefile
-D
argv[0]
$(clang_install_dir)/bin/clang
clang
clang
clang
作为参考,还有其他几个与该主题相关的问题和讨论,尽管没有一个问题和足够完整的答案使其适合作为重复目标:
其中一些提供了不同的解决方法,包括传递一个额外的参数,正如你所指出的,它有效,但通常不是一个好的解决方案。-I
评论
/data/tfk/llvm/include
CLANG_INCLUDE_DIRS
评论