GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Musl & LLVM build by peppergrayxyz · Pull Request #343 · linuxdeploy/linuxdeploy

Conversation

@peppergrayxyz

@peppergrayxyz peppergrayxyz commented Nov 11, 2026

Copy link
Copy Markdown

These patches make linuxdeploy build and deploy correctly with musl (Alpine, Gentoo), with the LLVM toolchain (clang, lld, libc++, llvm-strip, llvm-objcopy) and on FreeBSD. They also add CI jobs and regression tests for these platforms.

Closes: #325
Closes: #340

The initial idea was to get musl and clang working, but I hit multiple issues and it escalated into a larger exercise. Most of the work is in dependency tracing: linuxdeploy parses the output of the platform's ldd, and glibc, musl and FreeBSD each format it differently, exit differently and list different things. This patch adds fixtures and mocks to test these contracts in CI.

I have ordered the commits to be somewhat logical and in a way that they can be split into multiple PRs, and mostly kept them small and focused so they can be cherry-picked. Happy to shuffle things around, just let me know.

Patches

1. LLVM build

  • f046183 subprocess: Add missing <cerrno> include
    libc++ 23 no longer includes it transitively, so the LLVM build fails.
  • 7780b3f tests: Use CMAKE_OBJCOPY
    The tests ran objcopy from $PATH, which LLVM-only systems don't have (they have llvm-objcopy).

2. Bugs

  • 6d280b9 util: Check PATH entries directly in which()
    It threw on searchable but unreadable $PATH directories and returned non-executables.
  • 885df2b plugin: Do not crash if $PATH is unset
    getenv("PATH") returned null and the plugin search crashed.
  • fb685bf plugin: Keep the file name alive while matching it
    The plugin's name was read from freed memory.
  • 8af2cd8 appdir: Fail the deployment if an rpath cannot be set
    The deployment succeeded with an AppDir whose files cannot find their libraries.

3. static-pie

  • 5663631 tests: Add a shared library fixture without dependencies
    A shared library without dependencies looks like a static-pie executable, so the next commit's check needs a fixture to rule out false positives.
  • d2a9be3 elf_file: Treat static-pie executables as statically linked
    static-pie executables (Rust's musl targets, Alpine's GCC with -static) were traced with ldd and had their rpath set, and static files hit an assert.

4. subprocess

  • a6fb640 subprocess: Close the pipes if starting a process fails
    A failed start leaked up to four file descriptors.
  • 1ac4371 subprocess: Do not allocate or throw in the forked child
    If exec* failed (e.g., a missing ldd), the child threw, and the caller's code ran in both processes.
  • 2d58807 subprocess: Report termination by signal
    A SIGKILL could not be told apart from exit 9.
  • 1c6890e subprocess: Keep the pipe ends above the standard streams
    With linuxdeploy's standard streams closed, the pipes took their numbers, and the child's redirections overwrote each other.
  • 0886c4b subprocess: Close the pipes on exec
    Children started by other threads inherited the pipes, so the reader saw no end of file until they exited.
  • 1cb3d57 subprocess: Report why a program could not be run
    Exit code 127 was ambiguous, so callers searched for programs up front with rules that differ from exec*; the missing ldd, patchelf and strip messages build on this.
  • 3cf5c78 subprocess: Throw called_process_error from check_output()
    Callers could not tell a program that failed from an error that stops any program from starting.
  • 359c4d1 subprocess: Read stdout and stderr alternately
    musl's ldd on plugins fills the stderr pipe, which deadlocked linuxdeploy. This blocks musl.

