about summary refs log tree commit diff
path: root/nixpkgs/pkgs/development/libraries/gobject-introspection/absolute_shlib_path.patch
blob: e2525d833f8f58788c3fd16e87056b51d6397eb7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
--- a/giscanner/scannermain.py
+++ b/giscanner/scannermain.py
@@ -101,6 +101,39 @@
     return group
 
 
+def _get_default_fallback_libpath():
+    # Newer multiple-output-optimized stdenv has an environment variable
+    # $outputLib which in turn specifies another variable which then is used as
+    # the destination for the library contents (${!outputLib}/lib).
+    store_path = os.environ.get(os.environ.get("outputLib")) if "outputLib" in os.environ else None
+    if store_path is None:
+        outputs = os.environ.get("outputs", "out").split()
+        if "lib" in outputs:
+            # For multiple output derivations let's try whether there is a $lib
+            # environment variable and use that as the base store path.
+            store_path = os.environ.get("lib")
+        elif "out" in outputs:
+            # Otherwise we have a single output derivation, so the libraries
+            # most certainly will end up in "$out/lib".
+            store_path = os.environ.get("out")
+
+    if store_path is not None:
+        # Even if we have a $lib as output, there still should be a $lib/lib
+        # directory.
+        return os.path.join(store_path, 'lib')
+    else:
+        # If we haven't found a possible scenario, let's return an empty string
+        # so that the shared library won't be prepended with a path.
+        #
+        # Note that this doesn't mean that all hope is lost, because after all
+        # we can still use --fallback-library-path to set one.
+        #
+        # Also, we're not returning None, because that would make it very
+        # difficult to disable adding fallback paths altogether using something
+        # like: --fallback-library-path=""
+        return ""
+
+
 def _get_option_parser():
     parser = optparse.OptionParser('%prog [options] sources',
                                    version='%prog ' + giscanner.__version__)
@@ -211,6 +244,10 @@
     parser.add_option("", "--filelist",
                       action="store", dest="filelist", default=[],
                       help="file containing headers and sources to be scanned")
+    parser.add_option("", "--fallback-library-path",
+                      action="store", dest="fallback_libpath",
+                      default=_get_default_fallback_libpath(),
+                      help="Path to prepend to unknown shared libraries")
 
     group = get_preprocessor_option_group(parser)
     parser.add_option_group(group)
--- a/giscanner/shlibs.py
+++ b/giscanner/shlibs.py
@@ -62,6 +62,12 @@
     $""" % re.escape(library_name), re.VERBOSE)
 
 
+def _ldd_library_nix_pattern(library_name):
+    nix_store_dir = re.escape('@nixStoreDir@'.rstrip('/'))
+    pattern = r'(%s(?:/[^/]*)+lib%s[^A-Za-z0-9_-][^\s\(\)]*)'
+    return re.compile(pattern % (nix_store_dir, re.escape(library_name)))
+
+
 # This is a what we do for non-la files. We assume that we are on an
 # ELF-like system where ldd exists and the soname extracted with ldd is
 # a filename that can be opened with dlopen().
@@ -110,17 +116,16 @@ def _resolve_non_libtool(options, binary, libraries):
         if isinstance(output, bytes):
             output = output.decode("utf-8", "replace")
 
-        # Use absolute paths on OS X to conform to how libraries are usually
-        # referenced on OS X systems, and file names everywhere else.
-        basename = platform.system() != 'Darwin'
-        return resolve_from_ldd_output(libraries, output, basename=basename)
+        # Never strip away absolute paths in Nix
+        basename = False
+        return resolve_from_ldd_output(libraries, output, basename=basename, fallback_libpath=options.fallback_libpath)
 
 
-def resolve_from_ldd_output(libraries, output, basename=False):
+def resolve_from_ldd_output(libraries, output, basename=False, fallback_libpath=""):
     patterns = {}
     for library in libraries:
         if not os.path.isfile(library):
-            patterns[library] = _ldd_library_pattern(library)
+            patterns[library] = (_ldd_library_pattern(library), _ldd_library_nix_pattern(library))
     if len(patterns) == 0:
         return []
 
@@ -129,11 +134,14 @@ def resolve_from_ldd_output(libraries, output, basename=False):
         if line.endswith(':'):
             continue
         for word in line.split():
-            for library, pattern in patterns.items():
-                m = pattern.match(word)
+            for library, (pattern, nix_pattern) in patterns.items():
+                if line.find('@nixStoreDir@') != -1:
+                    m = nix_pattern.match(word)
+                else:
+                    m = pattern.match(word)
                 if m:
                     del patterns[library]
-                    shlibs.append(_sanitize_install_name(m.group()))
+                    shlibs.append(os.path.join(fallback_libpath, _sanitize_install_name(m.group())))
                     break
 
     if len(patterns) > 0:
--- a/giscanner/utils.py
+++ b/giscanner/utils.py
@@ -116,17 +116,11 @@
     if dlname is None:
         return None
 
-    # Darwin uses absolute paths where possible; since the libtool files never
-    # contain absolute paths, use the libdir field
-    if platform.system() == 'Darwin':
-        dlbasename = os.path.basename(dlname)
-        libdir = _extract_libdir_field(la_file)
-        if libdir is None:
-            return dlbasename
-        return libdir + '/' + dlbasename
-    # From the comments in extract_libtool(), older libtools had
-    # a path rather than the raw dlname
-    return os.path.basename(dlname)
+    dlbasename = os.path.basename(dlname)
+    libdir = _extract_libdir_field(la_file)
+    if libdir is None:
+        return dlbasename
+    return libdir + '/' + dlbasename
 
 
 def extract_libtool(la_file):