scons: Add a convenience method to set RPATH for local libraries.
authorGabe Black <gabeblack@google.com>
Thu, 21 Feb 2019 01:43:15 +0000 (17:43 -0800)
committerGabe Black <gabeblack@google.com>
Thu, 21 Feb 2019 22:37:21 +0000 (22:37 +0000)
When linking in a dynamic library which is in the gem5 build directory,
it's useful to set RPATH so that you don't have to set LD_LIBRARY_PATH
when you run gem5 so that the dynamic linker can find it.

Since it's tricky and not entirely obvious how to set up those paths
correctly, this change adds a small convenience function which does
that for you. It also handles situations where the same dynamic
library may be linked into different binaries in different directories
which each need a different relative RPATH. It does that by letting the
environment for each binary set a construction variable which says
how to get from that particular binary back to the build directory.
This helper method then sets RPATH to start at $ORIGIN (the binary),
to follow that relative path to the variant build directory, and then
the per-library but not per-binary path to the library's directory.

This change also adds the -z origin linker flag which makes the linker
handle $ORIGIN properly.

Change-Id: I45f4d72cd14396a73e0b963cea6a39d9bfb7f984
Reviewed-on: https://gem5-review.googlesource.com/c/16566
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Gabe Black <gabeblack@google.com>

SConstruct
src/SConscript

index 5c8f64956482ff10a16f98cfa672d8f70205b0f6..026327c2c1b6c543589aaa71160884e2e555e66b 100755 (executable)
@@ -1072,6 +1072,27 @@ partial_shared_builder = Builder(action=SCons.Defaults.ShLinkAction,
 main.Append(BUILDERS = { 'PartialShared' : partial_shared_builder,
                          'PartialStatic' : partial_static_builder })
 
+def add_local_rpath(env, *targets):
+    '''Set up an RPATH for a library which lives in the build directory.
+
+    The construction environment variable BIN_RPATH_PREFIX should be set to
+    the relative path of the build directory starting from the location of the
+    binary.'''
+    for target in targets:
+        target = env.Entry(target)
+        if not target.isdir():
+            target = target.dir
+        relpath = os.path.relpath(target.abspath, env['BUILDDIR'])
+        components = [
+            '\\$$ORIGIN',
+            '${BIN_RPATH_PREFIX}',
+            relpath
+        ]
+        env.Append(RPATH=[env.Literal(os.path.join(*components))])
+
+main.Append(LINKFLAGS=Split('-z origin'))
+main.AddMethod(add_local_rpath, 'AddLocalRPATH')
+
 # builds in ext are shared across all configs in the build root.
 ext_dir = abspath(joinpath(str(main.root), 'ext'))
 ext_build_dirs = []
index 81b6cd3f1d65814e0b9514c945bcaff96f9e786b..ef7e670ab8beb8e64c6f95fc854619bc1363cf09 100644 (file)
@@ -449,6 +449,10 @@ class Executable(object):
         if objs is None:
             objs = self.srcs_to_objs(env, self.sources)
 
+        env = env.Clone()
+        env['BIN_RPATH_PREFIX'] = os.path.relpath(
+                env['BUILDDIR'], self.path(env).dir.abspath)
+
         if env['STRIP_EXES']:
             stripped = self.path(env)
             unstripped = env.File(str(stripped) + '.unstripped')