Skip to content

Commit 6d38993

Browse files
committed
linkers: don't include absolue RPATH on cross-compiling
There is currently a reproducible problem when cross-compiling with the inclusion of external shared library RPATH entry. Meson normally includes RPATH entry to permit the usage of the tool in the build process and later removes it on the intall phase. This might be ok and permits creating reproducible build to some degree when building on host (as we can expect the shared library are always placed on a standard directory path and have a consistent RPATH) This doesn't apply for cross-compilation scenario where the shared library might be provided from an arbritrary directory to be later packed in the final system (for example a squashfs image) On top of this on cross-compilation on 99% of the scenario, it's not really possible to run the just built tool for build usage as it probably target a different arch. To permit building REAL reproducible binary, add extra logic to skip the inclusion of such library path in RPATH if we detect a cross-compilation scenario and limit the inclusion of library path in RPATH only to relative path (expected to be the ones specific to the building binary/internal shared library) Signed-off-by: Christian Marangi <[email protected]>
1 parent b527ed5 commit 6d38993

File tree

1 file changed

+40
-17
lines changed

1 file changed

+40
-17
lines changed

mesonbuild/linkers/linkers.py

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -561,11 +561,11 @@ def get_output_args(self, target: str) -> T.List[str]:
561561
def get_linker_always_args(self) -> T.List[str]:
562562
return ['-r']
563563

564-
def prepare_rpaths(raw_rpaths: T.Tuple[str, ...], build_dir: str, from_dir: str) -> T.List[str]:
564+
def prepare_rpaths(env: Environment, raw_rpaths: T.Tuple[str, ...], build_dir: str, from_dir: str) -> T.List[str]:
565565
# The rpaths we write must be relative if they point to the build dir,
566566
# because otherwise they have different length depending on the build
567567
# directory. This breaks reproducible builds.
568-
internal_format_rpaths = [evaluate_rpath(p, build_dir, from_dir) for p in raw_rpaths]
568+
internal_format_rpaths = [evaluate_rpath(env, p, build_dir, from_dir) for p in raw_rpaths]
569569
ordered_rpaths = order_rpaths(internal_format_rpaths)
570570
return ordered_rpaths
571571

@@ -582,11 +582,16 @@ def order_rpaths(rpath_list: T.List[str]) -> T.List[str]:
582582
return sorted(rpath_list, key=os.path.isabs)
583583

584584

585-
def evaluate_rpath(p: str, build_dir: str, from_dir: str) -> str:
585+
def evaluate_rpath(env: Environment, p: str, build_dir: str, from_dir: str) -> str:
586586
if p == from_dir:
587587
return '' # relpath errors out in this case
588588
elif os.path.isabs(p):
589-
return p # These can be outside of build dir.
589+
# Skip external library for cross-compiling build to
590+
# permit creation of reproducible builds.
591+
if env.is_cross_build():
592+
return ''
593+
else:
594+
return p # These can be outside of build dir.
590595
else:
591596
return os.path.relpath(os.path.join(build_dir, p), os.path.join(build_dir, from_dir))
592597