5. patchelf, strip and error reporting

  • 9572769 main: Report uncaught errors instead of aborting
    Uncaught exceptions aborted and dumped core, and the following commits throw more.
  • 1975f57 elf_file: Stop if patchelf cannot read an rpath
    An rpath patchelf could not read was silently replaced with $ORIGIN.
  • 751e65d core: Report a patchelf or strip which cannot be run
    A tool that could not be run was treated as a failed call, or reported as Strip call failed: without a reason, once per file.
  • bb8c4d5 appdir: Allow strip to be set through $STRIP
    The LLVM toolchain only ships llvm-strip, so stripping failed (Add --strip and --appimagetool parameters to pass local locations of strip and appimagetool #325).
  • ec0d4da elf_file: Select patchelf like strip
    A name in $PATCHELF failed, an empty value counted as set, and an unset $PATH crashed.
  • 167fb47 plugin: Skip unreadable directories and failing plugins
    One unreadable directory or broken plugin in $PATH ended linuxdeploy on every start, even if the plugin was not used.

6. CI: Alpine and Gentoo containers

  • 3832b53 ci: Default $ARCH to the host architecture
    The scripts failed without $ARCH, and did not accept uname's names (e.g., armv7l).
  • 3306cb0 ci: Keep the user's uid in rootless Podman
    Rootless Podman mapped the user to a uid that cannot write to the mounted working tree.
  • 84ee43e ci: Bundle the patchelf and strip selected by $PATCHELF and $STRIP
    build.sh bundled the first strip in $PATH, not the one linuxdeploy runs (e.g., llvm-strip).
  • 6f1a2e6 ci: Support building in Alpine and Gentoo containers
    Add images for musl and LLVM.

7. i386: CImg

  • 97d9ed1 core: Include <cstdint> before CImg.h
    CImg's 16 GiB buffer limit overflows to 0 on i386, so every CImg allocation threw, which only surfaced once a test ran simple_executable.

8. Dependency tracing tests

  • d3d9c84 tests: Add dependency tracing regression tests
    ldd behaves differently on glibc, musl and FreeBSD, and no single machine has them all: the recordings test every platform's behavior on any machine.
  • 2ec7f2e ci: Add a dependency tracing test script
    Nothing checked tracing end to end (build, tests, deploy, run): CI and local runs share this script.

Every scenario runs twice:

  • against the system's ldd (test_dependency_tracing_real, which records the calls), and
  • against the recordings of every platform (test_dependency_tracing_mock)

9. ldd differences

  • ff64c28 elf_file: Recognize missing libraries with an address suffix
    FreeBSD: not found was deployed as a library path.
  • b5a71cf elf_file: Handle the non-zero exit status of musl's ldd
    musl: any plugin whose symbols the host program provides ended linuxdeploy.
  • fa66875 elf_file: Report a missing ldd
    A missing ldd (e.g., Alpine without musl-utils) was reported as if the traced file were missing.
  • e0fe02b elf_file: Trace libraries not named lib* on FreeBSD
    FreeBSD: libraries not named lib* were neither deployed nor reported as missing.
  • 777c454 elf_file: Skip musl's loader and libc aliases
    musl: its libc and loader were deployed into the AppDir ([musl/ldd] std::runtime_error: Failed to run ldd: exited with code 1 #340).
  • 8878025 elf_file: Recognize glibc's loaders by their file name
    glibc: the substring match dropped real libraries in paths like build-linux-x86_64/.
  • 5f815ad elf_file: Deploy libraries needed by their path with a warning
    glibc dropped them, while musl and FreeBSD deployed them silently: the warning is there because the loader usually won't use the copy.
  • 4aba2af elf_file: Do not deploy preloaded libraries
    Libraries from $LD_PRELOAD and /etc/ld.so.preload (e.g., libarmmem on Raspberry Pi OS, fakeroot) were bundled.

10. Recordings and CI job

  • dc295c3 ci: Record the ldd calls of the tests
    Recordings to be used for mock tests for every platform's ldd calls.
  • ba02b8a ci: Add a dependency tracing job
    Run dependency tracing in CI.

Platforms: Debian, Alpine (musl/GCC and LLVM), Gentoo (LLVM) and FreeBSD

11. Patches of unmerged upstream PRs

  • 808b81f ci: Apply the patches of unmerged PRs
    The musl builds need these currently unmerged submodule fixes:
    • append to C/CXX-flags to keep toolchain flags linuxdeploy-plugin-appimage#45
    • add missing <climits> include linuxdeploy-plugin-appimage#46
    • including missing header for musl build linuxdeploy-desktopfile#11
    • add option to force gtest build from source cmake-scripts#1
      Revert this commit once they are merged

Changed behavior

Please check whether these changes are acceptable:

Deployment

Before Now Group
Succeeded if patchelf failed to set an rpath Fails 2
An rpath patchelf couldn't read was replaced with $ORIGIN Fails, and the file isn't stripped 5
A patchelf that couldn't be run counted as a failed call Fails with the reason 5
A strip that couldn't be run gave Strip call failed: once per file Reported once with the reason, and stripping stops 5
An uncaught exception aborted and dumped core Reported, and exits with an error 5
static-pie executables were traced with ldd and had their rpath set Treated as static and left alone 3

Tool selection

Before Now Group
$STRIP was ignored $STRIP (a name or a path) is used, with no fallback. Environments that export $STRIP for other tools (autotools, SDKs, cross toolchains) now use that strip 5
$PATCHELF had to be an existing path, and an empty value counted as set A name or a path, empty means unset, with no fallback 5
build.sh bundled the first patchelf and strip in $PATH Bundles the ones $PATCHELF/$STRIP select 6
build.sh and build-in-docker.sh required $ARCH Defaults to uname -m, and also accepts uname's names (e.g., armv7l) 6

Plugins

Before Now Group
An unlistable $PATH directory, or a plugin that couldn't be accessed or queried, ended linuxdeploy on every start Skipped, and the plugin is reported as Could not load plugin. Errors that hit any program (e.g., too many open files) still end linuxdeploy 5
An unset $PATH crashed the plugin search Treated as empty 2
which() threw on directories it couldn't list, and returned files that aren't executable Checks each candidate directly and only returns executables. Like exec*, it checks names that contain a slash directly 2

Dependency tracing

Before Now Group
A non-zero ldd exit (musl) ended linuxdeploy Excluded missing libraries and unresolved symbols give a warning, and everything else fails the deployment (DependencyTraceError) 9
A missing ldd was reported as if the traced file were missing Reports ldd, or its interpreter, as missing 9
FreeBSD: missing libraries were deployed as a path called not found Reported as missing 9
FreeBSD: libraries not named lib* were dropped Deployed, or reported as missing 9
musl: its libc and loader were deployed Skipped 9
Libraries whose path contains ld-linux- or linux-vdso.so (e.g., build-linux-x86_64/) were dropped Deployed. Only loaders listed by path, and the vDSO by its bare name, are skipped 9
Libraries needed by their path were dropped on glibc, and deployed without a message on musl and FreeBSD Deployed with a warning on all platforms, unless excluded by file name 9
glibc: libraries preloaded by name were deployed. musl, FreeBSD: all preloaded libraries were deployed Libraries from $LD_PRELOAD and /etc/ld.so.preload are skipped, with one warning per library. Their dependencies are still deployed 9

API

Plugins compile against these headers, so these changes may affect them.

Before Now Group
check_output() threw std::logic_error Throws called_process_error, which derives from std::logic_error 4
Signals and exec* failures couldn't be told apart from exit codes term_signal(), exec_error() and exit_description() tell them apart. exit_code() is unchanged 4
subprocess_result(exit_code, stdout, stderr) subprocess_result(exit_code, term_signal, exec_error, stdout, stderr) 4
getRPath() returned "" if patchelf failed or couldn't be run Throws PatchelfError. Returns "" without running patchelf for static and debug symbols files 5
setRPath() treated a patchelf that couldn't be run as a failure Throws PatchelfError. Still returns false if patchelf ran but failed 5
traceDynamicDependencies() asserted on static files Returns {} 3
traceDynamicDependencies() threw std::runtime_error if ldd exited non-zero Throws DependencyTraceError, which is now the base of DependencyNotFoundError 9
traceDynamicDependencies(excludeLibraryPatterns) Two new defaulted parameters: preloadFile and warnedPreloads 9

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
peppergrayxyz added 30 commits November 11, 2026 01:45
@peppergrayxyz
subprocess: Add missing <cerrno> include
f046183
libc++ 23 dropped many transitive includes, which breaks the build with
the LLVM toolchain.

Include <cerrno> explicitly.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
tests: Use CMAKE_OBJCOPY
7780b3f
The tests used the first objcopy in $PATH, which does not exist
without GNU binutils.

Use the objcopy CMake found for the toolchain (e.g., llvm-objcopy).

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
util: Check PATH entries directly in which()
6d280b9
which() listed every directory in $PATH, which throws on directories
which are searchable but not readable, and it returned files which are
not executable.

- check each candidate with access() instead
- skip empty entries
- check names containing a slash directly, like exec*
- add tests

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
plugin: Do not crash if $PATH is unset
885df2b
The plugin search split getenv("PATH") without checking it for null.

Use splitEnv(), which treats an unset $PATH as empty.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
plugin: Keep the file name alive while matching it
fb685bf
The plugin search matched each file name in a temporary string, which
was destroyed before the plugin's name was read from the match, so it
was read from freed memory.

Match a named string with std::smatch instead.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
appdir: Fail the deployment if an rpath cannot be set
8af2cd8
executeDeferredOperations() recorded that patchelf failed to set an
rpath, but returned true, so linuxdeploy succeeded with an AppDir whose
files do not find their libraries.

- return whether all rpaths were set
- add tests

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
tests: Add a shared library fixture without dependencies
5663631
A shared library which needs no other libraries looks like a static-pie
executable, but no fixture lets the tests tell them apart.

Add simple_library_no_dependencies, linked with -nostdlib. Disable
clang's warning about unused runtime options from $LDFLAGS for it, and
do not instrument it for coverage, as the coverage runtime needs the C
library.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
elf_file: Treat static-pie executables as statically linked
d2a9be3
static-pie executables (e.g., Rust's musl targets) have no PT_INTERP,
but a PT_DYNAMIC segment like shared libraries, so they were traced
with ldd and had their rpath set.

Treat files with the DF_1_PIE flag and no DT_NEEDED entries as static,
and return no dependencies for static files instead of asserting. Add
static-pie and interpreter-less PIE fixtures, and keep the static
fixture non-PIE, as GCC on Alpine links -static as static-pie.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
subprocess: Close the pipes if starting a process fails
a6fb640
The constructor threw without closing the pipes it had created (e.g.,
if the second pipe() or fork() failed), leaking up to four file
descriptors per call.

- give the file descriptors owners, which close them unless handed over
- add tests

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
subprocess: Do not allocate or throw in the forked child
1ac4371
If exec* failed (e.g., for a missing ldd), the child threw, so the
caller's code continued to run in the child.

Prepare the exec* vectors before forking, and do not allocate or throw
in the child (execvpe, which POSIX does not list as async-signal-safe,
does not allocate on the heap in glibc, musl or FreeBSD), but exit with
127, like shells do for commands which cannot be run.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
subprocess: Report termination by signal
2d58807
A process terminated by a signal reported the signal's number as its
exit code, so callers could not tell SIGKILL apart from exit 9.

Add term_signal(), and exit_description() for messages, which
check_output() uses. exit_code() is unchanged.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
subprocess: Keep the pipe ends above the standard streams
1c6890e
If linuxdeploy's standard streams are closed, the pipes get their
numbers, so connecting one end in the child replaced another.

Move the pipe ends above the standard streams, and test it.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
subprocess: Close the pipes on exec
0886c4b
Programs started while the pipes were open (e.g., by another thread)
inherited them, so the reader saw no end of file until they exited.

Create the pipes with O_CLOEXEC.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
subprocess: Report why a program could not be run
1cb3d57
If exec* failed, the child exited with 127 without saying why, which
callers could not tell from a program exiting with 127. Instead, they
searched for programs up front, which does not follow the rules of
exec* (e.g., for an unset $PATH or empty entries).

Send the errno to the parent through a pipe which exec* closes, and add
exec_error(). exit_description() describes it, so check_output()
reports it, and the plugin process handler logs it. Test the search
rules of exec*, so callers can rely on them instead of searching up
front.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
subprocess: Throw called_process_error from check_output()
3cf5c78
check_output() threw a std::logic_error if the program failed or could
not be run, like the errors of starting any program (e.g., too many
open files), so callers could not tell them apart.

Throw the new called_process_error instead, which derives from
std::logic_error, so that existing handlers still catch it.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
subprocess: Read stdout and stderr alternately
359c4d1
run() read stdout until its end before reading stderr, so a program
which wrote more to stderr than its pipe holds (e.g., musl's ldd,
which reports every unresolved symbol of a plugin) blocked, and with
it linuxdeploy.

Read the data which is available from each pipe in turn, and restore
the read buffer's size before each read, as read() shrinks it. Drop
the sleep between the rounds, as poll() in each read already waits for
data.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
main: Report uncaught errors instead of aborting
9572769
An uncaught exception (e.g., for a missing patchelf) aborted linuxdeploy
and dumped core.

Catch exceptions in main(), report them, and exit with an error.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
elf_file: Stop if patchelf cannot read an rpath
1975f57
If patchelf failed to read an rpath, or could not be started,
getRPath() returned an empty one, which replaced the existing rpath
with $ORIGIN.

Throw a PatchelfError instead, which fails the deployment, and do not
strip a file whose rpath cannot be read. Return an empty rpath without
running patchelf for static and debug symbols files.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
core: Report a patchelf or strip which cannot be run
751e65d
A patchelf which could not be run was treated like one which failed, and
a strip which could not be run was reported as "Strip call failed:"
without a reason, once per file.

Report both with the reason: patchelf through a PatchelfError, which
fails the deployment, and strip once, then stop stripping the others.
For a patchelf or strip which ran, but failed, report how it ended.
Tests follow with $STRIP and $PATCHELF.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
appdir: Allow strip to be set through $STRIP
bb8c4d5
The LLVM toolchain provides llvm-strip rather than strip, so stripping
failed.

Run $STRIP (a name or a path), otherwise the strip next to linuxdeploy
or the first in $PATH, without falling back. Implement the lookup as
util::findTool(), so patchelf can share it, document it in the README
and test it. FreeBSD has no /proc to read linuxdeploy's path from, so
the tests of the bundled strip are skipped there.

Closes: linuxdeploy#325
Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
elf_file: Select patchelf like strip
ec0d4da
$PATCHELF had to be an existing file, so a name failed, an empty
$PATCHELF counted as set, and the search in $PATH crashed if $PATH was
unset.

- use util::findTool() like for strip
- test the lookup and how patchelf errors are handled
- update README

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
plugin: Skip unreadable directories and failing plugins
167fb47
The plugin search threw on directories in $PATH which are searchable
but not readable, on plugins which cannot be accessed (e.g., a symlink
loop), and on plugins whose query fails (e.g., which cannot be run),
which ended linuxdeploy on every start.

Skip such directories and plugins, and report the plugins as "Could not
load plugin". Errors which affect any program (e.g., too many open
files) still end linuxdeploy. Test these through --list-plugins.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
ci: Default $ARCH to the host architecture
3832b53
build.sh and build-in-docker.sh failed without $ARCH.

Default it to uname -m, and accept uname's names (e.g., armv7l for
armhf) in both, as $ARCH also names the AppImage.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
ci: Keep the user's uid in rootless Podman
3306cb0
Rootless Podman maps the host user's uid (which is used by the build)
to a subordinate uid, which cannot write to the mounted working tree.

Pass --userns=keep-id with rootless Podman, and ignore the HSTS database
wget then saves in $HOME, which is the working tree.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
ci: Bundle the patchelf and strip selected by $PATCHELF and $STRIP
84ee43e
build.sh bundled the first patchelf and strip in $PATH, not the ones
linuxdeploy runs (e.g., llvm-strip set in $STRIP).

Bundle those, linked under their default names, by which linuxdeploy
looks for the bundled tools.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
ci: Support building in Alpine and Gentoo containers
6f1a2e6
Linux CI only builds in Debian, with glibc and GCC.

Add images for Alpine (musl with GCC or LLVM) and Gentoo (glibc or musl
with GCC, musl with LLVM). build-in-docker.sh selects the distribution
by its first argument (or $TARGET, default debian) and the toolchain by
$TOOLCHAIN. Set CMAKE_POLICY_VERSION_MINIMUM for Alpine's CMake 4, and
build gtest from source for libc++. The musl builds also need unmerged
fixes of the submodules, which "ci: Apply the patches of unmerged PRs"
applies.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
core: Include <cstdint> before CImg.h
97d9ed1
CImg sizes its buffer limit by UINTPTR_MAX without including the header
defining it. When CImg.h comes first, the 64-bit limit of 16 GiB
overflows i386's 32-bit unsigned long to 0, so every CImg allocation
throws, including cimg::info()'s. No test ran simple_executable before,
so this went unnoticed.

src/core/appdir.cpp only gets UINTPTR_MAX through <filesystem> (e.g.,
with libstdc++), which need not include <cstdint>, so include it there,
too.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
tests: Add dependency tracing regression tests
d3d9c84
Dependency tracing depends on the platform's ldd (glibc, musl or
FreeBSD), which no single test machine covers.

