Repository navigation
Expand file tree
/
Copy pathdylink.sh
More file actions
272 lines (256 loc) · 9.1 KB
/
Copy pathdylink.sh
File metadata and controls
272 lines (256 loc) · 9.1 KB
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
########################################################################
# #
# This file is part of the ksh 93u+m package #
# Copyright (c) 2021-2026 Contributors to ksh 93u+m #
# and is licensed under the #
# Eclipse Public License, Version 2.0 #
# #
# A copy of the License is available at #
# https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html #
# (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) #
# #
# Martijn Dekker <martijn@inlv.org> #
# Johnothan King <johnothanking@protonmail.com> #
# #
########################################################################
# Dynamic library linking tool for ksh 93u+m and supporting libraries.
# Called from **/Mamfile.
case ${ZSH_VERSION+z} in
z) emulate ksh ;;
*) (command set -o posix) 2>/dev/null && set -o posix ;;
esac
set -o noglob # avoid pathname expansion interfering with field splitting
CCn='
' # newline
case $(getopts '[-][123:xyz]' opt --xyz 2>/dev/null; echo 0$opt) in
0123) optstring=$'
[-?
@(#)$Id: dylink (ksh 93u+m) 2026-09-14 $
]
[-author?Martijn Dekker <martijn@inlv.org>]
[-copyright?(c) 2021-2026 Contributors to ksh 93u+m]
[-license?https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html]
[+NAME?dylink - dynamic library linking tool for ksh 93u+m and supporting libraries]
[+DESCRIPTION?The \bdylink\b command is called from \b**/Mamfile\b to build
dynamically linked shared libraries and executables that use them. It
detects whether dynamic libraries are supported on the current system,
and if so, invokes the C compiler and linker to produce a dynamic
library or link an executable against one. Each non-option argument is
a *.o object file built by the compiler.]
[+?With \b-Q\b, \bdylink\b only queries whether dynamic libraries are
supported on the current system; no other options or arguments may be
given.]
[+?Without \b-Q\b, either \b-e\b or \b-m\b must be given (but not both) to
specify what should be built.]
[Q?Query support for dynamic libraries on this system. Exits 0 if supported,
1 if not. Must be used alone.]
[e]:[exec-file?Link \aexec-file\a as an executable against the dynamic
libraries specified by \b-l\b.]
[m]:[module-name?Build a dynamic library named \amodule-name\a. Requires
\b-v\b, \b-p\b, and \b-s\b.]
[l]:[libname?Link against \blib\b\alibname\a. To link against multiple
libraries, specify this option multiple times.]
[v]:[version?The dynamic library version for the file name, e.g. \b6.0\b.
Used with \b-m\b.]
[p]:[prefix?The operating system'\'$'s dynamic library file name prefix.
Must be \blib\b or empty. Used with \b-m\b.]
[s]:[suffix?The dynamic library file name suffix, e.g. \b.so\b or
\b.dylib\b. Used with \b-m\b.]
[ objectfile ... ]
[+SEE ALSO?\bmamake\b(1), \bmkdeps\b(1)]\n'
;;
*) optstring='Qe:m:l:v:p:s:';
;;
esac
note()
{
printf "${0##*/}: %s\\n" "$@" >&2
}
err_out()
{
note "$@"
exit 3
}
do_link()
{
target=$dest_dir/$1
shift
test -e "$target" && rm -f "$target"
(
PS4="[dylink] $PS4"
set -o xtrace
# why pass CCFLAGS here? because it *might* have a flag like -m64 that the linker also needs
${CC:-cc} $CCFLAGS $LDFLAGS -o "$target" "$@"
) || exit
}
# Basic sanity check.
case ${HOSTTYPE:+H}${INSTALLROOT:+I} in
HI) ;;
*) err_out "Required environment missing"
;;
esac
# Parse options.
unset opt_query exec_file module_name l_flags version prefix suffix
deproot=$INSTALLROOT/lib/lib
while getopts "$optstring" opt
do case $opt in
Q) opt_query=y # query support for dynamic libraries on this system
;;
e) exec_file=$OPTARG
;;
m) test -n "${module_name+m}" && err_out "-m cannot be used more than once"
test -n "${l_flags+l}" && err_out "-m cannot be used after -l"
test -f "$OPTARG.req" || err_out "$OPTARG.req not found -- generate it with mkreq(1)"
l_flags=$(sed 1d "$OPTARG.req") || exit
module_name=$OPTARG
;;
l) if test -f "$OPTARG.req"
then l_flags=${l_flags:+$l_flags$CCn}$(cat "$OPTARG.req") || exit
elif test -f "$deproot/$OPTARG"
then l_flags=${l_flags:+$l_flags$CCn}$(cat "$deproot/$OPTARG") || exit
else l_flags=${l_flags:+$l_flags$CCn}\ -l$OPTARG
fi
;;
v) version=$OPTARG # this should be like 6.0
;;
p) prefix=$OPTARG # this should be 'lib' or empty
;;
s) suffix=$OPTARG # this should be like .dylib or .so
;;
'?') exit 2
;;
*) err_out "Internal error (getopts)"
;;
esac
done
shift $((OPTIND - 1))
# Validate options.
case ${opt_query+Q}${exec_file:+e}${module_name:+m}${l_flags+l}${version+v}${prefix+p}${suffix+s} in
Q?*) err_out "-Q cannot be used with other options" ;;
Q) test "$#" -gt 0 && err_out "-Q cannot be used with arguments" ;;
e | e[!m]* | m*)
;;
*) err_out "Either -e or -m should be specified" ;;
esac
case ${module_name:+m}${prefix+p}${suffix+s}${version:+v} in
'' | mpsv )
case $prefix in
'' | lib)
;;
*) err_out "the -p option value must be 'lib' or ''"
;;
esac
;;
msv) note "warning: -p not given; assuming -p lib for backward compat"
prefix=lib
;;
*) err_out "-m requires -v/-p/-s and vice versa"
;;
esac
# Check if building dynamic libraries was disabled.
case ${AST_NO_DYLIB+N}${opt_query+Q} in
NQ) exit 1
;;
N) note "Building dynamic libraries was disabled; skipping"
exit 0 # continue build
;;
esac
# Check for supported system.
case $HOSTTYPE in
android.* | darwin.* | dragonflybsd.* | freebsd* | haiku.* | linux.* | netbsd.* | openbsd.* | qnx.* | sol??.* )
# supported
test -n "$opt_query" && exit 0
;;
cygwin.*)
test -n "$opt_query" && exit 1
note "Dynamic libraries are not supported on Cygwin."
exit 0 # continue build
;;
*) case ${AST_DYLIB_TEST:+y} in
y) test -n "$opt_query" && exit 0
;;
*) test -n "$opt_query" && exit 1
note "The system $HOSTTYPE is currently untested for dynamic libraries" \
"so dynamic libraries are disabled by default. To test them," \
"export AST_DYLIB_TEST to try to build a dynamically linked ksh."
exit 0 # continue build
;;
esac
;;
esac
# Set destination directory.
dest_dir=$INSTALLROOT/dyn
mkdir -p "$dest_dir/bin" "$dest_dir/lib" || err_out "could not mkdir"
# Deduplicate -l flags and convert them to static linkage where necessary.
# Keep the last-mentioned of each item that occurs multiple times (this is
# required for passing libraries to the linker in the correct order; that
# is, each dependency must come after all the libraries that depend on it).
dupes=$l_flags
l_flags=
while test -n "$dupes"
do # Grab first item from dupes
item=${dupes%%"$CCn"*}
# Remove that item from dupes
dupes=${dupes#"$item"}
dupes=${dupes#"$CCn"} # remove $CCn separately as last item won't end in it
# Skip the item if another identical item is still in dupes
case "$CCn$dupes$CCn" in
*"$CCn$item$CCn"*)
continue ;;
esac
# If item was locally compiled but only as a static library, convert it to static linkage (path to lib${name}.a)
name=${item# -l}
case $(set +o noglob; set -- $dest_dir/lib/lib$name.* $dest_dir/lib/$name.*; printf '%s' "$#,$1,$2") in
"2,$dest_dir/lib/lib$name.*,$dest_dir/lib/$name.*")
# Unchanged glob patterns = the dynamic library does not exist in our local build tree.
# If there is no local static library either, leave it alone; it's probably an OS library.
if test -f $INSTALLROOT/lib/lib${name}.a
then item=" $INSTALLROOT/lib/lib${name}.a"
fi ;;
esac
# Add item to new space-separated l_flags
l_flags="$l_flags$item"
done
# Do the dynamic linking.
case ${exec_file} in
'') # ... figure out library file name(s) and internal name for linking purposes
# on macOS we have version before extension (libast.6.0.dylib), on other systems, after (libast.so.6.0)
case $suffix in
.dylib) lib_file=$prefix$module_name.$version$suffix
lib_linkname=$prefix$module_name.${version%%.*}$suffix
;;
*) lib_file=$prefix$module_name$suffix.$version
lib_linkname=$prefix$module_name$suffix.${version%%.*}
;;
esac
sym_links="$lib_linkname $prefix$module_name$suffix"
# ... remove possible old versions
(set +o noglob; exec rm -f "$dest_dir/lib/$prefix$module_name".*)
# ... execute linker command
case $HOSTTYPE in
darwin.*)
do_link "lib/$lib_file" -dynamiclib \
-Wl,-dylib_install_name -Wl,"@rpath/$lib_linkname" \
"$@" -L"$dest_dir/lib" $l_flags
;;
*) do_link "lib/$lib_file" -shared -Wl,-soname -Wl,"$lib_linkname" \
"$@" -L"$dest_dir/lib" $l_flags
;;
esac
for f in $sym_links
do ln -sf "$lib_file" "$dest_dir/lib/$f"
done
;;
*) # Link an executable.
case $HOSTTYPE in
darwin.*)
# since macOS SIP broke DYLD_LIBRARY_PATH, add a temporary @rpath
do_link "bin/$exec_file" "$@" -headerpad_max_install_names -L"$dest_dir/lib" $l_flags
install_name_tool -add_rpath "$dest_dir/lib" "$dest_dir/bin/$exec_file"
;;
*)
do_link "bin/$exec_file" "$@" -L"$dest_dir/lib" $l_flags
;;
esac
;;
esac