-
-
Notifications
You must be signed in to change notification settings - Fork 548
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
build: Tell cmake to set 'rpath' #531
Conversation
The rpath should be set to Then we should consider not adding an rpath for system library directories, see |
d650a5c
to
278aa59
Compare
Thank you for the help, @nwellnhof. I forcibly pushed 2 commits to replace the old one:
The following text was added to the original commit message:
EDIT: In the commit log, I accidentally wrote |
278aa59
to
fbe4cf4
Compare
cmake/modules/SetRPATH.cmake
Outdated
@@ -0,0 +1,15 @@ | |||
set(CMAKE_SKIP_BUILD_RPATH FALSE) | |||
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both of these variables should already be set to FALSE by default. I think they are only mentioned in the CMake Wiki for clarity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, exactly. They are mentioned for clarity.
-
Defaults are great, until they're not; convention is a terrible foundation.
-
As it turns out,
cmake
has a lot of knobs related torpath
; one might as well set the knobs explicitly, and in one place, so as to help anybody in the future who has some unforeseen need.
Nevertheless:
-
The reason it made sense to me to remove the explicit setting of the target property
MACOSX_RPATH
is that such an option never made much sense, anyway. -
If you still don’t agree with setting some of these variables explicitly, then perhaps they can be simply commented out. Would that be acceptable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's misleading to set variables to their default values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course, it's not misleading at all. Quite the opposite.
However, I'll choose to interpret your reply as "Look, just remove them, OK?"
cmake/modules/SetRPATH.cmake
Outdated
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) | ||
|
||
# Append non-standard external dependency directories | ||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
libcmark has no external dependencies, so this is unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course libcmark
has external dependencies.
$ ldd /path/to/installed/files/bin/cmark linux-gate.so.1 (0xb7ef2000) libcmark.so.0.31.0 => /path/to/installed/files/lib/libcmark.so.0.31.0 (0xb7e95000) libc.so.6 => /usr/lib/libc.so.6 (0xb7cbc000) /lib/ld-linux.so.2 => /usr/lib/ld-linux.so.2 (0xb7ef3000)
For example:
cd "$repo" d=/tmp/custom p=' {print} /^include\(GNUInstallDirs\)$/ { print("link_directories(\"'"$d"'\")") } ' f=CMakeLists.txt; t=$f.tmp; <"$f" awk >"$t" "$p" && mv -f "$t" "$f" git diff | cat echo '=================' i='/path/to/installed/files' make INSTALL_PREFIX="$i" install | grep 'Set runtime path'
Here are the results of running those commands:
diff --git a/CMakeLists.txt b/CMakeLists.txt index 054f8d4..22d9506 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,7 @@ include(CMakePackageConfigHelpers) include(CTest) include(GenerateExportHeader) include(GNUInstallDirs) +link_directories("/tmp/custom") if(NOT MSVC OR CMAKE_HOST_SYSTEM_NAME STREQUAL Windows) set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON) ================= -- Set runtime path of "/path/to/installed/files/bin/cmark" to "/path/to/installed/files/lib:/tmp/custom" -- Set runtime path of "/path/to/installed/files/lib/libcmark.so.0.31.0" to "/path/to/installed/files/lib:/tmp/custom"
Then:
-
Default to System Library
$ ldd "$i"/bin/cmark linux-gate.so.1 (0xb7ef2000) libcmark.so.0.31.0 => /path/to/installed/files/lib/libcmark.so.0.31.0 (0xb7e95000) libc.so.6 => /usr/lib/libc.so.6 (0xb7cbc000) /lib/ld-linux.so.2 => /usr/lib/ld-linux.so.2 (0xb7ef3000)
-
Custom Library
$ mkdir -p "$d" $ cp -a -t "$d" /usr/lib/libc.so.6 /usr/lib/libc-2.29.so $ ldd "$i"/bin/cmark linux-gate.so.1 (0xb7ef2000) libcmark.so.0.31.0 => /path/to/installed/files/lib/libcmark.so.0.31.0 (0xb7e95000) libc.so.6 => /tmp/custom/libc.so.6 (0xb7cbc000) /lib/ld-linux.so.2 => /usr/lib/ld-linux.so.2 (0xb7ef3000)
In other words:
-
By simply adding
link_directories("/tmp/custom")
to theCMakeLists.txt
, the directory/tmp/custom
got added to therpath
. -
The only reason this works is because
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
.
It's not unreasonable to think that at some point, in the future, an external dependency might be possible; maybe Nvidia will release a driver for offloading markdown parsing to the GPU. :-P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, obviously the C library is a dependency but it doesn't seem useful to support this use case. Maybe we should also consider to only set the INSTALL_RPATH target property for the cmark executable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
Shared libraries have dependencies, too.
$ ldd "$i"/lib/libcmark.so linux-gate.so.1 (0xb7fa3000) libc.so.6 => /tmp/custom/libc.so.6 (0xb7da3000) /usr/lib/ld-linux.so.2 (0xb7fa4000)
-
However, it's straightforward enough to set only
cmark
’srpath
to an unorthodox installation path, while still allowingcmake
to setlibcmark
’srpath
if it deems necessary (as described above); then, in most cases (pretty much always),libcmark
’srpath
will be the empty string, even when installed in an unorthodox location. -
The goal isn’t to support that use case.
(However, it would indeed now be supported; I mean, maybe someone wants to build against musl or something, and has put everything in a separate, non-standard hierarchy.)
Rather, the goal is to support a logical policy in general, namely:
If
cmake
is ever aware of an external dependency (or search directory) that is not covered by the standard locations, thencmake
should add the relevant path to therpath
.That sounds like a sensible policy; it sounds like a sensible default.
cmake/modules/SetRPATH.cmake
Outdated
set(CMAKE_INSTALL_RPATH "${p}" PARENT_SCOPE) | ||
endif() | ||
endfunction() | ||
SetRPATH() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if we need a separate function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would have much preferred to write:
block() set(p "${CMAKE_INSTALL_FULL_LIBDIR}") list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${p}" i) if("${i}" STREQUAL "-1") set(CMAKE_INSTALL_RPATH "${p}" PARENT_SCOPE) endif() endblock()
However, the CMake language only got [anonymous] block scoping in version 3.25
, while this project currently sets 3.7
as the minimum version; I cannot use the block()
construct.
This is why I added the comment:
# CMake 3.25 has a better scoping solution: 'block()'
My hope was that it would be a hint to some future janitor to use the block()
construct when available.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are only five relevant Iines in that block and I think it's clearer to add them directly in CMakeLists.txt without adding an additional file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, it would be much clearer to move even more stuff into their own files, but I guess we have different tastes. I will move it all into CMakeLists.txt
, as that is what you prefer.
According to CMake's documentation, MACOSX_RPATH is on already: https://cmake.org/cmake/help/latest/policy/CMP0042.html Specifically: CMake 3.0 and later prefer this property to be ON by default. [This policy] may be set by cmake_policy() or cmake_minimum_required(). If it is not set, CMake warns, and uses OLD behavior. Well, the top-level 'CMakeLists.txt' already sets the minimum version: cmake_minimum_required(VERSION 3.7) Therefore, it is unnecessary to enable it explicitly.
fbe4cf4
to
76b7e2c
Compare
I think I have hit all the buttons this time. 🤞
|
Looks good to me. |
…ibcmark.so' Before this commit, the 'cmark' executable didn't inform the dynamic linker where to look for the 'libcmark' shared object; this becomes an irritation when libcmark is installed in an unorthodox location: $ ldd /path/to/installed/files/bin/cmark linux-gate.so.1 (0xb7ed7000) libcmark.so.0.31.0 => not found libc.so.6 => /usr/lib/libc.so.6 (0xb7cf3000) /lib/ld-linux.so.2 => /usr/lib/ld-linux.so.2 (0xb7ed8000) Because of this commit, the cmark executable's 'rpath' setting (or equivalent) is set upon installation, thereby providing the required search directory: $ ldd /path/to/installed/files/bin/cmark linux-gate.so.1 (0xb7ef2000) libcmark.so.0.31.0 => /path/to/installed/files/lib/libcmark.so.0.31.0 (0xb7e95000) libc.so.6 => /usr/lib/libc.so.6 (0xb7cbc000) /lib/ld-linux.so.2 => /usr/lib/ld-linux.so.2 (0xb7ef3000) There is some intelligence behind whether rpath is set at all: * If 'CMAKE_INSTALL_RPATH' is set, then it is used; this allows the user to set a single, overriding value in the expected way. * Otherwise, the base case rpath is determined by the following: "${CMAKE_INSTALL_FULL_LIBDIR}" If that path is a standard location, then the base case rpath is the empty string; otherwise, the base case rpath is that path. * The cmark executable's rpath is set to the base case rpath. * Currently, libcmark's rpath is set to the empty string. * In addition, cmake has been instructed to add to each target's rpath any directories that it thinks might contain potential dependencies from outside the project; most of the time, there will be none, and so nothing will be added. Of course, this will only help on a system that supports an rpath feature known to cmake; for example, Windows has no such feature, and so all of this will presumably be ignored when building under that system.
76b7e2c
to
10e06da
Compare
I pushed a slightly modified version; as described in the commit log:
Essentially: diff --git a/CMakeLists.txt b/CMakeLists.txt index 9170bf3..21c1763 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,9 @@ set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) set(CMAKE_INCLUDE_CURRENT_DIR ON) +if (DEFINED CMAKE_INSTALL_RPATH) + set(Base_rpath "${CMAKE_INSTALL_RPATH}") +else() if(BUILD_SHARED_LIBS) set(p "${CMAKE_INSTALL_FULL_LIBDIR}") list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${p}" i) @@ -76,6 +79,7 @@ if(BUILD_SHARED_LIBS) set(Base_rpath "${p}") endif() endif() +endif() # Append non-standard external dependency directories, if any. set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) |
Sorry, I forgot about this. @nwellnhof if it still looks good to you I will merge this. |
Looks good. |
Before this commit, the
cmark
executable didn’t inform the dynamic linker where to look for thelibcmark
shared object; this becomes an irritation whenlibcmark
is installed in an unorthodox location:Because of this commit, the
cmark
executable’srpath
[0][1] setting (or equivalent) is set upon installation, thereby providing the required search directory:In particular,
rpath
is set to the following value:Of course, this will only help on a system that supports an
rpath
feature known tocmake
. Windows has no such feature anyway, apparently.