-
Notifications
You must be signed in to change notification settings - Fork 205
/
Copy pathrpath_args.py
executable file
·168 lines (140 loc) · 6.21 KB
/
rpath_args.py
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#!/usr/bin/env python
##
# Copyright 2016-2025 Ghent University
#
# This file is part of EasyBuild,
# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
# with support of Ghent University (http://ugent.be/hpc),
# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
# Flemish Research Foundation (FWO) (http://www.fwo.be/en)
# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
#
# https://github.com/easybuilders/easybuild
#
# EasyBuild is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation v2.
#
# EasyBuild is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>.
##
"""
Utility script used by RPATH wrapper script;
output is statements that define the following environment variables
* $CMD_ARGS: new list of command line arguments to pass
* $RPATH_ARGS: command line option to specify list of paths to RPATH
author: Kenneth Hoste (HPC-UGent)
"""
import os
import re
import sys
def is_new_existing_path(new_path, paths):
"""
Check whether specified path exists and is a new path compared to provided list of paths.
"""
# assume path is new, until proven otherwise
res = True
if os.path.exists(new_path):
for path in paths:
if os.path.exists(path) and os.path.samefile(new_path, path):
res = False
break
else:
# path doesn't exist
res = False
return res
cmd = sys.argv[1]
rpath_filter = sys.argv[2]
rpath_include = sys.argv[3]
args = sys.argv[4:]
# determine whether or not to use -Wl to pass options to the linker based on name of command
if cmd in ['ld', 'ld.gold', 'ld.bfd']:
flag_prefix = ''
else:
flag_prefix = '-Wl,'
rpath_filter = rpath_filter.split(',')
if rpath_filter:
rpath_filter = re.compile('^%s$' % '|'.join(rpath_filter))
else:
rpath_filter = None
if rpath_include:
rpath_include = rpath_include.split(',')
else:
rpath_include = []
add_rpath_args = True
cmd_args, cmd_args_rpath = [], []
rpath_lib_paths = []
# process list of original command line arguments
idx = 0
while idx < len(args):
arg = args[idx]
# if command is run in 'version check' mode, make sure we don't include *any* -rpath arguments
if arg in ['-v', '-V', '--version', '-dumpversion']:
add_rpath_args = False
cmd_args.append(arg)
# compiler options like "-x c++header" imply no linking is done (similar to -c),
# so then we must not inject -Wl,-rpath option since they *enable* linking;
# see https://github.com/easybuilders/easybuild-framework/issues/3371
elif arg == '-x':
idx_next = idx + 1
if idx_next < len(args) and args[idx_next] in ['c-header', 'c++-header']:
add_rpath_args = False
cmd_args.append(arg)
# FIXME: support to hard inject additional library paths?
# FIXME: support to specify list of path prefixes that should not be RPATH'ed into account?
# FIXME skip paths in /tmp, build dir, etc.?
# handle -L flags, inject corresponding -rpath flag
elif arg.startswith('-L'):
# take into account that argument to -L may be separated with one or more spaces...
if arg == '-L':
# actual library path is next argument when arg='-L'
idx += 1
lib_path = args[idx]
else:
lib_path = arg[2:]
# don't RPATH in empty or relative paths, or paths that are filtered out;
# linking relative paths via RPATH doesn't make much sense,
# and it can also break the build because it may result in reordering lib paths
if lib_path and os.path.isabs(lib_path) and (rpath_filter is None or not rpath_filter.match(lib_path)):
# avoid using duplicate library paths
if is_new_existing_path(lib_path, rpath_lib_paths):
# inject -rpath flag in front for every -L with an absolute path,
rpath_lib_paths.append(lib_path)
cmd_args_rpath.append(flag_prefix + '-rpath=%s' % lib_path)
# always retain -L flag (without reordering!)
cmd_args.append('-L%s' % lib_path)
# replace --enable-new-dtags with --disable-new-dtags if it's used;
# --enable-new-dtags would result in copying rpath to runpath,
# meaning that $LD_LIBRARY_PATH is taken into account again;
# --enable-new-dtags is not removed but replaced to prevent issues when linker flag is forwarded from the compiler
# to the linker with an extra prefixed flag (either -Xlinker or -Wl,).
# In that case, the compiler would erroneously pass the next random argument to the linker.
elif arg == flag_prefix + '--enable-new-dtags':
cmd_args.append(flag_prefix + '--disable-new-dtags')
else:
cmd_args.append(arg)
idx += 1
# also inject -rpath options for all entries in $LIBRARY_PATH,
# unless they are there already
for lib_path in os.getenv('LIBRARY_PATH', '').split(os.pathsep):
if lib_path and os.path.isabs(lib_path) and (rpath_filter is None or not rpath_filter.match(lib_path)):
# avoid using duplicate library paths
if is_new_existing_path(lib_path, rpath_lib_paths):
rpath_lib_paths.append(lib_path)
cmd_args_rpath.append(flag_prefix + '-rpath=%s' % lib_path)
if add_rpath_args:
# try to make sure that RUNPATH is not used by always injecting --disable-new-dtags
cmd_args_rpath.insert(0, flag_prefix + '--disable-new-dtags')
# add -rpath options for paths listed in rpath_include
cmd_args_rpath = [flag_prefix + '-rpath=%s' % inc for inc in rpath_include] + cmd_args_rpath
# add -rpath flags in front
cmd_args = cmd_args_rpath + cmd_args
# wrap all arguments into single quotes to avoid further bash expansion
cmd_args = ["'%s'" % a.replace("'", "''") for a in cmd_args]
# output: statement to define $CMD_ARGS and $RPATH_ARGS
print("CMD_ARGS=(%s)" % ' '.join(cmd_args))