Add scenarios which test_dependency_tracing_real runs with the system's
ldd, recording its calls, and test_dependency_tracing_mock replays with
the recordings of every platform. Add the fixture chain
simple_executable -> dependency_parent -> dependency_leaf.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
ci: Add a dependency tracing test script
2ec7f2e
There is no script to check dependency tracing on a platform, from the
tests to a deployed AppDir.

test-dependency-tracing.sh builds linuxdeploy, runs all tests, deploys
simple_executable to an AppDir, checks its libraries and runs it.
$BUILD_DIR reuses a build directory. build-in-docker.sh runs it if
$BUILD_TYPE is dependency-tracing.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
elf_file: Recognize missing libraries with an address suffix
ff64c28
FreeBSD's ldd appends an address to missing libraries
("libfoo.so => not found (0)"), which the expression for resolved
libraries matched, so "not found" was deployed as a library path.

Check for missing libraries first, with an expression of their own, and
move the exclusion check into a lambda, so other reports can share it.

Signed-off-by: Pepper Gray <[email protected]>
peppergrayxyz added 10 commits November 11, 2026 01:45
@peppergrayxyz
elf_file: Handle the non-zero exit status of musl's ldd
b5a71cf
musl's ldd exits with a non-zero status for missing libraries and for
unresolved symbols (e.g., of plugins whose symbols the host program
provides), while still listing the resolved libraries. This threw a
std::runtime_error, which ended linuxdeploy.

