forked from derphilipp/macportsscripts
-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
port-depcheck.sh
executable file
·210 lines (196 loc) · 8.49 KB
/
port-depcheck.sh
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
#!/bin/bash
# A script to check the dependencies of a port against which libraries the port actually
# links against.
# `otool` is an OS X thing (from cctools), so do NOT go expecting to run this on
# other platforms
if [ -z "$(which port)" ]; then
echo "MacPorts not found, this script is primarily for use with MacPorts."
exit 1
fi
if [ -z "$1" ]; then
echo "Usage: $(basename $0) portname"
exit 1
fi
if [ -z "$(port list $1)" ]; then
echo "Error: port $1 not found"
exit 1
fi
if [ "$(port installed $1)" = "None of the specified ports are installed." ]; then
echo "$(port installed $1)"
exit 1
fi
tempfoo=$(basename $0)
# I added the suffix stuff before I knew that `mktemp` already added one for you;
# I left them in anyway though because why not
# TODO:
# -[ ] Handle other special timezones besides EDT
# -[ ] Actually, just handle the output of `date` better in general
if [ "$(date | cut -d\ -f5)" != "EDT" ]; then
SUFFIX_PT1=$(date | cut -d\ -f5 | tr -d :)
SUFFIX_PT2=$(date | cut -d\ -f7)
else
SUFFIX_PT1=$(date | cut -d\ -f4 | tr -d :)
SUFFIX_PT2=$(date | cut -d\ -f6)
fi
SUFFIX=${SUFFIX_PT1}${SUFFIX_PT2}
# The first few times I tried this script I had some trouble with my $TMPDIR;
# that is why I am making sure it exists and is set here.
if [ -z "$TMPDIR" ]; then
export TMPDIR=/tmp
fi
# This might be a paradox, but I cannot think of a better way to make sure that
# this call to mkdir will actually succeed...
if [ ! -d $TMPDIR -a -w ${TMPDIR}/.. ]; then
mkdir -p $TMPDIR
fi
# TODO:
# -[ ] Make a function (or use a loop) to do this so I do not have to
# copy-n-paste as much
TMPFILE0=$(mktemp -q ${TMPDIR}/${tempfoo}.${SUFFIX}0.XXXXXX)
if [ $? -ne 0 ]; then
echo "$0: Cannot create zeroth temp file, exiting..."
exit 1
fi
TMPFILE1=$(mktemp -q ${TMPDIR}/${tempfoo}.${SUFFIX}1.XXXXXX)
if [ $? -ne 0 ]; then
echo "$0: Cannot create first temp file, exiting..."
exit 1
fi
TMPFILE2=$(mktemp -q ${TMPDIR}/${tempfoo}.${SUFFIX}2.XXXXXX)
if [ $? -ne 0 ]; then
echo "$0: Cannot create second temp file, exiting..."
exit 1
fi
TMPFILE3=$(mktemp -q ${TMPDIR}/${tempfoo}.${SUFFIX}3.XXXXXX)
if [ $? -ne 0 ]; then
echo "$0: Cannot create third temp file, exiting..."
exit 1
fi
TMPFILE4=$(mktemp -q ${TMPDIR}/${tempfoo}.${SUFFIX}4.XXXXXX)
if [ $? -ne 0 ]; then
echo "$0: Cannot create fourth temp file, exiting..."
exit 1
fi
delete_tmpfiles() {
for TMPFILE_TO_DELETE in "${TMPFILE0}" "${TMPFILE1}" "${TMPFILE2}" "${TMPFILE3}" "${TMPFILE4}"; do
if [ -w "${TMPDIR}" -a -w "${TMPFILE_TO_DELETE}" ]; then
rm -f "${TMPFILE_TO_DELETE}"
fi
done
}
# This one gets a special case because there are more reasons to delete it:
delete_tmpfile3() {
if [ -w "${TMPDIR}" -a -w "${TMPFILE3}" ]; then
rm -f "${TMPFILE3}"
fi
}
if [ -L "$(which port)" ]; then
REAL_PORT=$(readlink "$(which port)")
echo "Warning: $(which port) is a symlink to ${REAL_PORT}."
export MP_PREFIX=$(dirname $(dirname ${REAL_PORT}))
echo "Assuming MP_PREFIX is actually ${MP_PREFIX}."
else
export MP_PREFIX=$(dirname $(dirname "$(which port)"))
fi
if [ -z "$MP_PREFIX" ]; then
export MP_PREFIX=/opt/local
fi
# TODO:
# -[ ] Figure out if it is safe to remove the dependencies that are probably due
# to libtool overlinking
# -[ ] Actually do the removing
echo "Finding MacPorts libraries that ${1} links against..."
# I should find a way to not have to pipe so much stuff through `cut` here...
# http://trac.macports.org/ticket/38428
MACH_O_FILES=$(port -q contents $1 | xargs /usr/bin/file | grep Mach-O | cut -d\: -f1 | cut -d\ -f1 | uniq)
if [ ! -z "${MACH_O_FILES}" ]; then
LINKED_AGAINST_LIBS=$(echo "${MACH_O_FILES}" | xargs otool -L | grep "\ version\ " | grep "${MP_PREFIX}" | sort | uniq | cut -d\ -f1)
echo "${LINKED_AGAINST_LIBS}" >> "${TMPFILE0}"
SYMBOLS=$(for macho in ${MACH_O_FILES}; do if [ ! -z "${macho}" ]; then nm -m "${macho}" 2>/dev/null && echo ""; fi && echo ""; done && echo "")
echo "${SYMBOLS}" >> "${TMPFILE4}"
echo "" >> "${TMPFILE4}"
if [ ! -z "$LINKED_AGAINST_LIBS" ]; then
# This is the part where we actually get the ports linked against:
echo $(cat "${TMPFILE0}" | xargs port -q provides 2>/dev/null | grep "is provided by" | tee -a /dev/tty | cut -d\: -f2 | sort | uniq) | sed "s|${1} ||" | tr \ \\n >> "${TMPFILE1}"
if [ ! -z "${SYMBOLS}" -a -e "${TMPFILE4}" ]; then
if [ -z "${PORT_DEPCHECK_SKIP_NM_SYMBOL_CHECK}" ]; then
echo "Checking symbols in linked-against libraries..."
for MP_LIBRARY in $(echo "${LINKED_AGAINST_LIBS}" | uniq | xargs basename | uniq | cut -d. -f1 | uniq | cut -d\- -f1 | uniq); do
printf "Checking to see if %s actually uses symbols from %s... " "${1}" "${MP_LIBRARY}"
if [ ! -z "$(grep ${MP_LIBRARY} ${TMPFILE4})" ]; then
echo "yes"
else
PORT_TO_REMOVE="$(cat ${TMPFILE0} | uniq | sort | uniq | xargs port -q provides 2>/dev/null | uniq | sort | uniq | grep ${MP_LIBRARY} | uniq | sort | uniq | cut -d\: -f2 | uniq | sort | uniq | tr -d [:blank:])"
if [ -z "${PORT_DEPCHECK_KEEP_PORTS_THAT_FAIL_SYMBOL_CHECK}" ]; then
echo "no (TODO: use sed properly to remove \"${PORT_TO_REMOVE}\" from list of dependencies)"
else
echo "no (an environment variable is set; remove \"${PORT_TO_REMOVE}\" from the list of dependencies manually)"
fi
fi
done
else
echo "The environment variable to skip the symbol check is set."
fi
else
echo "Warning: libraries have no symbols... (how did that happen?)"
fi
else
echo "${1} does not actually link against any MacPorts libraries, exiting..."
delete_tmpfiles
exit 1
fi
else
echo "${1} does not actually contain any mach-o binaries, exiting..."
delete_tmpfiles
exit 1
fi
if [ "$(port -q version | cut -d: -f2 | cut -d. -f1)" -eq 2 -a "$(port -q version | cut -d: -f2 | cut -d. -f2)" -lt 2 ]; then
if [ ! -z "$(port -q installed libtool)" ];then
echo "Finding which linkages might be due to libtool over-linking..."
LIBTOOL_ARCHIVES=$(port -q contents $1 | xargs file | grep "libtool library file" | cut -d\: -f1 | cut -d\ -f1 | uniq)
if [ ! -z "$LIBTOOL_ARCHIVES" ]; then
DEPENDENCY_LIBS=$(cat "${LIBTOOL_ARCHIVES}" | grep "dependency_libs" | tr \ \\n | grep "$MP_PREFIX" | grep \.la)
# TODO:
# -[ ] Handle the dangling single-quotes in a way that does not
# confuse the syntax highlighting in my text editor...
if [ ! -z "$DEPENDENCY_LIBS" ]; then
echo "${DEPENDENCY_LIBS}"
echo "Checking which ports provide dependency_libs entries in these libtool archives..."
DEPENDENCY_PROVIDERS=$(echo "${DEPENDENCY_LIBS}" | xargs port -q provides | cut -d\: -f2 | uniq | sort | uniq | tr -d '[:blank:]' | sed "s|${1}||" | tr -d '[:blank:]' | uniq | tee -a /dev/tty)
echo "${DEPENDENCY_PROVIDERS}" >> "${TMPFILE3}"
else
echo "libtool archives have already been cleared of dependency_libs; libtool over-linking likely is not a problem..."
delete_tmpfile3
fi
else
echo "Actually, no libtool archives were found, so never mind."
delete_tmpfile3
fi
else
echo "You do not have the libtool port installed; no need to check for libtool over-linking."
delete_tmpfile3
fi
else
echo "Checking libtool archives for overlinking should not be necessary for your MacPorts version ($(port -q version)), unless you have NOT rebuilt everything since you updated..."
echo "This script does NOT know whether or not you have rebuilt as such though, so we shall assume the best of you and skip the libtool-archives check."
echo "(the libtool-archives check was just a back-up check in case the check with \`nm(1)\` failed, anyways, so skipping it should be harmless)"
delete_tmpfile3
fi
echo "Finding the libraries that $(port file ${1}) lists as dependencies..."
ACTIVE_VARIANTS=$(port -q installed "${1}" | grep \(active\) | cut -d\ -f4)
echo "${1} is installed with the following active variants: ${ACTIVE_VARIANTS}"
echo "So we shall find the dependencies for those variants..."
# I would like there to be a `lib_depof:` type of pseudo-portname to use here:
# https://trac.macports.org/ticket/38381
port info --line --depends_lib "${1}" "${ACTIVE_VARIANTS}" | tr ',' '\n' | tee -a /dev/tty | awk -F ':' '{ print $NF; }' | sort | uniq >> "${TMPFILE2}"
echo "Comparing the list of library linkages with the list of library dependencies..."
DIFF_CONTENTS=$(diff -iwBu --strip-trailing-cr "${TMPFILE2}" "${TMPFILE1}")
if [ -z "${DIFF_CONTENTS}" ]; then
echo "No difference in dependencies, exiting."
delete_tmpfiles
exit 1
else
DIFF_FILE=${TMPDIR}/${1}-deps.${SUFFIX}.diff
echo "$DIFF_CONTENTS" | tee "${DIFF_FILE}"
echo "Output a diff file to ${DIFF_FILE}"
fi