Skip to content

Commit ea339fa

Browse files
committed
Merge branch 'meson-rpath' into 'meson'
2 parents f192a39 + a0d893e commit ea339fa

File tree

3 files changed

+145
-17
lines changed

3 files changed

+145
-17
lines changed

meson.build

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ portname = host_system
167167

168168
exesuffix = '' # overridden below where necessary
169169
dlsuffix = '.so' # overridden below where necessary
170+
rpath_origin = '$ORIGIN'
170171
library_path_var = 'LD_LIBRARY_PATH'
171172

172173
# Format of file to control exports from libraries, and how to pass them to
@@ -222,6 +223,7 @@ elif host_system == 'cygwin'
222223
elif host_system == 'darwin'
223224
dlsuffix = '.dylib'
224225
library_path_var = 'DYLD_LIBRARY_PATH'
226+
rpath_origin = '@loader_path'
225227

226228
export_file_format = 'darwin'
227229
export_fmt = '-exported_symbols_list=@0@'
@@ -260,8 +262,16 @@ elif host_system == 'netbsd'
260262
# LDFLAGS.
261263
ldflags += ['-Wl,-z,now', '-Wl,-z,relro']
262264

265+
# netbsd patched their meson in a broken way:
266+
# https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=56959
267+
# until there's a way out of that, disable rpath_origin
268+
rpath_origin = ''
269+
263270
elif host_system == 'openbsd'
264-
# you're ok
271+
# openbsd's $ORIGIN doesn't use an absolute path to the binary, but argv[0]
272+
# (i.e. absolute when invoked with an absolute name, but e.g. not absolute
273+
# when invoked via PATH search).
274+
rpath_origin = ''
265275

266276
elif host_system == 'sunos'
267277
portname = 'solaris'
@@ -273,6 +283,7 @@ elif host_system == 'windows'
273283
exesuffix = '.exe'
274284
dlsuffix = '.dll'
275285
library_path_var = ''
286+
rpath_origin = ''
276287

277288
export_file_format = 'win'
278289
export_file_suffix = 'def'
@@ -2596,25 +2607,41 @@ bin_install_rpaths = []
25962607
lib_install_rpaths = []
25972608
mod_install_rpaths = []
25982609

2599-
2600-
# Don't add rpaths on darwin for now - as long as only absolute references to
2601-
# libraries are needed, absolute LC_ID_DYLIB ensures libraries can be found in
2602-
# their final destination.
2610+
# Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2611+
#
2612+
# Not needed on darwin, even if we use relative rpaths for our own libraries,
2613+
# as the install_name of libraries in extra_lib_dirs will point to their
2614+
# location anyway.
26032615
if host_system != 'darwin'
2616+
bin_install_rpaths += postgres_lib_d
2617+
lib_install_rpaths += postgres_lib_d
2618+
mod_install_rpaths += postgres_lib_d
2619+
endif
2620+
2621+
# If the host can form relative rpaths, use that to make the installation
2622+
# properly relocatable
2623+
if rpath_origin != ''
2624+
# PG binaries might need to link to libpq, use relative path to reference
2625+
bin_to_lib = run_command(python, files('src/tools/relpath.py'),
2626+
dir_bin, dir_lib, check: true).stdout().strip()
2627+
bin_install_rpaths += rpath_origin / bin_to_lib
2628+
2629+
# PG extensions might need to link to libpq, use relative path to reference
2630+
# (often just .)
2631+
mod_to_lib = run_command(python, files('src/tools/relpath.py'),
2632+
dir_lib_pkg, dir_lib, check: true).stdout().strip()
2633+
mod_install_rpaths += rpath_origin / mod_to_lib
2634+
2635+
test_use_library_path_var = false
2636+
else
2637+
26042638
# Add absolute path to libdir to rpath. This ensures installed binaries /
26052639
# libraries find our libraries (mainly libpq).
26062640
bin_install_rpaths += dir_prefix / dir_lib
26072641
lib_install_rpaths += dir_prefix / dir_lib
26082642
mod_install_rpaths += dir_prefix / dir_lib
26092643

2610-
# Add extra_lib_dirs to rpath. This ensures we find libraries we depend on.
2611-
#
2612-
# Not needed on darwin even if we use relative rpaths for our own libraries,
2613-
# as the install_name of libraries in extra_lib_dirs will point to their
2614-
# location anyway.
2615-
bin_install_rpaths += postgres_lib_d
2616-
lib_install_rpaths += postgres_lib_d
2617-
mod_install_rpaths += postgres_lib_d
2644+
test_use_library_path_var = true
26182645
endif
26192646