Accept excluded missing libraries and unresolved symbols. As every
deployed library is traced again, the warning only counts the symbols,
and the debug log lists them. Reject all other diagnostics, and an ldd
which could not be run or was terminated, through the new
DependencyTraceError, which fails the deployment.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
elf_file: Report a missing ldd
fa66875
Without ldd (e.g., Alpine without musl-utils), the error read "Failed to
run ldd on <file>: No such file or directory", as if the traced file
were missing.

Report ldd or its interpreter as missing if exec* reports ENOENT, and
test that other errors are still reported with their reason.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
elf_file: Trace libraries not named lib* on FreeBSD
e0fe02b
FreeBSD's ldd lists libraries not named lib* without their path or
whether they were found ("ldd (0x...)"), so they were neither deployed
nor reported as missing.

Set their format to that of the others through
LD_TRACE_LOADED_OBJECTS_FMT2.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
elf_file: Skip musl's loader and libc aliases
777c454
musl's libc is also its loader. Its ldd lists it without "=>" by the
name it was run as (e.g., /lib/ld-musl-*.so.1 or "ldd"), and the
libraries it provides itself (e.g., libc.so) resolve to that name, so
they were deployed.

Skip entries which resolve to an object listed without "=>", so musl is
recognized by any name, while libraries which only share such a name
are still deployed. Check in test-dependency-tracing.sh that no musl
runtime object is deployed.

