Hello,

If one searches for "inconsistency in registered CommandLine options" - Google Search

There are a lot of matches spanning various graphical applications, from the zig programming language to LibreOffice, Darktable, Blender, to various other things using Flatpak, AppImage, etc.

The most common reason for this issue is that an application uses its own statically-linked version of LLVM, likely to JIT-compile something, while the user’s graphics driver likely links against the graphics driver, libGL.so, which for users of either Intel or AMD (or any other Mesa-based) drivers, links against the distro’s libLLVM.so

But there does not seem to be any consensus about how to solve that meaningfully, and allowing an application to be built a single time , e.g. against a static LLVM-10 because it has been updated to LLVM-10 API, and still run on a wide range of linux distros.

Proposing to add the software to the Linux repos does not cut it - what if I make a new software tomorrow ? There are still plenty of people on Ubuntu 16.04/18.04/20.04 for instance - they should be able to use that software, especially considering that this is a non-issue on macOS and Windows.

Neither does “rebuilding the app for each distro” - if an app uses LLVM 10 API, how many distros can be targeted today ? Pretty much only Arch Linux and similar.

So, is there a way ? A special option to set while building LLVM ? Is this issue on the radar of the LLVM team ?

Thanks !

I believe you need your application to either be packaged for the distro (and so linked against the LLVM present in the distribution repo), or embed LLVM inside your application with private visibility so that the copy of LLVM you embed won’t interact with the rest of the distribution (like the graphic drivers).

What if this happens on an out-of-source pass running in opt? I have specific case where i am using the Linker in a pass. If i link the Linker lib e.g:

add_library(LinkRT SHARED ${LinkRT_Sources})
set_target_properties(LinkRT PROPERTIES COMPILE_FLAGS "-fno-rtti")
target_link_libraries(LinkRT LLVMLinker)

I get in opt:
opt: CommandLine Error: Option 'debug-pass' registered more than once!

if i don’t link the Linker lib i get:
opt: symbol lookup error: lib/Transforms/libLinkRT.so: undefined symbol: _ZN4llvm6Linker11linkModulesERNS_6ModuleESt10unique_ptrIS1_St14default_deleteIS1_EEjSt8functionIFvS2_RKNS_9StringSetINS_15MallocAllocatorEEEEE

Any ideas?

What I managed to do is add a linker script when linking my app that puts every symbol (including the statically-linked LLVM symbols) in a namespace.
The script looks like :

FOOBAR_1.0 {
local: *;

Hi @eeGx i run into the same situation as you except that when link with LLVMLinker, my opt error is:

opt: CommandLine Error: Option 'asm-macro-max-nesting-depth' registered more than once!

without linking, the error is exactly same as yours.

May I check if you manage to solve or make any headway in this issue? Thanks in advance. :blush:

Can we get this fixed? Would be nice if people could use my software on Linux without running into this issue.

Maybe it could be fixed by having an option when building the LLVM libs of using an alternative namespace (for example you could use “my_llvm” instead of “llvm”.
That way the symbols won’t clash with another LLVM loaded into the process.

Not sure if this one is still valid, so here come my 2 cents:

I came across the same problem recently when building my own clang/llvm version with debug info. The solution I found when searching was to change the way the LLVM library was linked into the project inside the CMakeLists.txt.

Basically I switched from

set(LIBRARY_LIST clang-cpp LLVM stdc++fs)
target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBRARY_LST})

set(LIBRARY_LIST clang-cpp stdc++fs)
llvm_map_components_to_libnames(LLVM_LIBS core )
target_link_libraries(${PROJECT_NAME} PRIVATE ${LLVM_LST} ${LIBRARY_LIST})

This solved the problem for me.

Hope this helps.

The function is defined here:

llvm/cmake/modules/LLVM-Config.cmake

and briefly explained here: llvm/docs/CMake.rst:

Example:
//Find the libraries that correspond to the LLVM components
//that we wish to use
llvm_map_components_to_libnames(llvm_libs support core irreader)

The list of libraries is determined by using the
llvm_map_components_to_libnames() CMake function. For a list of available
components look at the output of running llvm-config --components.

Not sure about the inner details of that function (more than the function name already explains) but it works for me.

Thanks, this solution seems to work for me. Can you explain what that linker script does?

It puts all the symbols of the binary behind a versioned ELF version namespace and hides them: VERSION (LD)

I might be a little bit late to the party, but this thread was the first I found while I was researching this error, so I am posting my findings here.

I’ve had the same issue when using a pass-plugin that is statically linked against LLVM in clang (that also links LLVM statically). When trying to load the plugin, the constructor _GLOBAL__sub_I_RegAllocBasic.cpp of the plugin meanders to a

llvm::cl::initializer<llvm::FunctionPass* (*)()> llvm::cl::init<llvm::FunctionPass* (*)()>(llvm::FunctionPass* (* const&)()) (clang-17) 

that lives in the compiler that loads the plugin. Just as it is described at #47565

I think the issue here is that it is clang’s singleton that tries to register the command line option and not the plugins. Since I am on macos, I think the dyld sees that the constructor tries to call the symbol and selects the global symbol exported by the compiler to resolve the call (and not the correct local one).

My solution was to instruct the apple linker to only export the functions needed for the plugin to be loaded by clang. So when you link your plugin something like this needs to be present:

clang [...] -Wl,-exported_symbols_list -Wl,exported_symbols.sym

E.g. your .sym file could look like:

_llvmGetPassPluginInfo

Hope this helps if anyone has a similar issue.