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

4ioopgfo  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(87)

原题

我按照教程创建了一个名为ast_extract的工具来分析libpng的源代码:

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”文件的问题,如以下错误消息所示:
我可以通过添加一个额外的参数来暂时解决这个问题,比如ast_extract --extra-arg='-I/data/tfk/llvm/lib/clang/17/include'。但是,当使用Bash时,我可以简单地从compile_commands.json复制命令行,而不会遇到任何问题:

clang -c -DHAVE_CONFIG_H -I. -g -O2 -fPIC -DPIC -o .libs/pngmem.o pngmem.c


如何修改ast_extract工具以消除对额外参数的需要?

更新

感谢scott!通过将以下规则合并到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变量直接对应所需的路径?

dluptydi

dluptydi1#

简而言之,不同之处在于bash调用的clang在文件系统中附近有其编译器头文件(包括stddef.h),而LibTooling可执行文件则没有。
解析C需要的不仅仅是一个能够读取C语法的程序,它还需要某些头文件,这些头文件在逻辑上是编译器的一部分,而不是C库的一部分; stddef.h是前者之一,而(比如)stdio.h是后者之一。如果你使用LibTooling来创建一个解析C++的可执行文件,如果没有编译器头文件,它是不完整的,就像一个视频游戏的可执行文件缺少它的艺术资产一样。(就像一个视频游戏可以将它的艺术打包到可执行文件中一样,一个LibTooling可执行文件可以将编译器头嵌入其中,但是不幸的是,LibTooling API并没有设置成容易做到这一点。)
那么,LibTooling程序如何找到它的编译器头文件呢?有几个API接受类似argv的数组,包括您代码中使用的clang::tooling::CommonOptionsParser::create。这些API安排在该数组中查找与argv[0]相关的编译器头文件,实际上是在$(argv[0])/../lib/clang/$(version)/include中。因此,您需要确保目录存在,并且填充了所有必需的文件。

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

然而,由于这有点烦人,我通常会让我的Makefile传递一个-D开关,该开关提供我正在使用的Clang安装目录的路径,然后在我的C++代码中,我只需将shell传递的argv[0]替换为$(clang_install_dir)/bin/clang,有效地欺骗Clang API来模拟clang本身。然后API将找到与clang相同的编译器头。这当然意味着我的工具只在该位置安装了clang的兼容版本时才能工作,所以它适合于实验和一次性开发,但是如果其他人要安装和使用它,那么工具就不应该这样做。
作为参考,还有其他几个与此主题有关的问题和讨论,尽管没有一个问题和足够完整的答案使其适合作为重复目标:

其中一些提供了不同的解决方法,包括传递一个额外的-I参数,这可以像您注意到的那样工作,但通常不是一个好的解决方案。

相关问题