This is an archive of the discontinued LLVM Phabricator instance.

cmake: Set the proper rpath in add_llvm_executable and llvm_add_library
AbandonedPublic

Authored by plevine on Oct 6 2016, 12:32 AM.

Details

Reviewers
beanz
Summary

LLVM sets CMAKE_INSTALL_RPATH in its top-level CMakeLists.txt to "\$ORIGIN/../lib${LLVM_LIBDIR_SUFFIX}". When Clang is built with LLVM, this propagates to Clang as well and ensures that even if CMAKE_INSTALL_PREFIX is set, installed binaries always find their dependent libraries.

When compiling clang as a separate build, no such rpath is set. If CMAKE_INSTALL_PREFIX is not set and libraries are installed to standard locations, this is not a problem. But when defining CMAKE_INSTALL_PREFIX, even if the same as that of LLVM, and installing and then executing binaries like clang, it results in

error while loading shared libraries: libLLVMBPFCodeGen.so.4.0: cannot open shared object file: No such file or directory

A fix was proposed to Clang: https://reviews.llvm.org/D25267. It was suggested that this problem be resolved by patching LLVM's 'add_llvm_executable' function and remove the rpath logic from the top-level CMakeLists.txt entirely.

This patch is based on the rpath logic of the top-level CMakeLists.txt. It has been tested by building LLVM with "CMAKE_INSTALL_PREFIX=/usr/lib/llvm-9999" and building Clang separately with "CMAKE_INSTALL_PREFIX=/usr/lib/clang-9999" (the version number is a Gentoo Linux convention). Testing with readelf -d /usr/lib/llvm-9999/bin/llvm-extract | grep 'RUNPATH', for instance, correctly prints:

0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/../lib64]

and readelf -d /usr/lib/clang-9999/bin/clang++ | grep 'RUNPATH' correctly prints

0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/../lib64:/usr/lib64/llvm-9999/lib64]

Update: Patch updated based on previous suggestions.

Diff Detail

Event Timeline

plevine updated this revision to Diff 73731.Oct 6 2016, 12:32 AM
plevine retitled this revision from to cmake: Set the proper rpath in add_llvm_executable and llvm_add_library.
plevine updated this object.
plevine added reviewers: beanz, mgorny.
plevine added a subscriber: llvm-commits.
beanz edited edge metadata.Oct 6 2016, 9:25 AM

First, the two blocks of code are doing the same thing, so they should be a function, not duplicated. Aside from that I have some feedback on the specific implementation, but I'm only going to write it on one set of the diffs.

cmake/modules/AddLLVM.cmake
509

In OS X 10.4 @loader_path was introduced as a more rubust rpath option, and it is equivolent to @executable_path in trivial situations but also supports bundles (which is important to LLDB), so we should use that here instead of @executable_path. I'm pretty sure nobody cares about deploying to 10.3 anymore.

514

Just for safety sake, please put an extra space at the end of the flag too.

518

This is definately not right. This condition will be false in clang and other sub-projects regardless of whether or not you're building against an installed LLVM. It might be sufficient to compare CMAKE_INSTALL_PREFIX against LLVM_INSTALL_PREFIX. The later is defined by LLVMConfig.cmake which is used by out-of-tree project builds. Writing the compare that way would also result in not having unnecissary extra rpaths.

521

Why are you setting this off? This doesn't seem right to me.

522

This should be semi-colon separated not colon-separated. When CMake interprets INSTALL_RPATH it expects a list of entries that it converts to the correct platform specific linker flags. Colon-separated may be correct for ELF platforms, but it isn't for Mach-o.

plevine added inline comments.Oct 6 2016, 1:12 PM
cmake/modules/AddLLVM.cmake
521

Whenever building clang with BUILD_WITH_INSTALL_RPATH set to ON, it fails with

warning: libclangLex.so.4.0, needed by lib32/libclangFormat.so.4.0.0, not found (try using -rpath or -rpath-link)
/usr/lib/gcc/x86_64-pc-linux-gnu/6.2.0/../../../../x86_64-pc-linux-gnu/bin/ld: warning: libclangAST.so.4.0, needed by lib32/libclangToolingCore.so.4.0.0, not found (try using -rpath or -rpath-link)

along with undefined reference errors pertaining to clang library symbols. The libraries do include in their rpath "$ORIGIN/../lib32" which does correctly point back to the library directory even at build time so I admit I'm at a loss. Regardless, clang does build correctly with BUILD_WITH_INSTALL_RPATH set to OFF and the correct and necessary rpath exists at runtime. I'm open to any insight you can offer and any changes you would suggest.

beanz added inline comments.Oct 7 2016, 7:57 PM
cmake/modules/AddLLVM.cmake
521

Unfortunately I'm not sure I'm the right person to help with the Linux issue here. What I can say is that I did not see this issue on Darwin, and if you turn BUILD_WITH_INSTALL_RPATH off on Darwin the binaries get the wrong rpath in the build tree.

plevine added inline comments.Oct 9 2016, 7:29 PM
cmake/modules/AddLLVM.cmake
521

Here's the problem. The build-time linker doesn't respect $ORIGIN whether with -rpath or --rpath-link. When testing on the command line in the build directory, by changing $ORIGIN/../lib32 to ./lib32 it links fine.

plevine updated this revision to Diff 74092.Oct 9 2016, 8:41 PM
plevine updated this object.
plevine edited edge metadata.
plevine added inline comments.Oct 9 2016, 10:08 PM
cmake/modules/AddLLVM.cmake
518

It might be sufficient to compare CMAKE_INSTALL_PREFIX against LLVM_INSTALL_PREFIX

This doesn't appear to be working.

beanz added inline comments.Oct 11 2016, 11:15 AM
cmake/modules/AddLLVM.cmake
316

Please rename this to follow the conventions in this file (i.e. llvm_set_rpath).

317

Can you refactor this to reduce the number of places where set_target_properties is called?

This should be able to have a single call site something like:

set_target_properties(${name} PROPERTIES
          BUILD_WITH_INSTALL_RPATH On
          INSTALL_RPATH "${_install_rpath}"
          ${_install_name_dir})

Where _install_rpath is the rpath setting, and _install_name_dir is only defined on Apple to set(_install_name_dir INSTALL_NAME_DIR "@rpath").

327

As convention we don't put the condition inside endif blocks.

471

Rather than adding a condition block for this can you hoist it up under the add_library call above in the elseif(ARG_SHARED) block?

521

This seems wrong to me. In general rpaths are intended to be consumed by the loader, not the static linker. They get encoded into the final binary. Rather than disabling building with the install rpath, maybe this should be fixed by adding linker search paths.

Disabling the install rpath means that binaries need to be re-linked before installing them because the binaries aren't in their final linked form in the build directory.

mgorny edited edge metadata.Oct 26 2016, 8:13 AM

@plevine, are you still working on this? If not, I may need to take it over. I just noticed that the lack of this is breaking tests in clang stand-alone build, making them use clang libraries from previous install.

Also, testing this patch I get the following output:

... -Wl,-rpath,/var/tmp/portage/sys-devel/llvm-9999/work/llvm-9999-abi_x86_32.x86/lib32:::::::::::::::::::

This doesn't look correct to me (esp. the dozen of empty paths).

beanz added a comment.Nov 1 2016, 10:55 AM

@mgorny and I worked together on a patch that I've landed in rL285714, which should address this issue. If you're still having problems please let us know.

mgorny resigned from this revision.Jan 24 2017, 2:41 PM
plevine abandoned this revision.Feb 6 2017, 10:25 AM

Yep. rL285714 works for me.