blob: c1f385e1516978939ea436281048b6b152c32ebf (
plain)
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
|
# SPDX-FileCopyrightText: 2021 René de Hesselle <dehesselle@web.de>
#
# SPDX-License-Identifier: GPL-2.0-or-later
### description ################################################################
# Provide convenience wrappers for install_name_tool.
### shellcheck #################################################################
# shellcheck shell=bash # no shebang as this file is intended to be sourced
### dependencies ###############################################################
assert_darwin
bash_d_include echo
bash_d_include readlinkf
### variables ##################################################################
LIB_RESET_ID=keep # options: basename, canonical, keep
### functions ##################################################################
function lib_change_path
{
# Compared to install_name_tool, this function
# - requires less arguments as 'source' can be deducted from 'target'
# - can apply the requested changes to multiple binaries at once
local target=$1 # new path to dynamically linked library
local binaries=${*:2} # binaries to modify
local source_lib=${target##*/} # get library filename from target location
for binary in $binaries; do # won't work if spaces in paths
if [[ $binary == *.so ]] ||
[[ $binary == *.dylib ]] ||
[ $(file $binary | grep "shared library" | wc -l) -eq 1 ]; then
lib_reset_id $binary
fi
local source=$(otool -L $binary | grep "$source_lib " | awk '{ print $1 }')
if [ -z $source ]; then
echo_w "no $source_lib in $binary"
else
# Reconstructing 'target' as it might have been specified as regex.
target=$(dirname $target)/$(basename $source)
install_name_tool -change $source $target $binary
fi
done
}
function lib_change_paths
{
# This is a wrapper ontop lib_change_path: given a directory 'lib_dir' that
# contains the libraries, all (matching) libraries linked in 'binary' can be
# changed at once to a specified 'target' path.
local target=$1 # new path to dynamically linked library
local lib_dir=$2
local binaries=${*:3}
for binary in $binaries; do
for linked_lib in $(otool -L $binary | tail -n +2 | awk '{ print $1 }'); do
if [ "$(basename $binary)" != "$(basename $linked_lib)" ] &&
[ -f $lib_dir/$(basename $linked_lib) ]; then
lib_change_path $target/$(basename $linked_lib) $binary
fi
done
done
}
function lib_change_siblings
{
# This is a wrapper ontop lib_change_path: all libraries inside a given
# 'lib_dir' that are linked to libraries located in that same 'lib_dir' can
# be automatically adjusted.
local lib_dir=$1
for lib in $lib_dir/*.dylib; do
lib_reset_id $lib
for linked_lib in $(otool -L $lib | tail -n +2 | awk '{ print $1 }'); do
if [ "$(basename $lib)" != "$(basename $linked_lib)" ] &&
[ -f $lib_dir/$(basename $linked_lib) ]; then
lib_change_path @loader_path/$(basename $linked_lib) $lib
fi
done
done
}
function lib_reset_id
{
local lib=$1
case "$LIB_RESET_ID" in
basename)
install_name_tool -id $(basename $lib) $lib
;;
canonical)
install_name_tool -id $(readlinkf $lib) $lib
;;
keep)
: # don't do anything
;;
*)
echo_e "invalid value for LIB_RESET_ID: $LIB_RESET_ID"
;;
esac
}
function lib_add_rpath
{
local rpath=$1
local binary=$2
install_name_tool -add_rpath "$rpath" "$binary"
}
function lib_clear_rpath
{
local binary=$1
for rpath in $(otool -l $binary | grep -A2 LC_RPATH | grep -E "^[ ]+path" | awk '{ print $2 }'); do
install_name_tool -delete_rpath $rpath $binary
done
}
function lib_replace_path
{
local source=$1
local target=$2
local binary=$3
for lib in $(lib_get_linked $binary); do
if [[ $lib =~ $source ]]; then
lib_change_path @rpath/$(basename $lib) $binary
fi
done
}
function lib_get_linked
{
local binary=$1 # can be executable or library
#echo_d "binary: $binary"
local filter # we need to distinguish between executable and library
local file_type
file_type=$(file "$binary")
if [[ $file_type = *"shared library"* ]]; then
filter="-v $(otool -D "$binary" | tail -n 1)" # exclude library id
elif [[ $file_type = *"executable"* ]]; then
filter="-E [.]+" # include everything
else
echo_w "neither shared library nor executable: $binary"
return 1
fi
# since we're not echoing this, output will be newline-separated
# shellcheck disable=SC2086 # need word splitting for arguments
otool -L "$binary" | grep " " | grep $filter | awk '{ print $1 }'
}
### aliases ####################################################################
# Nothing here.
### main #######################################################################
# Nothing here.
|