Closes: linuxdeploy#340
Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
elf_file: Recognize glibc's loaders by their file name
8878025
To skip glibc's loader and the vDSO, every ldd line containing
"ld-linux-" or "linux-vdso.so" was dropped, and with it libraries in
paths like build-linux-x86_64/.

Recognize the loaders by their file name instead (e.g., ld-linux-*.so.*,
ld64.so.*, ld.so.* or ld-musl-*.so.1), but only where ldd lists them, by
their path, so that libraries searched for by a loader-like name (e.g.,
ld.so.1) are still deployed. Recognize the vDSO by its name without a
path. Both rules also cover the lines glibc 2.36 listed with "=>" (see
linuxdeploy#210).

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
elf_file: Deploy libraries needed by their path with a warning
5f815ad
glibc's ldd lists libraries needed by their path (e.g., an absolute
DT_NEEDED, or one relative to $ORIGIN, which it expands) without "=>",
so they were dropped, while musl's and FreeBSD's ldd list them with
"=>", so they were deployed without a word.

Deploy them on all platforms, with a warning unless they are excluded,
as the loader only uses the copy if the path is relative to $ORIGIN and
the copy is at that path relative to the file which needs it. Exclude
them by their file name, also when they are missing. Skip the traced
file's PT_INTERP, which is listed without "=>", too, in case the
loader's file name is not recognized (e.g., LSB's ld-lsb-x86-64.so.3).

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
elf_file: Do not deploy preloaded libraries
4aba2af
ldd lists the libraries which $LD_PRELOAD or glibc's /etc/ld.so.preload
preload like dependencies, so they were deployed (e.g., libarmmem,
which Raspberry Pi OS preloads system-wide).