@@ -714,7 +719,7 @@ def build_rpath_args(self, env: Environment, build_dir: str, from_dir: str,
714719
return ([], set())
715720
args: T.List[str] = []
716721
origin_placeholder = '$ORIGIN'
717-
processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
722+
processed_rpaths = prepare_rpaths(env, rpath_paths, build_dir, from_dir)
718723
# Need to deduplicate rpaths, as macOS's install_name_tool
719724
# is *very* allergic to duplicate -delete_rpath arguments
720725
# when calling depfixer on installation.
@@ -724,9 +729,12 @@ def build_rpath_args(self, env: Environment, build_dir: str, from_dir: str,
724729
rpath_dirs_to_remove.add(p.encode('utf8'))
725730
# Build_rpath is used as-is (it is usually absolute).
726731
if target.build_rpath != '':
727-
all_paths.add(target.build_rpath)
728-
for p in target.build_rpath.split(':'):
729-
rpath_dirs_to_remove.add(p.encode('utf8'))
732+
paths = target.build_rpath.split(':')
733+
for p in paths:
734+
# Only include relative paths for cross builds
735+
if not env.is_cross_build() or not os.path.isabs(p):
736+
all_paths.add(p)
737+
rpath_dirs_to_remove.add(p.encode('utf8'))
730738
if extra_paths:
731739
all_paths.update(extra_paths)
732740

@@ -886,10 +894,14 @@ def build_rpath_args(self, env: Environment, build_dir: str, from_dir: str,
886894
# @loader_path is the equivalent of $ORIGIN on macOS
887895
# https://stackoverflow.com/q/26280738
888896
origin_placeholder = '@loader_path'
889-
processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
897+
processed_rpaths = prepare_rpaths(env, rpath_paths, build_dir, from_dir)
890898
all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths])
891899
if target.build_rpath != '':
892-
all_paths.update(target.build_rpath.split(':'))
900+
paths = target.build_rpath.split(':')
901+
for p in paths:
902+
# Only include relative paths for cross builds
903+
if not env.is_cross_build() or not os.path.isabs(p):
904+
all_paths.add(p)
893905
if extra_paths:
894906
all_paths.update(extra_paths)
895907
for rp in all_paths:
@@ -1268,10 +1280,14 @@ def build_rpath_args(self, env: Environment, build_dir: str, from_dir: str,
12681280
return ([], set())
12691281
args: T.List[str] = []
12701282
origin_placeholder = '$ORIGIN'
1271-
processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
1283+
processed_rpaths = prepare_rpaths(env, rpath_paths, build_dir, from_dir)
12721284
all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths])
12731285
if target.build_rpath != '':
1274-
all_paths.add(target.build_rpath)
1286+
paths = target.build_rpath.split(':')
1287+
for p in paths:
1288+
# Only include relative paths for cross builds
1289+
if not env.is_cross_build() or not os.path.isabs(p):
1290+
all_paths.add(p)
12751291
if extra_paths:
12761292
all_paths.update(extra_paths)
12771293
for rp in all_paths:
@@ -1524,15 +1540,18 @@ def build_rpath_args(self, env: Environment, build_dir: str, from_dir: str,
15241540
rpath_paths = target.determine_rpath_dirs()
15251541
if not rpath_paths and not target.install_rpath and not target.build_rpath and not extra_paths:
15261542
return ([], set())
1527-
processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir)
1543+
processed_rpaths = prepare_rpaths(env, rpath_paths, build_dir, from_dir)
15281544
all_paths = mesonlib.OrderedSet([os.path.join('$ORIGIN', p) for p in processed_rpaths])
15291545
rpath_dirs_to_remove: T.Set[bytes] = set()
15301546
for p in all_paths:
15311547
rpath_dirs_to_remove.add(p.encode('utf8'))
15321548
if target.build_rpath != '':
1533-
all_paths.add(target.build_rpath)
1534-
for p in target.build_rpath.split(':'):
1535-
rpath_dirs_to_remove.add(p.encode('utf8'))
1549+
paths = target.build_rpath.split(':')
1550+
for p in paths:
1551+
# Only include relative paths for cross builds
1552+
if not env.is_cross_build() or not os.path.isabs(p):
1553+
all_paths.add(p)
1554+
rpath_dirs_to_remove.add(p.encode('utf8'))
15361555
if extra_paths:
15371556
all_paths.update(extra_paths)
15381557

@@ -1598,7 +1617,11 @@ def build_rpath_args(self, env: Environment, build_dir: str, from_dir: str,
15981617
if target.install_rpath != '':
15991618
all_paths.add(target.install_rpath)
16001619
if target.build_rpath != '':
1601-
all_paths.add(target.build_rpath)
1620+
paths = target.build_rpath.split(':')
1621+
for p in paths:
1622+
# Only include relative paths for cross builds
1623+
if not env.is_cross_build() or not os.path.isabs(p):
1624+
all_paths.add(p)
16021625
for p in target.determine_rpath_dirs():
16031626
all_paths.add(os.path.join(build_dir, p))
16041627
# We should consider allowing the $LIBPATH environment variable

0 commit comments

Comments
 (0)