Bash 调用的 Clang 和 ClangTool 有什么区别?

What's the difference between Clang invoked by Bash and the ClangTool?

提问人:Fanke Tong 提问时间:11/17/2023 最后编辑:Fanke Tong 更新时间:11/18/2023 访问量:34

问:

原始问题

我按照教程创建了一个名为分析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 变量?

C++ clang clang-ast-matchers

评论


答:

0赞 Scott McPeak 11/18/2023 #1

简而言之,区别在于 invoked 的编译器头(包括 )在文件系统中附近,而您的 LibTooling 可执行文件则没有。clangbashstddef.h

解析 C++ 需要的不仅仅是一个可以读取 C++ 语法的程序。它还需要某些头文件,这些头文件在逻辑上是编译器的一部分,而不是 C 库的一部分; 是前者之一,而(说)是后者之一。如果使用 LibTooling 创建解析 C++ 的可执行文件,则如果没有编译器标头,它是不完整的,就像视频游戏可执行文件缺少其艺术资源一样。(就像视频游戏可以将其艺术打包到可执行文件中一样,LibTooling 可执行文件可以将编译器头文件嵌入其中,但不幸的是,LibTooling API 的设置并不容易做到这一点。stddef.hstdio.h

那么 LibTooling 程序如何找到它的编译器头呢?有几个 API 接受类似 -的数组,包括代码中使用的数组 clang::tooling::CommonOptionsParser::create。这些 API 安排查找相对于该数组中的编译器标头,本质上是 .因此,您需要确保该目录存在并填充了所有必需的文件。argvargv[0]$(argv[0])/../lib/clang/$(version)/include

解决方案:正确的方法是让您的工具具有“安装”步骤或类似步骤,将 Clang 编译器标头以及可执行文件复制到后者将运行的位置。您需要复制 中的每个文件。lib/clang/$(version)/include

但是,由于这有点烦人,我通常做的是让我传递一个开关,该开关提供我正在使用的 Clang 安装目录的路径,然后在我的 C++ 代码中,我只需将 shell 传入的替换为 ,有效地欺骗 Clang API 以模拟自己。然后,API 将找到与查找相同的编译器标头。这当然意味着我的工具只有在该位置安装了兼容版本时才有效,因此它适用于实验和一次性开发,但如果工具要被其他人安装和使用,则不应该这样做。一个完整的例子在我的print-clang-ast工具中。Makefile-Dargv[0]$(clang_install_dir)/bin/clangclangclangclang

作为参考,还有其他几个与该主题相关的问题和讨论,尽管没有一个问题和足够完整的答案使其适合作为重复目标:

其中一些提供了不同的解决方法,包括传递一个额外的参数,正如你所指出的,它有效,但通常不是一个好的解决方案。-I

评论

0赞 Fanke Tong 11/18/2023
谢谢,困扰我很久的问题终于迎刃而解了。顺便说一句,我最初假设 ${CLANG_INCLUDE_DIRS} 会引用所需的路径,但根据输出,${CLANG_INCLUDE_DIRS} 和 ${LLVM_INCLUDE_DIRS} 似乎是相同的 ()。您知道是否有任何指向所需路径的 CMake 变量吗?/data/tfk/llvm/include
0赞 Scott McPeak 11/19/2023
@FankeTong 右边,指向编译 Clang(或 LibTooling 程序)所需的头文件,而不是需要使用它部署的头文件。我不知道有指向后者的 CMake 变量,但这意义不大,因为我对 CMake 总体了解不多。CLANG_INCLUDE_DIRS