Skip to content

Commit 5970245

Browse files
authored
Merge pull request #38 from scratchcpp/linux_workflow
Add Linux workflow
2 parents 01025f8 + 63551c2 commit 5970245

File tree

16 files changed

+814
-8
lines changed

16 files changed

+814
-8
lines changed

.ci/bin/xldd

Lines changed: 371 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,371 @@
1+
#!/bin/bash
2+
3+
# ldd drop-in replacement for cross-compilation toolchains.
4+
5+
# This file is a slightly modified version of xldd.in from
6+
# crosstool-ng 1.22.0
7+
8+
# In order to use it, copy it in same directory than other
9+
# toolchain binaries and rename it with same tuple.
10+
# (i.e. /opt/arm-sysmic-linux-gnueabihf/bin/arm-sysmic-linux-gnueabihf-ldd)
11+
# Thus, this will automaticaly detect necessary information
12+
# about your toolchain.
13+
14+
export LC_ALL=C
15+
version="forked from crosstool-ng 1.22.0"
16+
# Change it to 64 if necessary
17+
bits="32"
18+
sed="${SED:-sed}"
19+
grep="${GREP:-grep}"
20+
21+
abs_path="$(realpath $0)"
22+
my_name="$( basename "${abs_path}" )"
23+
prefix="${abs_path%-ldd}"
24+
gcc="${prefix}-gcc"
25+
readelf="${prefix}-readelf"
26+
fake_load_addr_root="$((0xdeadbeef))"
27+
fake_load_addr_rpath="$((0xdeadc0de))"
28+
fake_load_addr_sysroot="$((0x8badf00d))"
29+
ld_library_path="/lib:/usr/lib:$LD_LIBRARY_PATH"
30+
31+
do_error() {
32+
printf "%s: %s\n" "${my_name}" "$*" >&2
33+
}
34+
35+
do_opt_error() {
36+
do_error "$@"
37+
printf "Try \`%s --help' for more information\n" "${my_name}" >&2
38+
}
39+
40+
do_trace() {
41+
local depth=0
42+
43+
[ -z "${CT_XLDD_VERBOSE}" ] && return 0
44+
45+
for((depth=0; "${#FUNCNAME[$((depth+1))]}" != 0; depth++)); do :; done
46+
printf "%*s" $((4*(depth-1))) "" >&2
47+
printf -- "$@" >&2
48+
}
49+
50+
show_version() {
51+
# Fake a real ldd, just in case some dumb script would check
52+
cat <<_EOF_
53+
ldd (crosstool-NG) ${version}
54+
Copyright (C) 2010 "Yann E. MORIN" <yann.morin.1998@free.fr>
55+
This is free software; see the source for copying conditions. There is NO
56+
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
57+
Licensed under the GPLv2, see the file LICENSES in the top-directory of the
58+
sources for this package.
59+
_EOF_
60+
}
61+
62+
show_help() {
63+
cat <<_EOF_
64+
Usage: ${my_name} [OPTION]... --root DIR FILE...
65+
--help print this help and exit
66+
--version print version information and exit
67+
--root dir treat dir as being the root of the target
68+
-s, --show-system mark libs from the sysroot with a trailing '[*]'
69+
and libs found via RPATH with a trailing '[+]'
70+
71+
_EOF_
72+
cat <<_EOF_ |fmt
73+
${my_name} tries to mimick the behavior of a real native ldd, but can be
74+
used in a cross-development environment. Here is how it differs from a
75+
real native ldd:
76+
77+
If the CT_XLDD_VERBOSE variable is set and non-empty, then ${my_name} will
78+
print a lot of debug messages, explaining how it builds the library
79+
search path, and how each library was found and why.
80+
81+
The LD_LIBRARY_PATH variable is not used, as it can not reliably be
82+
guessed except at runtime, and we can't run.
83+
84+
${my_name} does not scan /etc/ld.so.cache, but instead uses /etc/ld.so.conf
85+
(it understands the include directives therein for libces that have that).
86+
87+
${my_name} also interprets (tries to!) the RPATH/RUNPATH records found in
88+
the dynamic ELF section. Such paths are searched for only relative to
89+
the specified root, not from the sysroot (see below). Also, those paths
90+
are searched for not only for the file they appear in, but also for its
91+
dependencies.
92+
93+
${my_name} will search the directory specified with --root for libraries
94+
to resolve the NEEDED tags. If --root is not set, then ${my_name} will
95+
use the value in the environment variable \${CT_XLDD_ROOT}. If neither
96+
is set, then this is an error.
97+
98+
If NEEDED libraries can't be found in the specified root directory, then
99+
${my_name} will also look in the sysroot of the toolchain to see if it
100+
can find them.
101+
102+
For NEEDED libraries that were found, the output will look like:
103+
libneeded.so => /path/to/libneeded.so (0xloadaddr)
104+
105+
and for those that were not found, the output will look like:
106+
libneeded.so not found
107+
108+
The paths are relative to the host root directory.
109+
110+
The expected load address 'loadaddr' is a faked address to match the output
111+
of the real ldd, but has no actual meaning (set to some constants for now,
112+
0x8badf00d for libraries from the sysroot, 0xdeadc0de for those found via
113+
the RPATH/RUNPATH records, and 0xdeadbeef for others).
114+
_EOF_
115+
116+
# Unimplemeted yet:
117+
# -d, --data-relocs process data relocations
118+
# -r, --function-relocs process data and function relocations
119+
# -u, --unused print unused direct dependencies
120+
# -v, --verbose print all information
121+
122+
# See also this thread:
123+
# http://sourceware.org/ml/crossgcc/2008-09/msg00057.html
124+
}
125+
126+
# Parse command line options
127+
root="${CT_XLDD_ROOT}"
128+
show_system=
129+
while true; do
130+
case "${1}" in
131+
--help)
132+
show_help
133+
exit 0
134+
;;
135+
--version)
136+
show_version
137+
exit 0
138+
;;
139+
--root)
140+
root="$2"
141+
shift
142+
;;
143+
--root=*)
144+
root="${1#--root=}"
145+
;;
146+
--show-system|-s)
147+
show_system=1
148+
;;
149+
-*)
150+
do_opt_error "unrecognized option \`${1}'"
151+
exit 1
152+
;;
153+
*)
154+
break
155+
;;
156+
esac
157+
shift
158+
done
159+
160+
# Sanity checks
161+
sysroot="$( "${gcc}" -print-sysroot 2>/dev/null )"
162+
if [ -z "${sysroot}" ]; then
163+
sysroot="$( "${gcc}" -print-file-name=libc.so 2>/dev/null \
164+
|${sed} -r -e 's:/usr/lib/libc.so$::;' \
165+
)"
166+
fi
167+
if [ -z "${sysroot}" ]; then
168+
do_error "unable to find sysroot for \`${gcc}'"
169+
fi
170+
171+
if [ -z "${root}" ]; then
172+
root=${sysroot}
173+
fi
174+
if [ ! -d "${root}" ]; then
175+
do_error "\`${root}': no such file or directory"
176+
exit 1
177+
fi
178+
179+
do_report_needed_found() {
180+
local needed="${1}"
181+
local path="${2}"
182+
local origin="${3}"
183+
local loadaddr
184+
local sys
185+
local root_append=""
186+
187+
case "${origin}" in
188+
root)
189+
loadaddr="${fake_load_addr_root}"
190+
root_append="${root}"
191+
;;
192+
rpath)
193+
loadaddr="${fake_load_addr_rpath}"
194+
if [ -n "${show_system}" ]; then
195+
sys=" [+]"
196+
fi
197+
;;
198+
sysroot)
199+
loadaddr="${fake_load_addr_sysroot}"
200+
if [ -n "${show_system}" ]; then
201+
sys=" [*]"
202+
fi
203+
;;
204+
esac
205+
206+
printf "%8s%s => %s (0x%0*x)%s\n" \
207+
"" \
208+
"${needed}" \
209+
"${path}" \
210+
"$((bits/4))" \
211+
"${loadaddr}" \
212+
"${sys}" | sed "s| => /| => ${root_append}/|"
213+
}
214+
215+
# Search a needed file, scanning ${lib_dir} in the root directory
216+
do_find_needed() {
217+
local needed="${1}"
218+
local -a list
219+
local -a dirs
220+
local found
221+
local where
222+
local base
223+
local d i
224+
225+
do_trace "Searching for '%s'\n" "${needed}"
226+
227+
# rpath shall come first!
228+
list=( \
229+
"rpath:${root}" \
230+
"root:${root}" \
231+
"sysroot:${sysroot}" \
232+
)
233+
234+
for i in "${list[@]}"; do
235+
where="${i%%:*}"
236+
base="${i#*:}"
237+
if [ "${where}" = "rpath" ]; then
238+
dirs=( "${search_rpath[@]}" )
239+
else
240+
dirs=( "${needed_search_path[@]}" )
241+
fi
242+
for d in "${dirs[@]}"; do
243+
do_trace "-> looking in '%s' (%s)\n" "${d}" "${where}"
244+
if [ -f "${base}${d}/${needed}" ]; then
245+
found="${d}/${needed}"
246+
do_trace "---> found\n"
247+
break 2
248+
fi
249+
done
250+
done
251+
252+
if [ -n "${found}" ]; then
253+
do_report_needed_found "${needed}" "${found}" "${where}"
254+
do_process_file "${base}${found}"
255+
else
256+
printf "%8s%s not found\n" "" "${needed}"
257+
fi
258+
259+
do_trace "Done searching for '%s'\n" "${needed}"
260+
}
261+
262+
# Scan a file for all NEEDED tags
263+
do_process_file() {
264+
local file="${1}"
265+
local -a save_search_rpath
266+
local n m
267+
local found
268+
269+
do_trace "Parsing file '%s'\n" "${file}"
270+
271+
save_search_rpath=( "${search_rpath[@]}" )
272+
for n in $( "${readelf}" -d "${file}" \
273+
|"${grep}" -E '\((RPATH|RUNPATH)\)' \
274+
|"${sed}" -r -e 's/^.*Library r(|un)path:[[:space:]]+\[(.*)\]$/\2/;'\
275+
); do
276+
277+
OIFS=$IFS;
278+
IFS=":";
279+
narray=($n)
280+
for subn in "${narray[@]}"; do
281+
do_trace "-> adding rpath '%s'\n" "${subn}"
282+
search_rpath+=( "${subn}" )
283+
done
284+
IFS=$OIFS;
285+
done
286+
do_trace ": search path:\n"
287+
for n in "${search_rpath[@]}" "${needed_search_path[@]}"; do
288+
do_trace ": - '%s'\n" "${n}"
289+
done
290+
do_trace ": end search path\n"
291+
292+
for n in $( "${readelf}" -d "${file}" \
293+
|"${grep}" -E '\(NEEDED\)' \
294+
|"${sed}" -r -e 's/^.*Shared library:[[:space:]]+\[([^]]+)\].*/\1/;' \
295+
); do
296+
found=0
297+
for m in "${needed_list[@]}"; do
298+
[ "${n}" = "${m}" ] && found=1 && break
299+
done
300+
if [ ${found} -ne 0 ]; then
301+
do_trace "-> skipping already known dependency '%s'\n" "${n}"
302+
continue
303+
fi
304+
do_trace "-> handling new dependency '%s'\n" "${n}"
305+
needed_list+=( "${n}" )
306+
do_find_needed "${n}"
307+
do_trace "-> done handling dependency '%s'\n" "${n}"
308+
done
309+
310+
search_rpath=( "${save_search_rpath[@]}" )
311+
312+
do_trace "Finished parsing file '%s'\n" "${file}"
313+
}
314+
315+
# Recursively scan a /etc/ld.so.conf file
316+
do_scan_etc_ldsoconf() {
317+
local ldsoconf="${1}"
318+
local g
319+
local f
320+
321+
[ -f "${ldsoconf}" ] || return 0
322+
do_trace "Parsing ld.so.conf: '%s'\n" "${ldsoconf}"
323+
324+
while read line; do
325+
case "${line}" in
326+
include\ *)
327+
g="${root}${line#include }"
328+
do_trace "-> handling include directive '%s'\n" "${g}"
329+
for f in ${g}; do
330+
do_scan_etc_ldsoconf "${f}"
331+
done
332+
do_trace "-> finished handling include directive '%s'\n" "${g}"
333+
;;
334+
\#*|"")
335+
;;
336+
*)
337+
do_trace "-> adding search dir '%s'\n" "${line}"
338+
needed_search_path+=( "${line}" )
339+
;;
340+
esac
341+
done <"${ldsoconf}"
342+
343+
do_trace "Finished parsing ld.so.conf: '%s'\n" "${ldsoconf}"
344+
}
345+
346+
# Build up the full list of search directories
347+
declare -a needed_search_path
348+
do_trace "Adding basic lib dirs\n"
349+
ld_library_path="${ld_library_path}:"
350+
while [ -n "${ld_library_path}" ]; do
351+
d="${ld_library_path%%:*}"
352+
if [ -n "${d}" ]; then
353+
do_trace "-> adding search dir '%s'\n" "${d}"
354+
needed_search_path+=( "${d}" )
355+
fi
356+
ld_library_path="${ld_library_path#*:}"
357+
done
358+
do_trace "Done adding basic lib dirs\n"
359+
do_trace "Scanning '/etc/ld.so.conf'\n"
360+
do_scan_etc_ldsoconf "${root}/etc/ld.so.conf"
361+
do_trace "Done scanning '/etc/ld.so.conf'\n"
362+
do_trace "Search path:\n"
363+
for p in "${needed_search_path[@]}"; do
364+
do_trace "-> '%s'\n" "${p}"
365+
done
366+
367+
declare -a needed_list
368+
declare -a search_rpath
369+
do_trace "Scanning file '%s'\n" "${1}"
370+
do_process_file "${1}"
371+
do_trace "Done scanning file '%s'\n" "${1}"

0 commit comments

Comments
 (0)