How to build a standalone Clang Tool?

I’m developing a Clang-based tool to expose internals of C++ ABI as C structs (memory layout of classes with vtable and content of vtable), so that it can be used to generate language bindings. I want to use the code at clang/lib/AST/ItaniumCXXABI.cpp and clang/lib/AST/ItaniumMangle.cpp. it should be similar to clang -cc1 -fdump-record-layouts --fdump-vtable-layout.

Since these classes are not exposed in Clang C API (libclang), I have to link to clang-cpp library directly.

Requirements:

  • dynamically link to clang-cpp.so to reduce binary size
  • out-of-tree build (it’s not going to be part of Clang, so my source tree is separated from clang’s)

I built LLVM with Clang and installed it to /home/dev/usr/llvm.

This is my CMakeLists.txt

set(LLVM_INSTALL_PREFIX "/home/dev/usr/llvm")

# use CMAKE_MODULE_PATH
include(${LLVM_INSTALL_PREFIX}/lib/cmake/clang/ClangConfig.cmake)
include(${LLVM_INSTALL_PREFIX}/lib/cmake/llvm/LLVMConfig.cmake)

include(${LLVM_INSTALL_PREFIX}/lib/cmake/llvm/AddLLVM.cmake)
include(${LLVM_INSTALL_PREFIX}/lib/cmake/clang/AddClang.cmake)

include_directories(${LLVM_INSTALL_PREFIX}/include)

set(LLVM_LINK_COMPONENTS
          Support
    )
add_clang_executable(cxx-abi-export main.cpp)

target_link_libraries(cxx-abi-export
  PRIVATE
  clang-cpp
  )

main.cpp (just a place holder):

int main(int argc, char **argv) {
  if (argc > 1) {
    auto ast = clang::tooling::buildASTFromCode(argv[1]);
  }
}

I can build the binary successfully, but

  • what’s the expected way to use lib/cmake/clang/* and lib/cmake/llvm/*. Should I add them to CMAKE_MODULE_PATH? I think these cmake files can handle include_directories for me, and I can use find(Clang) instead of specifying LLVM_INSTALL_PREFIX manually.

Another issue is the system include path.

When I run cxx-abi-export "#include <cstdio>", it failed with /usr/include/stdio.h:33:10: fatal error: 'stddef.h' file not found.
According to LibTooling, the default location to look for builtin headers is in a path $(dirname /path/to/tool)/../lib/clang/3.3/include relative to the tool binary. However, my tool should be able to start from any working directory, just like clang-format.

my tool with -v (mind the first line):

ignoring nonexistent directory "lib/clang/17/include"
ignoring nonexistent directory "/../lib/gcc/x86_64-redhat-linux/12/../../../../x86_64-redhat-linux/include"
ignoring nonexistent directory "/include"
#include "..." search starts here:
#include <...> search starts here:
 /../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12
 /../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/x86_64-redhat-linux
 /../lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/backward
 /usr/local/include
 /usr/include
End of search list.

so I have to run my tool at llvm toplevel directory.

but Clang itself can find the header files. (/home/dev/usr/llvm/bin/clang -v input.cpp):

ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/12/../../../../x86_64-redhat-linux/include"
ignoring nonexistent directory "/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12
 /usr/lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/x86_64-redhat-linux
 /usr/lib/gcc/x86_64-redhat-linux/12/../../../../include/c++/12/backward
 /home/dev/usr/llvm/lib/clang/17/include
 /usr/local/include
 /usr/include

How can I make my tool find /home/dev/usr/llvm/lib/clang/17/include like clang?
Currently, I add -isystem CLANG_RESOURCE_HEADERS to fix it.

I’m new to Clang. Any idea can be helpful.

Here is what our build-system does (also CMake):

set(LLVM_DIR "c:\\code\\llvm\\llvm-project\\build" CACHE FILEPATH "")

...

set(CLANG_SEARCH_PATHS
  ${LLVM_DIR}
  ${LLVM_DIR}/lib/cmake
  ${LLVM_DIR}/lib/cmake/llvm
  ${LLVM_DIR}/lib/cmake/clang
  ${LLVM_DIR}/share/clang/cmake/
  ${LLVM_DIR}/share/llvm/cmake/
)

find_package(Clang
  REQUIRED
  CONFIG
  PATHS ${CLANG_SEARCH_PATHS}
  NO_DEFAULT_PATH
)

add_executable(mytool mytool.cpp)

target_link_libraries(mytool INTERFACE
  LLVMSupport
  clangTooling
  clangDependencyScanning
)

thanks. I’ve changed my CMakeLists.txt to

set(LLVM_DIR "/home/dev/usr/llvm")

set(CLANG_SEARCH_PATHS
  ${LLVM_DIR}
  ${LLVM_DIR}/lib/cmake
  ${LLVM_DIR}/lib/cmake/llvm
  ${LLVM_DIR}/lib/cmake/clang
  ${LLVM_DIR}/share/clang/cmake
  ${LLVM_DIR}/share/llvm/cmake
)


find_package(Clang
  REQUIRED
  CONFIG
  PATHS ${CLANG_SEARCH_PATHS}
  NO_DEFAULT_PATH
)

include_directories(${CLANG_INCLUDE_DIRS})

add_executable(cxx-abi-export main.cpp)

target_link_libraries(cxx-abi-export
  PRIVATE
  clang-cpp
)

It looks much better now.

After some experiments, Clang finds clang-resource-dir by relative path. out-of-tree tools have to compile this path into the executable binary, and specify it by -resource-dir PATH_TO_CLANG_RESOURCE_DIR.

1 Like