LLVM error with out-of-source check

Hi,

I’d like to write some clang-tidy checks for a closed-source C++ project. I need them to be out-of-source (for a variety of reasons - they’re not useful outside this project, so no point open-sourcing them, and asking DevOps to re-distribute clang every time I make a change will make me very unpopular).

The documentation for out-of-source checks is quite sparse. More documentation, or (even better) a minimal working example, would be really useful!

This is what I have so far:

set(library myCheck)

find_package(Clang CONFIG REQUIRED
  PATHS "path/to/clang"
)

add_library(${library} SHARED
  myCheck.cpp
)

target_include_directories(${library} 
  SYSTEM PUBLIC 
    ${CLANG_INCLUDE_DIRS}
)

target_compile_options(${library} PRIVATE -fno-rtti)

target_link_libraries(${library} PRIVATE  clangTidy)

Where myCheck is some boring check.

This compiles and links fine, but I get the following error when I try and run:

$ clang-tidy --load myCheck.so --verify-config
clang-tidy: CommandLine Error: Option ‘static-func-full-module-prefix’ registered more than once!
LLVM ERROR: inconsistency in registered CommandLine options
PLEASE submit a bug report to Issues · llvm/llvm-project · GitHub and include the crash backtrace.
Stack dump:
0. Program arguments: clang-tidy --load lib/linux-x86_64-2.17/clang15.0/lib/libclangTidyStarModule.so --verify-config
#0 0x0000000004208a61 PrintStackTraceSignalHandler(void*) Signals.cpp:0:0
#1 0x0000000004206274 SignalHandler(int) Signals.cpp:0:0
#2 0x00007f3dd8e3a630 __restore_rt sigaction.c:0:0
#3 0x00007f3dd7927387 raise (/lib64/libc.so.6+0x36387)
#4 0x00007f3dd7928a78 abort (/lib64/libc.so.6+0x37a78)
#5 0x00000000008e752e llvm::json::operator==(llvm::json::Value const&, llvm::json::Value const&) (.cold) JSON.cpp:0:0
#6 0x0000000004112288 (/u/thojam9h/custom_programs/llvm-project/build/bin/clang-tidy+0x4112288)
#7 0x00000000040f7950 (anonymous namespace)::CommandLineParser::addOption(llvm::cl::Option*, llvm::cl::SubCommand*) CommandLine.cpp:0:0
#8 0x00000000040f82fd llvm::cl::Option::addArgument() (/u/thojam9h/custom_programs/llvm-project/build/bin/clang-tidy+0x40f82fd)
#9 0x00007f3dd43851f1 _GLOBAL__sub_I_InstrProf.cpp InstrProf.cpp:0:0
#10 0x00007f3dd90569c3 _dl_init (/lib64/ld-linux-x86-64.so.2+0xf9c3)
#11 0x00007f3dd905b59e dl_open_worker dl-open.c:0:0
#12 0x00007f3dd90567d4 _dl_catch_error (/lib64/ld-linux-x86-64.so.2+0xf7d4)
#13 0x00007f3dd905ab8b _dl_open (/lib64/ld-linux-x86-64.so.2+0x13b8b)
#14 0x00007f3dd8a1ffab dlopen_doit dlopen.c:0:0
#15 0x00007f3dd90567d4 _dl_catch_error (/lib64/ld-linux-x86-64.so.2+0xf7d4)
#16 0x00007f3dd8a205ad _dlerror_run (/lib64/libdl.so.2+0x15ad)
#17 0x00007f3dd8a20041 dlopen@@GLIBC_2.2.5 (/lib64/libdl.so.2+0x1041)
#18 0x00000000041eca24 llvm::sys::DynamicLibrary::getPermanentLibrary(char const*, std::__cxx11::basic_string<char, std::char_traits, std::allocator>) (/u/thojam9h/custom_programs/llvm-project/build/bin/clang-tidy+0x41eca24)
#19 0x000000000415a3ef llvm::PluginLoader::operator=(std::__cxx11::basic_string<char, std::char_traits, std::allocator> const&) (/u/thojam9h/custom_programs/llvm-project/build/bin/clang-tidy+0x415a3ef)
#20 0x000000000092044a llvm::cl::opt<llvm::PluginLoader, false, llvm::cl::parser<std::__cxx11::basic_string<char, std::char_traits, std::allocator>>>::handleOccurrence(unsigned int, llvm::StringRef, llvm::StringRef) (/u/thojam9h/custom_programs/llvm-project/build/bin/clang-tidy+0x92044a)
#21 0x00000000040fd1dc llvm::cl::ParseCommandLineOptions(int, char const
const*, llvm::StringRef, llvm::raw_ostream*, char const*, bool) (/u/thojam9h/custom_programs/llvm-project/build/bin/clang-tidy+0x40fd1dc)
#22 0x00000000019956a8 clang::tooling::CommonOptionsParser::init(int&, char const**, llvm::cl::OptionCategory&, llvm::cl::NumOccurrencesFlag, char const*) (/u/thojam9h/custom_programs/llvm-project/build/bin/clang-tidy+0x19956a8)
#23 0x0000000001996c16 clang::tooling::CommonOptionsParser::create(int&, char const**, llvm::cl::OptionCategory&, llvm::cl::NumOccurrencesFlag, char const*) (/u/thojam9h/custom_programs/llvm-project/build/bin/clang-tidy+0x1996c16)
#24 0x0000000000928369 clang::tidy::clangTidyMain(int, char const**) (/u/thojam9h/custom_programs/llvm-project/build/bin/clang-tidy+0x928369)
#25 0x00007f3dd7913555 __libc_start_main (/lib64/libc.so.6+0x22555)
#26 0x000000000091f86a _start (/u/thojam9h/custom_programs/llvm-project/build/bin/clang-tidy+0x91f86a)
Aborted

I suspect there’s something fundamentally wrong with my approach - if I had to guess, I’d say that, because I’m linking clangTidy as a static library (as supplied by ClangConfig.cmake), some symbols are defined twice, causing the above error. Where have I gone wrong?

Thanks,
Tom

Looks like I needed to compile LLVM itself with -DBUILD_SHARED_LIBS:BOOL=ON. It would be really useful if this kind of thing was documented!