26202647

@@ -2938,6 +2965,14 @@ above, or by running configure and then make maintainer-clean.
29382965
endif
29392966

29402967

2968+
# To make MacOS installation work without a prior make install, even with SIP
2969+
# enabled, make rpaths relative after installation. This also makes the
2970+
# installation relocatable.
2971+
if host_system == 'darwin'
2972+
meson.add_install_script('src/tools/relativize_shared_library_references')
2973+
endif
2974+
2975+
29412976

29422977
###############################################################
29432978
# Install targets
@@ -3062,10 +3097,9 @@ test_env.set('REGRESS_SHLIB', regress_module.full_path())
30623097
# Export PG_TEST_EXTRA so it can be checked in individual tap tests.
30633098
test_env.set('PG_TEST_EXTRA', get_option('PG_TEST_EXTRA'))
30643099

3065-
# Add the temporary installation to the library search path on platforms where
3066-
# that works (everything but windows, basically). On windows everything
3067-
# library-like gets installed into bindir, solving that issue.
3068-
if library_path_var != ''
3100+
# On platforms without $ORIGIN support we need to add the temporary
3101+
# installation to the library search path.
3102+
if test_use_library_path_var and library_path_var != ''
30693103
test_env.prepend(library_path_var, test_install_location / get_option('libdir'))
30703104
endif
30713105

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#!/usr/bin/env python3
2+
# -*-python-*-
3+
4+
# This script updates a macos postgres installation to reference all internal
5+
# shared libraries using rpaths, leaving absolute install_names in the
6+
# libraries themselves intact.
7+
8+
import os
9+
import sys
10+
import json
11+
import subprocess
12+
import shutil
13+
14+
15+
def installed_path(destdir, path):
16+
if destdir is not None:
17+
return f'{destdir}{path}'
18+
else:
19+
return path
20+
21+
22+
def collect_information():
23+
shared_libraries = []
24+
executables = []
25+
shared_modules = []
26+
27+
meson_info_p = os.path.join(build_root, 'meson-info')
28+
targets = json.load(
29+
open(os.path.join(meson_info_p, 'intro-targets.json')))
30+
installed = json.load(
31+
open(os.path.join(meson_info_p, 'intro-installed.json')))
32+
33+
for target in targets:
34+
if not target['installed']:
35+
continue
36+
37+
filenames = target['filename']
38+
39+
if target['type'] == 'shared library':
40+
assert(len(filenames) == 1)
41+
filename = filenames[0]
42+
43+
shared_libraries.append(installed[filename])
44+
45+
if target['type'] == 'executable':
46+
assert(len(filenames) == 1)
47+
filename = filenames[0]
48+
executables.append(installed[filename])
49+
50+
if target['type'] == 'shared module':
51+
assert(len(filenames) == 1)
52+
filename = filenames[0]
53+
shared_modules.append(installed[filename])
54+
55+
return shared_libraries, executables, shared_modules
56+
57+
58+
def patch_references(destdir, shared_libraries, executables, shared_modules):
59+
install_name_tool = [shutil.which('install_name_tool')]
60+
61+
for lib in shared_libraries:
62+
libname = os.path.basename(lib)
63+
libpath = installed_path(destdir, lib)
64+
newref = f'@rpath/{libname}'
65+
66+
for patch in shared_modules + executables:
67+
patchpath = installed_path(destdir, patch)
68+
69+
# print(f'in {patchpath} replace reference to {libpath} with {newref}')
70+
if not os.path.exists(patchpath):
71+
print(f"path {patchpath} doesn't exist", file=sys.stderr)
72+
sys.exit(1)
73+
74+
cmd = install_name_tool + ['-change', lib, newref, patchpath]
75+
subprocess.check_call(cmd)
76+
77+
78+
if __name__ == '__main__':
79+
build_root = os.environ['MESON_BUILD_ROOT']
80+
destdir = os.environ.get('DESTDIR', None)
81+
82+
print(f'making references to shared libraries relative, destdir is {destdir}',
83+
file=sys.stderr)
84+
85+
shared_libraries, executables, shared_modules = collect_information()
86+
patch_references(destdir, shared_libraries, executables, shared_modules)
87+
88+
sys.exit(0)

src/tools/relpath.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env python3
2+
3+
import os
4+
import sys
5+
6+
print(os.path.relpath(sys.argv[2], start=sys.argv[1]))

0 commit comments

Comments
 (0)