Skip all libraries $LD_PRELOAD and /etc/ld.so.preload list, which ldd
lists by their entry there (e.g., with $LIB), also those given by name
(e.g., fakeroot's libfakeroot-sysv.so). Keep $LD_PRELOAD for ldd, as
tools which rely on it (e.g., fakechroot) would not apply to it
otherwise. The dependencies of preloaded libraries are still deployed,
as ldd lists them like the program's. Warn once per deployment about
each skipped library, as one the program needs, too, is only listed as
preloaded.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
ci: Record the ldd calls of the tests
dc295c3
The mock tests replay the ldd calls of every platform, which must be
recorded on each of them.

test-dependency-tracing.sh --record <platform> runs the real tests and
replaces the platform's recordings, or only adds those which ran if the
tests failed or were filtered. build-in-docker.sh records if
$BUILD_TYPE is record-ldd-calls. Add the recordings of Debian, Alpine
(musl and LLVM), Gentoo (LLVM) and FreeBSD.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
ci: Add a dependency tracing job
ba02b8a
The dependency tracing tests do not run in CI.

Run test-dependency-tracing.sh on x86_64 in Debian (glibc with GCC),
Alpine (musl with GCC and LLVM) and Gentoo (musl with LLVM), and on
FreeBSD.

Signed-off-by: Pepper Gray <[email protected]>
@peppergrayxyz
ci: Apply the patches of unmerged PRs
808b81f
The musl builds need fixes which are not merged yet:
- linuxdeploy/linuxdeploy-plugin-appimage#45
- linuxdeploy/linuxdeploy-plugin-appimage#46
- linuxdeploy/linuxdeploy-desktopfile#11
- linuxdeploy/cmake-scripts#1

Carry them in ci/upstream-patches, and apply them in build.sh and the
workflow. Revert this commit once all of them are merged.

Signed-off-by: Pepper Gray <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

[musl/ldd] std::runtime_error: Failed to run ldd: exited with code 1 Add --strip and --appimagetool parameters to pass local locations of strip and appimagetool

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@peppergrayxyz
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.