Giter VIP home page Giter VIP logo

exodus's Introduction

Exodus Tweet Share on Facebook Share on Reddit Share on Hacker News

Build Status Coverage License PyPI Version

Exodus is a tool that makes it easy to successfully relocate Linux ELF binaries from one system to another. This is useful in situations where you don't have root access on a machine or where a package simply isn't available for a given Linux distribution. For example, CentOS 6.X and Amazon Linux don't have packages for Google Chrome or aria2. Server-oriented distributions tend to have more limited and outdated packages than desktop distributions, so it's fairly common that one might have a piece of software installed on their laptop that they can't easily install on a remote machine.

With exodus, transferring a piece of software that's working on one computer to another is as simple as this.

exodus aria2c | ssh intoli.com

Exodus handles bundling all of the binary's dependencies, compiling a statically linked wrapper for the executable that invokes the relocated linker directly, and installing the bundle in ~/.exodus/ on the remote machine. You can see it in action here.

Demonstration of usage with htop

Table of Contents

The Problem Being Solved

If you simply copy an executable file from one system to another, then you're very likely going to run into problems. Most binaries available on Linux are dynamically linked and depend on a number of external library files. You'll get an error like this when running a relocated binary when it has a missing dependency.

aria2c: error while loading shared libraries: libgnutls.so.30: cannot open shared object file: No such file or directory

You can try to install these libraries manually, or to relocate them and set LD_LIBRARY_PATH to wherever you put them, but it turns out that the locations of the ld-linux linker and the glibc libraries are hardcoded. Things can very quickly turn into a mess of relocation errors,

aria2c: relocation error: /lib/libpthread.so.0: symbol __getrlimit, version
GLIBC_PRIVATE not defined in file libc.so.6 with link time reference

segmentation faults,

Segmentation fault (core dumped)

or, if you're really unlucky, this very confusing symptom of a missing linker.

$ ./aria2c
bash: ./aria2c: No such file or directory
$ ls -lha ./aria2c
-rwxr-xr-x 1 sangaline sangaline 2.8M Jan 30 21:18 ./aria2c

Exodus works around these issues by compiling a small statically linked launcher binary that invokes the relocated linker directly with any hardcoded RPATH library paths overridden. The relocated binary will run with the exact same linker and libraries that it ran with on its origin machine.

Installation

The package can be installed from the package on pypi. Running the following will install exodus locally for your current user.

pip install --user exodus-bundler

You will then need to add ~/.local/bin/ to your PATH variable in order to run the exodus executable (if you haven't already done so). This can be done by adding

export PATH="~/.local/bin/:${PATH}"

to your ~/.bashrc file.

Optional/Recommended Dependencies

It is also highly recommended that you install gcc and one of either musl libc or diet libc on the machine where you'll be packaging binaries. If present, these small C libraries will be used to compile small statically linked launchers for the bundled applications. An equivalent shell script will be used as a fallback, but it carries significant overhead compared to the compiled launchers.

Usage

Command-Line Interface

The command-line interface supports the following options.

usage: exodus [-h] [-c CHROOT_PATH] [-a DEPENDENCY] [-d] [--no-symlink FILE]
              [-o OUTPUT_FILE] [-q] [-r [NEW_NAME]] [--shell-launchers] [-t]
              [-v]
              EXECUTABLE [EXECUTABLE ...]

Bundle ELF binary executables with all of their runtime dependencies so that
they can be relocated to other systems with incompatible system libraries.

positional arguments:
  EXECUTABLE            One or more ELF executables to include in the exodus
                        bundle.

optional arguments:
  -h, --help            show this help message and exit
  -c CHROOT_PATH, --chroot CHROOT_PATH
                        A directory that will be treated as the root during
                        linking. Useful for testing and bundling extracted
                        packages that won't run without a chroot. (default:
                        None)
  -a DEPENDENCY, --add DEPENDENCY, --additional-file DEPENDENCY
                        Specifies an additional file to include in the bundle,
                        useful for adding programatically loaded libraries and
                        other non-library dependencies. The argument can be
                        used more than once to include multiple files, and
                        directories will be included recursively. (default:
                        [])
  -d, --detect          Attempt to autodetect direct dependencies using the
                        system package manager. Operating system support is
                        limited. (default: False)
  --no-symlink FILE     Signifies that a file must not be symlinked to the
                        deduplicated data directory. This is useful if a file
                        looks for other resources based on paths relative its
                        own location. This is enabled by default for
                        executables. (default: [])
  -o OUTPUT_FILE, --output OUTPUT_FILE
                        The file where the bundle will be written out to. The
                        extension depends on the output type. The
                        "{{executables}}" and "{{extension}}" template strings
                        can be used in the provided filename. If omitted, the
                        output will go to stdout when it is being piped, or to
                        "./exodus-{{executables}}-bundle.{{extension}}"
                        otherwise. (default: None)
  -q, --quiet           Suppress warning messages. (default: False)
  -r [NEW_NAME], --rename [NEW_NAME]
                        Renames the binary executable(s) before packaging. The
                        order of rename tags must match the order of
                        positional executable arguments. (default: [])
  --shell-launchers     Force the use of shell launchers instead of attempting
                        to compile statically linked ones. (default: False)
  -t, --tarball         Creates a tarball for manual extraction instead of an
                        installation script. Note that this will change the
                        output extension from ".sh" to ".tgz". (default:
                        False)
  -v, --verbose         Output additional informational messages. (default:
                        False)

Examples

Piping Over SSH

The easiest way to install an executable bundle on a remote machine is to pipe the exodus command output over SSH. For example, the following will install the aria2c command on the intoli.com server.

exodus aria2c | ssh intoli.com

This requires that the default shell for the remote user be set to bash (or a compatible shell). If you use csh, then you need to additionally run bash on the remote server like this.

exodus aria2c | ssh intoli.com bash

Explicitly Adding Extra Files

Additional files can be added to bundles in a number of different ways. If there is a specific file or directory that you would like to include, then you can use the --add option. For example, the following command will bundle nmap and include the contents of /usr/share/nmap in the bundle.

exodus --add /usr/share/nmap nmap

You can also pipe a list of dependencies into exodus. This allows you to use standard Linux utilities to find and filter dependencies as you see fit. The following command sequence uses find to include all of the Lua scripts under /usr/share/nmap.

find /usr/share/nmap/ -iname '*.lua' | exodus nmap

These two approaches can be used together, and the --add flag can also be used multiple times in one command.

Auto-Detecting Extra Files

If you're not sure which extra dependencies are necessary, you can use the --detect option to query your system's package manager and automatically include any files in the corresponding packages. Running

exodus --detect nmap

will include the contents of /usr/share/nmap as well as its man pages and the contents of /usr/share/zenmap/. If you ever try to relocate a binary that doesn't work with the default configuration, the --detect option is a good first thing to try.

You can also pipe the output of strace into exodus and all of the files that are accessed will be automatically included. This is particularly useful in situations where shared libraries are loaded programmatically, but it can also be used to determine which files are necessary to run a specific command. The following command will determine all of the files that nmap accesses while running the set of default scripts.

strace -f nmap --script default 127.0.0.1 2>&1 | exodus nmap

The output of strace is then parsed by exodus and all of the files are included. It's generally more robust to use --detect to find the non-library dependencies, but the strace pattern can be indispensable when a program uses dlopen() to load libraries programmatically. Also, note that any files that a program accesses will be included in a bundle when following this approach. Never distribute a bundle without being certain that you haven't accidentally included a file that you don't want to make public.

Renaming Binaries

Multiple binaries that have the same name can be installed in parallel through the use of the --rename/-r option. Say that you have two different versions of grep on your local machine: one at /bin/grep and one at /usr/local/bin/grep. In that situation, using the -r flag allows you to assign aliases for each binary.

exodus -r grep-1 -r grep-2 /bin/grep /usr/local/bin/grep

The above command would install the two grep versions in parallel with /bin/grep called grep-1 and /usr/local/bin/grep called grep-2.

Manual Extraction

You can create a compressed tarball directly instead of the default script by specifying the --tarball option. To create a tarball, copy it to a remote server, and then extract it in ~/custom-location, you could run the following.

# Create the tarball.
exodus --tarball aria2c --output aria2c.tgz

# Copy it to the remote server and remove it locally.
scp aria2c.tgz intoli.com:/tmp/aria2c.tgz
rm aria2c.tgz

# Make sure that `~/custom-location` exists.
ssh intoli.com "mkdir -p ~/custom-location"

# Extract the tarball remotely.
ssh intoli.com "tar --strip 1 -C ~/custom-location -zxf /tmp/aria2c.tgz"

# Remove the remote tarball.
ssh intoli.com "rm /tmp/aria2c.tgz"

You will additionally need to add ~/custom-location/bin to your PATH variable on the remote server. This can be done by adding the following to ~/.bashrc on the remote server.

export PATH="~/custom-location/bin:${PATH}"

Adding to a Docker Image

Tarball formatted exodus bundles can easily be included in Docker images by using the ADD instruction. You must first create a bundle using the --tarball option

# Create and enter a directory for the Docker image.
mkdir jq
cd jq

# Generate the `exodus-jq-bundle.tgz` bundle.
exodus --tarball jq

and then create a Dockerfile file inside of the jq directory with the following contents.

FROM scratch
ADD exodus-jq-bundle.tgz /opt/
ENTRYPOINT ["/opt/exodus/bin/jq"]

The Docker image can then be built by running

docker build -t jq .

and jq can be run inside of the container.

docker run jq

This simple image will include only the jq binary and dependencies, but the bundles can be included in existing docker images in the same way. For example, adding

ENV PATH="/opt/exodus/bin:${PATH}"
ADD exodus-jq-bundle.tgz /opt/

to an existing Dockerfile will make the jq binary available for use inside the container.

How It Works

There are two main components to how exodus works:

  1. Finding and bundling all of a binary's dependencies.

  2. Launching the binary in such a way that the proper dependencies are used without any potential interaction from system libraries on the destination machine.

The first component is actually fairly simple. You can invoke ld-linux with the LD_TRACE_LOADED_OBJECTS environment variable set to 1 and it will list all of the resolved library dependencies for a binary. For example, running

LD_TRACE_LOADED_OBJECTS=1 /lib64/ld-linux-x86-64.so.2 /bin/grep

will output the following.

    linux-vdso.so.1 =>  (0x00007ffc7495c000)
    libpcre.so.0 => /lib64/libpcre.so.0 (0x00007f89b2f3e000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f89b2b7a000)
    libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f0e95e8c000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f89b3196000)

The linus-vdso.so.1 dependency refers to kernel space routines that are exported to user space, but the other four are shared library files on disk that are required in order to run grep. Notably, one of these dependencies is the /lib64/ld-linux-x86-64.so.2 linker itself. The location of this file is typically hardcoded into an ELF binary's INTERP header and the linker is invoked by the kernel when you run the program. We'll come back to that in a minute, but for now the main point is that we can find a binary's direct dependencies using the linker.

Of course, these direct dependencies might have additional dependencies of their own. We can iteratively find all of the necessary dependencies by following the same approach of invoking the linker again for each of the library dependencies. This isn't actually necessary for grep, but exodus does handle finding the full set of dependencies for you.

After all of the dependencies are found, exodus puts them together with the binary in a tarball that can be extracted (typically into either /opt/exodus/ or ~/.exodus). We can explore the structure of the grep bundle by using tree combined with a sed one-liner to truncate long SHA-256 hashes to 8 digits. Running

alias truncate-hashes="sed -r 's/([a-f0-9]{8})[a-f0-9]{56}/\1.../g'"
tree ~/.exodus/ | truncate-hashes

will show us all of the files and folders included in the grep bundle.

/home/sangaline/.exodus/
├── bin
│   └── grep -> ../bundles/3124cd96.../usr/bin/grep
├── bundles
│   └── 3124cd96...
│       ├── lib64
│       │   └── ld-linux-x86-64.so.2 -> ../../../data/dfd5de26...
│       └── usr
│           ├── bin
│           │   ├── grep
│           │   ├── grep-x -> ../../../../data/7477c1a7...
│           │   └── linker-dfd5de26...
│           └── lib
│               ├── libc.so.6 -> ../../../../data/6d0e1d45...
│               ├── libpcre.so.1 -> ../../../../data/a0862ebc...
│               └── libpthread.so.0 -> ../../../../data/85cb56a5...
└── data
    ├── 6d0e1d45...
    ├── 7477c1a7...
    ├── 85cb56a5...
    ├── a0862ebc...
    └── dfd5de26...

8 directories, 13 files

You can see that there are three top-level directories within ~/.exodus/: bin, bundles, and data. Let's cover these in reverse-alphabetical order, starting with the data directory.

The data directory contains the actual files from the bundles with names corresponding to SHA-256 hashes of their content. This is done so that multiple versions of a file with the same filename can be extracted in the data directory without overwriting each other. On the other hand, files that do have the same content will overwrite each other. This avoids the need to store multiple copies of the same data, even if the identical files appear in different bundles or directories.

Next, we have the bundles directory, which is full of subfolders that also have SHA-256 hashes as names. The hashes this time are determined based on the combined directory structure and content of everything included in the bundle. The hash provides a unique fingerprint for the bundle and allows multiple bundles to be extracted without their directory contents mixing.

Inside of each bundle subdirectory, the original directory structure of the bundle's contents on the host machine is mirrored. For this particular grep bundle, there are lib64, usr/bin, and usr/lib directories. A more complicated bundle could include additional files from /usr/share, /opt/local, a user's home directory, or really anywhere on the system (see the --add and --detect options). The files in both lib64 and usr/lib simply consist of symlinks to the actual library files in the top-level data/ directory. The usr/bin directory is a little more complicated.

The grep file isn't actually the original grep binary, it's a special executable that exodus constructs called a "launcher." A launcher is a tiny program that invokes the linker and overrides the library search path in such a way that our original binary can run without any system libraries being used and causing issues due to incompatibilities. The linker in this case is the linker-dfd5de26... file. This is located in the same directory so that resource paths can be resolved relative to the running executable. Finally, the grep-x symlink points to the actual grep binary that was bundled and extracted in the top-level data/ directory (this is the ELF file that the linker interprets).

When a C compiler and either musl libc or diet libc are available, exodus will compile a statically linked binary launcher. If neither of these are present, it will fall back to using a shell script to perform the task of the launcher. This adds a little bit of overhead relative to the binary launchers, but they are helpful for understanding what the launchers do. Here's the shell script version of the grep-launcher, for example.

#! /bin/bash

current_directory="$(dirname "$(readlink -f "$0")")"
executable="${current_directory}/./grep-x"
library_path="../../lib64:../lib64:../../lib:../lib:../../lib32:../lib32"
library_path="${current_directory}/${library_path//:/:${current_directory}/}"
linker="${current_directory}/./linker-dfd5de2638cea087685b67786050dcdc33aac7b67f5f8c2753b7da538517880a"
exec "${linker}" --library-path "${library_path}" --inhibit-rpath "" "${executable}" "$@"

You can see that the launcher first constructs the full paths for all of the LD_LIBRARY_PATH directories, the executable, and the linker based on its own location. It then executes the linker with a set of arguments that allow it to search the proper library directories, ignore the hardcoded RPATH, and run the binary with any command-line arguments passed along. This serves a similar purpose to something like patchelf that would modify the INTERP and RPATH of the binary, but it additionally allows for both the linker and library locations to be specified based solely on their relative locations. This is what allows for the exodus bundles to be extracted in ~/.exodus, /opt/exodus/, or any other location, as long as the internal bundle structure is preserved.

Continuing on with our reverse-alphabetical order, we finally get to the top-level bin directory. The top-level bin directory consists of symlinks of the binary names to their corresponding launchers. This allows for the addition of a single directory to a user's PATH variable in order to make the migrated exodus binaries accessible. For example, adding export PATH="~/.exodus/bin:${PATH}" to a ~/.bashrc file will add all of these entry points to a user's PATH and allow them to be run without specifying their full path.

Known Limitations

There are several scenarios under which bundling an application with exodus will fail. Many of these are things that we're working on and hope to improve in the future, but some are fundamentally by design and are unlikely to change. Here you can see an overview of situations where exodus will not be able to successfully relocate executables.

  • Non-ELF Binaries - Exodus currently only supports completely bundling ELF binaries. Interpreted executable files, like shell scripts, can be included in bundles, but their shebang interpreter directives will not be changed. This generally means that they will be interpreted using the system version of bash, python, perl, or whatever else. The problem that exodus aims to solve is largely centered around the dynamic linking of ELF binaries, so this is unlikely to change in the foreseeable future.
  • Incompatible CPU Architectures - Binaries compiled for one CPU architecture will generally not be able to run on a CPU of another architecture. There are some exceptions to this, for example x64 processors are backwards compatible with x86 instruction sets, but you will not be able to migrate x64 binaries to an x86 or an ARM machine. Doing so would require processor emulation, and this is definitely outside the scope of the exodus project. If you find yourself looking for a solution to this problem, then you might want to check out QEMU.
  • Incompatible Glibc and Kernel Versions - When glibc is compiled, it is configured to target a specific kernel version. Trying to run any software that was compiled against glibc on a system using an older kernel version than glibc's target version will result in a FATAL: kernel too old error. You can check the oldest supported kernel version for a binary by running file /path/to/binary. The output should include a string like for GNU/Linux 2.6.32 which signifies the oldest kernel version that the binary is compatible with. As a workaround, you can create exodus bundles in a Docker image using an operating system image which supports older kernels (e.g. use an outdated version of the operating system).
  • Driver Dependent Libraries - Unlike some other application bundlers, exodus aims to include all of the required libraries when the bundle is created and to completely isolate the transported binary from the destination machine's system libraries. This means that any libraries which are compiled for specific hardware drivers will only work on machines with the same drivers. A key example of this is the libGLX_indirect.so library which can link to either libGLX_mesa.so or libGLX_nvidia.so depending on which graphics card drivers are used on a given system. Bundling dependencies that are not locally available on the source machine is fundamentally outside the scope of what exodus is designed to do, and this will never change.

Development

The development environment can be setup by running the following.

# Clone the repository.
git clone https://github.com/intoli/exodus.git
cd exodus

# Create and enter a virtualenv.
virtualenv .env
. .env/bin/activate

# Install the development requirements.
pip install -r development-requirements.txt

# Install the exodus package in editable mode.
pip install -e .

The test suite can then be run using tox.

tox

Contributing

Contributions are welcome, but please follow these contributor guidelines outlined in CONTRIBUTING.md.

License

Exodus is licensed under a BSD 2-Clause License and is copyright Intoli, LLC.

exodus's People

Contributors

juergenhoetzel avatar paralax avatar sangaline avatar ss18 avatar swjz avatar vielmetti avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

exodus's Issues

cannot handle x as a builtin

I tried to pack git but after running it on remote I get:
cannot handle x as a builtin

is it work with the most application or it is an exception?
how do I make Exodus to pack git correctly?

  • Which Python version. v2

Modify Laucher and Executable names

  • OS = Kali Linux rolling 2023.2
  • Python 3.11.2
  • exodus-bundler 2.0.4 (From pipx, no --version option in exodus)
  • Binary = /usr/bin/kmod
  • readelf -a /usr/bin/kmod output = readelf-kmod.txt

I created an exodus bundle for kmod program using the following command:

exodus --shell-launchers -o kmod-bundle.tgz -t -v -a /usr/lib/libkmod.la -a /usr/lib/libkmod.so -a /usr/lib/libkmod.so.2 -a /usr/lib/libkmod.so.2.4.0 /usr/bin/depmod /usr/bin/insmod /usr/bin/kmod /usr/bin/lsmod /usr/bin/modinfo /usr/bin/modprobe /usr/bin/rmmod

kmod and its symlinks failed to run, terminating with 254 status code. kmod verifies its argv[0] using program_invocation_short_name() to determine what it will run as, kind of like busybox. To fix this, I renamed launcher scripts in exodus/bundles/3d77fd2.../<launcher> to add a .sh suffix. Then I renamed exodus/bundles/3d77fd2.../<progname>-x to remove -x suffix, hence regaining their original names. I edited the launcher scripts to remove the -x suffix accordingly. This is why I used --shell-launchers instead of binary ones. I then re-symlinked launcher scripts from exodus/bundles/3d77fd2.../<launcher>.sh to exodus/bin/<progname> so they would point to they newly renamed launchers. kmod worked just fine after that.

My suggestion is that launcher files in exodus/bundles/<hash>/<launcher> have a .sh suffix if shell-based or .bin suffix if binary. This way the ported programs in exodus/bundles/<hash>/<progname> will have their original names, incase they use it to determine what to run as. The symlinks to launchers in exodus/bin/<progname> will also have the same original names as the programs ported, so user experience will not be impacted. Also, a --version option would be great in exodus.

pyinstaller --onefile output elf does not work

os: ubuntu16.04 server
cpu: x86-64
python: 3.6.3

"pyinstaller --onefile t.py" output an elf file, t.

exodus ./dist/t -o /tmp/t -> ok

/tmp/t -> ok

/opt/exodus/bin/t -> error

error detail:

[4092] Cannot open self /opt/exodus/bundles/3cad7d5bdde37965bddba10dea540f3609875ee80cb5215cabb459b05c5880ea/root/tmp/dist/linker-6d0bfd685a7ad6dfccae1fae70c1f06018a0f756c53de0aabb609456a10f3747 or archive /opt/exodus/bundles/3cad7d5bdde37965bddba10dea540f3609875ee80cb5215cabb459b05c5880ea/root/tmp/dist/linker-6d0bfd685a7ad6dfccae1fae70c1f06018a0f756c53de0aabb609456a10f3747.pkg

Remove/uninstall the given package

It'd be very helpful to describe in readme.md how to remove/uninstall a package incl. all the pros & cons/potential_issues.

Or generate an uninstall script which will be installed along with the given binary?

Make exodus compliant with XDG base directory specification

Exodus uses $HOME/.exodus directory as storage on a target system. Such a "yet-another-dot-file in home directory" has issues with many users. Some readings on that:

Please make exodus compliant with XDG base-directory specification:

For instance:

  • $HOME/.exodus/bundle -> $HOME/.local/share/exodus/bundle
  • $HOME/.exodus/data -> $HOME/.localshare/exodus/data
  • $HOME/.exodus/bin -> $HOME/.local/bin

Exodus outputs fail on Steam Deck

I'm trying to use exodus on an Ubuntu 20.04 box to make a bundle for GNU screen and put it on my Steam Deck (which runs SteamOS 3.3.2, itself a downstream derivative of Arch Linux). The same bundle, which works flawlessly on non-SteamOS systems, produces the following output when run on my Steam Deck:

$ screen
getpwuid() can't identify your account!

I'm not sure where to poke to diagnose this. Any help would be appreciated.


Host OS: Ubuntu 20.04 x86_64
Target OS: SteamOS 3.3.2 (ArchLinux derivative)
Python version: 3.8.10
Exodus package version: 2.0.4
Command: exodus screen | ssh [email protected]
Output:

$ exodus --verbose screen | ssh [email protected]
Pseudo-terminal will not be allocated because stdin is not a terminal.
[email protected]'s password:
Installing executable bundle in "/home/deck/.exodus"...
Successfully installed, be sure to add /home/deck/.exodus/bin to your $PATH.

Commands run on host:

$ which screen
/usr/bin/screen
$ readelf -a /usr/bin/screen
<very long output that I'll include as the first comment>
$ echo $PATH
/home/<username>/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/<username>/.fzf/bin
$ echo $LD_LIBRARY_PATH
$

Commands run on target:

$ which screen
/home/deck/.exodus/bin/screen
$ readelf -a /home/deck/.exodus/bin/screen
<very long output that I'll include in the first comment>
$ echo $PATH
/home/deck/.local/bin:/home/deck/.exodus/bin:/home/deck/.local/podman/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/var/lib/flatpak/exports/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
$ echo $LD_LIBRARY_PATH
$

Graphical applications cannot get the X11 display when run on older distributions than the base target

Operating system, Python and Exodus version: Fedora 27, Python 3.6.4, Exodus 1.1.6
Target OS: Ubuntu 14.04

I successfully bundled Godot and Minetest binaries built on Fedora 27. However, while they are able to start up (for example, the -h flag can be passed to display the program's help text), they cannot retrieve the X11 display.

See the Godot startup log below for an example:

ERROR: initialize: Condition ' !fbc ' is true. returned: ERR_UNCONFIGURED
   At: platform/x11/context_gl_x11.cpp:121.
ERROR: initialize: Condition ' x11_window == 0 ' is true. returned: ERR_UNAVAILABLE
   At: platform/x11/os_x11.cpp:339.

Minetest startup log:

2018-02-05 18:15:17: WARNING[Main]: system-wide share not found at "/usr/local/share/minetest"
2018-02-05 18:15:17: WARNING[Main]: system-wide share not found at "/home/ubuntu/.exodus/lib/../share/minetest"
2018-02-05 18:15:17: WARNING[Main]: system-wide share not found at "/home/ubuntu/.exodus/lib/.."
2018-02-05 18:15:17: WARNING[Main]: Couldn't find a locale directory!
2018-02-05 18:15:17: ERROR[Main]: Subgame specified in default_game [minetest] is invalid.
2018-02-05 18:15:17: WARNING[Main]: Irrlicht: No doublebuffering available.
2018-02-05 18:15:17: ERROR[Main]: Irrlicht: Fatal error, could not get visual.
2018-02-05 18:15:17: ERROR[Main]: Could not initialize game engine.

In contrast, AppImages of the same programs built on Ubuntu 14.04 run successfully.

Can I use exodus to run Dying Light on Arch Linux?

Hello.

Dying Light is a game that currently only works on Ubuntu and its derivatives. I'm trying to get it to work on Arch Linux. The game logs suggest an issue with glibc.

Can I use exodus in this scenario?

Any tips would be appreciated. :)

Improve error handling and logging

There have been a couple of issues submitted where exceptions were raised that didn't really make it clear what their root causes were (e.g. #5 and #6). These sort of exceptions should be caught and logged with informative messages.

AssertionError: No linker candidates found.

on Ubuntu 16.04,

> which ldd
/usr/bin/ldd
> exodus ldd
Traceback (most recent call last):
  File "/.../.local/bin/exodus", line 11, in <module>
    sys.exit(main())
  File "/.../.local/lib/python2.7/site-packages/exodus_bundler/cli.py", line 113, in main
    create_bundle(**args)
  File "/.../.local/lib/python2.7/site-packages/exodus_bundler/bundling.py", line 32, in create_bundle
    root_directory = create_unpackaged_bundle(executables, rename=rename, ldd=ldd)
  File "/.../.local/lib/python2.7/site-packages/exodus_bundler/bundling.py", line 133, in create_unpackaged_bundle
    assert len(linker_candidates) > 0, 'No linker candidates found.'
AssertionError: No linker candidates found.

FATAL: kernel too old

Please include the following information if you're reporting an issue.

request response
Which operating system you're using. source:Ubuntu 17.1, dest: Centos 6.5
Which Python version. source: Python 2.7.14
Which exodus package version. release v1.1.9

NOTE exodus and/or exodus -h don't print a version number
The command that you're running exodus --verbose /usr/bin/duc | ssh my.destination.server.com
The full output of the command. Pseudo-terminal will not be allocated because stdin is not a terminal
Installing executable bundle in "/home/speare/.exodus"...
Successfully installed, be sure to add /home/speare/.exodus/bin to your $PATH.
which $BINARY /usr/bin/duc

I can provide rest of details on request. Not sure they're relevant here.

Output of uname -r

source dest
4.13.0-32-generic 2.6.32-696.10.3.el6.x86_64

Attempting to run ~/.exodus/bin/duc at destination returns FATAL: kernel too old

Any way to make this work?

vfork

I am attempting to use exodus (installed with pip exodus, on python2) on a mock container (epel-7). The idea is to build a linux universal version of CEF3, using my own starter application.

The application uses:

#if defined(OS_LINUX)
b->pid = vfork();
if (b->pid < 0) {
set_error("launch_browser2: vfork failed");
return false;
} else if (b->pid == 0) {
/* child branch of fork */

    execl(cefpath, cefpath, p1, p2, p3, p4, ed, de, pr, nm, ps, lg,
                            ca,
                            b->options[ 0], b->options[ 1],
                            b->options[ 2], b->options[ 3],
                            b->options[ 4], b->options[ 5],
                            b->options[ 6], b->options[ 7],
                            b->options[ 8], b->options[ 9],
                            b->options[10], b->options[11],
                            b->options[12], b->options[13],
                            b->options[14], b->options[15],
                            b->options[16], b->options[17],
                            b->options[18], b->options[19],
                            NULL);
    /* Note that UNTIL _exit() is done, the parent is paused. So,
     * we have *not* done the fdopen(b->pipe1, "r") in the
     * parent yet.
     *
     * If replacing vfork() with fork(), semantics are changed. The
     * purpose of this code is to force an error in the initial
     * handshake between parent and child. However this is done, is
     * ok. If open_browser() returns true, the communications pipe
     * is open, and the browser process is accepting commands and
     * generating replies. open_browser() returning false means that
     * this state has not been achieved.
     */
    close(b->pipe1[WRITE]);
    close(b->pipe2[READ]);
    close(b->pipe1[READ]);
    close(b->pipe2[WRITE]);

    /* The child must *never* return. */
    _exit(13);
}

to launch the executable, which has been bundled with exodus. The following happens (strace, with some annotations):

...
====== attempting to supply chrome with a directory for disk caching
mkdir("/tmp/cef", 0777) = -1 EEXIST (File exists)
openat(AT_FDCWD, "/tmp/cef/cef_cache_lock", O_RDONLY|O_CREAT|O_EXCL, 0644) = -1 EEXIST (File exists)
openat(AT_FDCWD, "/tmp/cef/cef_cache_lock", O_RDONLY) = 12
read(12, "", 4) = 0
close(12) = 0
kill(1, SIG_0) = -1 EPERM (Operation not permitted)
unlink("/tmp/cef/cef_cache_lock") = 0
openat(AT_FDCWD, "/tmp/cef/cef_cache_lock", O_RDONLY|O_CREAT|O_EXCL, 0644) = 12
write(12, "\0\0\0\0", 4) = -1 EBADF (Bad file descriptor)
close(12) = 0
====== beginning of launch of exodus bundled application
write(2, "libbrowser: trace: launch_browse"..., 34libbrowser: trace: launch_browser
) = 34

====== first, we vfork() pausing parent, and let child exec the bundled chrome browser app
vfork() = 5260
====== wait for affirmative to proceed
fcntl(3, F_GETFL) = 0 (flags O_RDONLY)
fstat(3, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
read(3, 0x21a29e0, 4096) = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
====== OOPS! didn't work as we expected
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_KILLED, si_pid=5260, si_uid=1000, si_status=SIGTRAP, si_utime=2, si_stime=29}} ---
read(3,

and we hang here.

It should look like this (non-bundled app):
...
mkdir("/tmp/cef", 0777) = -1 EEXIST (File exists)
openat(AT_FDCWD, "/tmp/cef/cef_cache_lock", O_RDONLY|O_CREAT|O_EXCL, 0644) = -1 EEXIST (File exists)
openat(AT_FDCWD, "/tmp/cef/cef_cache_lock", O_RDONLY) = 12
read(12, "", 4) = 0
close(12) = 0
kill(1, SIG_0) = -1 EPERM (Operation not permitted)
unlink("/tmp/cef/cef_cache_lock") = 0
openat(AT_FDCWD, "/tmp/cef/cef_cache_lock", O_RDONLY|O_CREAT|O_EXCL, 0644) = 12
write(12, "\0\0\0\0", 4) = -1 EBADF (Bad file descriptor)
close(12) = 0
write(2, "libbrowser: trace: launch_browse"..., 34libbrowser: trace: launch_browser
) = 34
vfork() = 5371
fcntl(3, F_GETFL) = 0 (flags O_RDONLY)
fstat(3, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
read(3, "HELLO 6,Wed May 16 22:29:45 EDT "..., 4096) = 100
...

Docker benefits

Simply wanted to point at the following which makes use of your great tool. This technique is able to squeeze down Docker images to a minimum, while still benefiting from the giant software and package catalog in Debian (or derivatives).

Thanks for this. I didn't think it was worth a PR as it is merely using exodus, rather than extending it. But maybe migrating in the main Dockerfile is something that you would be interested in?

generated sh file doesn't work with busybox tar

Please include the following information if you're reporting an issue.

  • Which operating system you're using.
    linux
  • Which Python version.
    python3
  • Which exodus package version.
    1.1.8
  • The command that you're running (please include the --verbose flag so that the stack trace is included).
    exodus /usr/bin/ffmpeg (yes, I know this is crazy)
  • The full output of the command.
    there is none, the command succeeds.
  • Where $BINARY is the name of the executable that you're trying to bundle, include the outputs of the following:
    • which $BINARY
    • readelf -a $BINARY
    • echo $PATH
    • echo $LD_LIBRARY_PATH

tar: unrecognized option '--preserve-permissions'

because the target system uses busybox. :(

Bug or maybe Feature request (?): bundling `.so`s together

Hello there,

I've resorted to using the 2.0 version of libtree for this, but the maintainer of that package suggests in his README that I'd probably be better off with yours.
I've been tryin to find a way to bundle a haskell .so with all of its many many dependencies.

When I try to create an archive with exodus I get the following:

 ❯ exodus -v dist-newstyle/build/x86_64-linux/ghc-9.6.3/hstherac25-0.1.0.0/build/libHShstherac25-0.1.0.0-inplace-ghc9.6.3.so -t                                                                     [17:42:49]
WARNING: An ELF binary without a suitable linker candidate was encountered. Either no linker was found or there are multiple conflicting linkers.
Successfully created "./exodus-libHShstherac25-0.1.0.0-inplace-ghc9.6.3.so-bundle.tgz".


 ❯ tar xavf exodus-libHShstherac25-0.1.0.0-inplace-ghc9.6.3.so-bundle.tgz                                                                                                                           [17:43:09]
exodus/
exodus/bin/
exodus/bin/libHShstherac25-0.1.0.0-inplace-ghc9.6.3.so
exodus/bundles/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/wrath/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/wrath/Documents/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/wrath/Documents/Unreal Projects/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/wrath/Documents/Unreal Projects/MyProject3 5.3/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/wrath/Documents/Unreal Projects/MyProject3 5.3/Plugins/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/wrath/Documents/Unreal Projects/MyProject3 5.3/Plugins/hstherac25/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/wrath/Documents/Unreal Projects/MyProject3 5.3/Plugins/hstherac25/dist-newstyle/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/wrath/Documents/Unreal Projects/MyProject3 5.3/Plugins/hstherac25/dist-newstyle/build/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/wrath/Documents/Unreal Projects/MyProject3 5.3/Plugins/hstherac25/dist-newstyle/build/x86_64-linux/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/wrath/Documents/Unreal Projects/MyProject3 5.3/Plugins/hstherac25/dist-newstyle/build/x86_64-linux/ghc-9.6.3/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/wrath/Documents/Unreal Projects/MyProject3 5.3/Plugins/hstherac25/dist-newstyle/build/x86_64-linux/ghc-9.6.3/hstherac25-0.1.0.0/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/wrath/Documents/Unreal Projects/MyProject3 5.3/Plugins/hstherac25/dist-newstyle/build/x86_64-linux/ghc-9.6.3/hstherac25-0.1.0.0/build/
exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/wrath/Documents/Unreal Projects/MyProject3 5.3/Plugins/hstherac25/dist-newstyle/build/x86_64-linux/ghc-9.6.3/hstherac25-0.1.0.0/build/libHShstherac25-0.1.0.0-inplace-ghc9.6.3.so

❯ ldd exodus/bundles/2470b10d94573c427aec94b04cc007ec67c2aa67c292b2f84552f6751f6411f4/home/wrath/Documents/Unreal\ Projects/MyProject3\ 5.3/Plugins/hstherac25/dist-newstyle/build/x86_64-linux/ghc-9.6.3/hstherac25-0.1.0.0/build/libHShstherac25-0.1.0.0-inplace-ghc9.6.3.so
        linux-vdso.so.1 (0x00007ffcdb6bc000)
        libm.so.6 => /usr/lib/libm.so.6 (0x00007fbcae618000)
        libHSrandom-1.2.1.1-f75323201d1b45182ed9370fb261ee029c5dbe1b59bf181cffc1aadffc6d66a4-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/random-1.2.1.1-f75323201d1b45182ed9370fb261ee029c5dbe1b59bf181cffc1aadffc6d66a4/lib/libHSrandom-1.2.1.1-f75323201d1b45182ed9370fb261ee029c5dbe1b59bf181cffc1aadffc6d66a4-ghc9.6.3.so (0x00007fbcae52a000)
        libHSsplitmix-0.1.0.5-4d43824a2aa15437e433f1a344653af933edf881ad9f72fc820c1c827832bfcb-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/splitmix-0.1.0.5-4d43824a2aa15437e433f1a344653af933edf881ad9f72fc820c1c827832bfcb/lib/libHSsplitmix-0.1.0.5-4d43824a2aa15437e433f1a344653af933edf881ad9f72fc820c1c827832bfcb-ghc9.6.3.so (0x00007fbcae50d000)
        libHSlens-5.2.3-d86330203b171f824d4fb69c91ee964741811590afac463378cc38fa94cf725b-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/lens-5.2.3-d86330203b171f824d4fb69c91ee964741811590afac463378cc38fa94cf725b/lib/libHSlens-5.2.3-d86330203b171f824d4fb69c91ee964741811590afac463378cc38fa94cf725b-ghc9.6.3.so (0x00007fbcade00000)
        libHSstrict-0.5-1a0c8f31aff2b2f1a8ae2f87d1569e7d08ca311d4a6f56f8f2ee0b62023ef159-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/strict-0.5-1a0c8f31aff2b2f1a8ae2f87d1569e7d08ca311d4a6f56f8f2ee0b62023ef159/lib/libHSstrict-0.5-1a0c8f31aff2b2f1a8ae2f87d1569e7d08ca311d4a6f56f8f2ee0b62023ef159-ghc9.6.3.so (0x00007fbcae47f000)
        libHSthese-1.2-3b1f6a11eac936dc57ccf3a6f07e8171cab1162bd8998b3ed3f34a6961b31092-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/these-1.2-3b1f6a11eac936dc57ccf3a6f07e8171cab1162bd8998b3ed3f34a6961b31092/lib/libHSthese-1.2-3b1f6a11eac936dc57ccf3a6f07e8171cab1162bd8998b3ed3f34a6961b31092-ghc9.6.3.so (0x00007fbcae42c000)
        libHSreflection-2.1.7-d3ea139d0f0c86e438da896be8449e191ce76e2eb27fb3832c7ab9f126b03f39-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/reflection-2.1.7-d3ea139d0f0c86e438da896be8449e191ce76e2eb27fb3832c7ab9f126b03f39/lib/libHSreflection-2.1.7-d3ea139d0f0c86e438da896be8449e191ce76e2eb27fb3832c7ab9f126b03f39-ghc9.6.3.so (0x00007fbcae353000)
        libHSparallel-3.2.2.0-47f7bdfc8e3ebb1c5d47a9407f58023050cb41106995f3c799e5470ffe686f82-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/parallel-3.2.2.0-47f7bdfc8e3ebb1c5d47a9407f58023050cb41106995f3c799e5470ffe686f82/lib/libHSparallel-3.2.2.0-47f7bdfc8e3ebb1c5d47a9407f58023050cb41106995f3c799e5470ffe686f82-ghc9.6.3.so (0x00007fbcadddd000)
        libHSkan-extensions-5.2.5-caf79b634b34a2578a14947c1f9ad16c74b1ac02b506800d20ab10c6f00455fd-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/kan-extensions-5.2.5-caf79b634b34a2578a14947c1f9ad16c74b1ac02b506800d20ab10c6f00455fd/lib/libHSkan-extensions-5.2.5-caf79b634b34a2578a14947c1f9ad16c74b1ac02b506800d20ab10c6f00455fd-ghc9.6.3.so (0x00007fbcadd3d000)
        libHSinvariant-0.6.2-a94e80bc2e928d55a3998fed401ab0f7700939305f774f996a17360c1d21c7bf-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/invariant-0.6.2-a94e80bc2e928d55a3998fed401ab0f7700939305f774f996a17360c1d21c7bf/lib/libHSinvariant-0.6.2-a94e80bc2e928d55a3998fed401ab0f7700939305f774f996a17360c1d21c7bf-ghc9.6.3.so (0x00007fbcadca8000)
        libHSadjunctions-4.4.2-be0d55c942fd250565ff3d59e24adb183a5cc27a3eea2be15eb18e07f640e208-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/adjunctions-4.4.2-be0d55c942fd250565ff3d59e24adb183a5cc27a3eea2be15eb18e07f640e208/lib/libHSadjunctions-4.4.2-be0d55c942fd250565ff3d59e24adb183a5cc27a3eea2be15eb18e07f640e208-ghc9.6.3.so (0x00007fbcadc19000)
        libHSvoid-0.7.3-22aac5bb8791896db13a8d9b34807b38c940d3d87c2ca2580c03ce7ef0dad7ed-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/void-0.7.3-22aac5bb8791896db13a8d9b34807b38c940d3d87c2ca2580c03ce7ef0dad7ed/lib/libHSvoid-0.7.3-22aac5bb8791896db13a8d9b34807b38c940d3d87c2ca2580c03ce7ef0dad7ed-ghc9.6.3.so (0x00007fbcadc14000)
        libHSsemigroups-0.20-9709772c97f16ed43a4621fe6e68cdf0ee2e547307f67935115fb6aa13cb2a8c-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/semigroups-0.20-9709772c97f16ed43a4621fe6e68cdf0ee2e547307f67935115fb6aa13cb2a8c/lib/libHSsemigroups-0.20-9709772c97f16ed43a4621fe6e68cdf0ee2e547307f67935115fb6aa13cb2a8c-ghc9.6.3.so (0x00007fbcadc09000)
        libHSindexed-traversable-instances-0.1.1.2-1d35d36596faa42be3cbf4e3c0d707101af9d6b45dd5a1e54ce37b9d9d7848aa-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/indexed-traversable-instances-0.1.1.2-1d35d36596faa42be3cbf4e3c0d707101af9d6b45dd5a1e54ce37b9d9d7848aa/lib/libHSindexed-traversable-instances-0.1.1.2-1d35d36596faa42be3cbf4e3c0d707101af9d6b45dd5a1e54ce37b9d9d7848aa-ghc9.6.3.so (0x00007fbcadbfb000)
        libHSvector-0.13.1.0-5c96f8edc96f72bd49c95ceca1fc3a7a7432ddad0bd5edfc469fb7a55616d510-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/vector-0.13.1.0-5c96f8edc96f72bd49c95ceca1fc3a7a7432ddad0bd5edfc469fb7a55616d510/lib/libHSvector-0.13.1.0-5c96f8edc96f72bd49c95ceca1fc3a7a7432ddad0bd5edfc469fb7a55616d510-ghc9.6.3.so (0x00007fbcad600000)
        libHSvector-stream-0.1.0.0-cd544f2a524119b745a23e3409aa3f38b5d18471174a3ec15e48fdb0b32df517-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/vector-stream-0.1.0.0-cd544f2a524119b745a23e3409aa3f38b5d18471174a3ec15e48fdb0b32df517/lib/libHSvector-stream-0.1.0.0-cd544f2a524119b745a23e3409aa3f38b5d18471174a3ec15e48fdb0b32df517-ghc9.6.3.so (0x00007fbcadba4000)
        libHSprimitive-0.9.0.0-e830a334559f9de6ae712c9ffba86091aae783ed0e65392e938048ba95f15f2d-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/primitive-0.9.0.0-e830a334559f9de6ae712c9ffba86091aae783ed0e65392e938048ba95f15f2d/lib/libHSprimitive-0.9.0.0-e830a334559f9de6ae712c9ffba86091aae783ed0e65392e938048ba95f15f2d-ghc9.6.3.so (0x00007fbcad51d000)
        libHSOneTuple-0.4.1.1-25a6728f7eaaed6f25c0c84b9d23c563689aba5664fafb9d25de1e8b6e93e436-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/OneTuple-0.4.1.1-25a6728f7eaaed6f25c0c84b9d23c563689aba5664fafb9d25de1e8b6e93e436/lib/libHSOneTuple-0.4.1.1-25a6728f7eaaed6f25c0c84b9d23c563689aba5664fafb9d25de1e8b6e93e436-ghc9.6.3.so (0x00007fbcadb9d000)
        libHSfree-5.2-d3e25ab10ce10f04e201b36c924319de2e34f33b465116f4f3dc1d6eb10ac4e8-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/free-5.2-d3e25ab10ce10f04e201b36c924319de2e34f33b465116f4f3dc1d6eb10ac4e8/lib/libHSfree-5.2-d3e25ab10ce10f04e201b36c924319de2e34f33b465116f4f3dc1d6eb10ac4e8-ghc9.6.3.so (0x00007fbcad200000)
        libHStransformers-base-0.4.6-7c5a8ca4b546fee71e383ab67aa6d04821890ff83d9df8fa9270fd287319cc2f-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/transformers-base-0.4.6-7c5a8ca4b546fee71e383ab67aa6d04821890ff83d9df8fa9270fd287319cc2f/lib/libHStransformers-base-0.4.6-7c5a8ca4b546fee71e383ab67aa6d04821890ff83d9df8fa9270fd287319cc2f-ghc9.6.3.so (0x00007fbcadb8a000)
        libHSsemigroupoids-6.0.0.1-d56f88db2e1891ee087502046796957cae68c5b2ce657ace8f34eccdd8b0241a-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/semigroupoids-6.0.0.1-d56f88db2e1891ee087502046796957cae68c5b2ce657ace8f34eccdd8b0241a/lib/libHSsemigroupoids-6.0.0.1-d56f88db2e1891ee087502046796957cae68c5b2ce657ace8f34eccdd8b0241a-ghc9.6.3.so (0x00007fbcad0d3000)
        libHSunordered-containers-0.2.19.1-fe823f0c4c35e091e52d2033a63fb26d634c96f699768c5240411cca0b2d0108-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/unordered-containers-0.2.19.1-fe823f0c4c35e091e52d2033a63fb26d634c96f699768c5240411cca0b2d0108/lib/libHSunordered-containers-0.2.19.1-fe823f0c4c35e091e52d2033a63fb26d634c96f699768c5240411cca0b2d0108-ghc9.6.3.so (0x00007fbcad458000)
        libHShashable-1.4.3.0-98acfc8d400a5c987d553ee7033a1f0d4393f505a0071034b204862e7038d80e-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/hashable-1.4.3.0-98acfc8d400a5c987d553ee7033a1f0d4393f505a0071034b204862e7038d80e/lib/libHShashable-1.4.3.0-98acfc8d400a5c987d553ee7033a1f0d4393f505a0071034b204862e7038d80e-ghc9.6.3.so (0x00007fbcad07a000)
        libHStext-2.0.2-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHStext-2.0.2-ghc9.6.3.so (0x00007fbcacc00000)
        libHSbinary-0.8.9.1-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHSbinary-0.8.9.1-ghc9.6.3.so (0x00007fbcacfac000)
        libHSprofunctors-5.6.2-cb1b6de2336c1f667ba432012ca7d50fecaf3f97a419f3decd0576c1f4f3dd56-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/profunctors-5.6.2-cb1b6de2336c1f667ba432012ca7d50fecaf3f97a419f3decd0576c1f4f3dd56/lib/libHSprofunctors-5.6.2-cb1b6de2336c1f667ba432012ca7d50fecaf3f97a419f3decd0576c1f4f3dd56-ghc9.6.3.so (0x00007fbcacb07000)
        libHSfilepath-1.4.100.4-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHSfilepath-1.4.100.4-ghc9.6.3.so (0x00007fbcaca43000)
        libHSexceptions-0.10.7-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHSexceptions-0.10.7-ghc9.6.3.so (0x00007fbcacf68000)
        libHSmtl-2.3.1-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHSmtl-2.3.1-ghc9.6.3.so (0x00007fbcacf17000)
        libHScontravariant-1.5.5-70d7f156408038e9752dcbba632c9c365900dde64d1872b1b3f3370b60d23395-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/contravariant-1.5.5-70d7f156408038e9752dcbba632c9c365900dde64d1872b1b3f3370b60d23395/lib/libHScontravariant-1.5.5-70d7f156408038e9752dcbba632c9c365900dde64d1872b1b3f3370b60d23395-ghc9.6.3.so (0x00007fbcadb51000)
        libHSStateVar-1.2.2-a828c4fffd0a9f376bdf1d2a0630fdc0e11764f2810422e01054ef1e5ae7a0d9-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/StateVar-1.2.2-a828c4fffd0a9f376bdf1d2a0630fdc0e11764f2810422e01054ef1e5ae7a0d9/lib/libHSStateVar-1.2.2-a828c4fffd0a9f376bdf1d2a0630fdc0e11764f2810422e01054ef1e5ae7a0d9-ghc9.6.3.so (0x00007fbcad44a000)
        libHSstm-2.5.1.0-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHSstm-2.5.1.0-ghc9.6.3.so (0x00007fbcad428000)
        libHScall-stack-0.4.0-6b79b48eec86a399d2f53fdf1d97dcbb176b61c50b0a51bdfd4155b328bd3be6-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/call-stack-0.4.0-6b79b48eec86a399d2f53fdf1d97dcbb176b61c50b0a51bdfd4155b328bd3be6/lib/libHScall-stack-0.4.0-6b79b48eec86a399d2f53fdf1d97dcbb176b61c50b0a51bdfd4155b328bd3be6-ghc9.6.3.so (0x00007fbcad41c000)
        libHSbytestring-0.11.5.2-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHSbytestring-0.11.5.2-ghc9.6.3.so (0x00007fbcac8de000)
        libHSbifunctors-5.6.1-821163cc03fae21b74f29dca370e811f63a65f46c62cfe96d1425caa200f3c5c-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/bifunctors-5.6.1-821163cc03fae21b74f29dca370e811f63a65f46c62cfe96d1425caa200f3c5c/lib/libHSbifunctors-5.6.1-821163cc03fae21b74f29dca370e811f63a65f46c62cfe96d1425caa200f3c5c-ghc9.6.3.so (0x00007fbcac763000)
        libHSth-abstraction-0.6.0.0-4b7fd6ddae43ee14f43798c73010233dd357bc47de41458d8a4e4c8fc084082b-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/th-abstraction-0.6.0.0-4b7fd6ddae43ee14f43798c73010233dd357bc47de41458d8a4e4c8fc084082b/lib/libHSth-abstraction-0.6.0.0-4b7fd6ddae43ee14f43798c73010233dd357bc47de41458d8a4e4c8fc084082b-ghc9.6.3.so (0x00007fbcac6c5000)
        libHScomonad-5.0.8-db6fdc8475375a8088bde8f5f0a18ec7839b5f7135bfd4a1b039ae844bb9f9f7-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/comonad-5.0.8-db6fdc8475375a8088bde8f5f0a18ec7839b5f7135bfd4a1b039ae844bb9f9f7/lib/libHScomonad-5.0.8-db6fdc8475375a8088bde8f5f0a18ec7839b5f7135bfd4a1b039ae844bb9f9f7-ghc9.6.3.so (0x00007fbcac674000)
        libHStransformers-compat-0.7.2-25923a9ee3488abd71a022b0310fa410647c6ac733dd896576b6e366ef80fd82-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/transformers-compat-0.7.2-25923a9ee3488abd71a022b0310fa410647c6ac733dd896576b6e366ef80fd82/lib/libHStransformers-compat-0.7.2-25923a9ee3488abd71a022b0310fa410647c6ac733dd896576b6e366ef80fd82-ghc9.6.3.so (0x00007fbcac611000)
        libHSindexed-traversable-0.1.3-5c151c51a16fe848251abf60409384564a48ba07895ffcc7c55051ccad6ef1c8-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/indexed-traversable-0.1.3-5c151c51a16fe848251abf60409384564a48ba07895ffcc7c55051ccad6ef1c8/lib/libHSindexed-traversable-0.1.3-5c151c51a16fe848251abf60409384564a48ba07895ffcc7c55051ccad6ef1c8-ghc9.6.3.so (0x00007fbcac5aa000)
        libHSdistributive-0.6.2.1-424d6f2381d9c9b4606d8ef373e84068158bda1024a3a03ef04f8b94e363236b-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/distributive-0.6.2.1-424d6f2381d9c9b4606d8ef373e84068158bda1024a3a03ef04f8b94e363236b/lib/libHSdistributive-0.6.2.1-424d6f2381d9c9b4606d8ef373e84068158bda1024a3a03ef04f8b94e363236b-ghc9.6.3.so (0x00007fbcac589000)
        libHSbase-orphans-0.9.1-264c535ac11fa2bb1dc61e9601fa533869cc15baf045a8637949e684cef27141-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/base-orphans-0.9.1-264c535ac11fa2bb1dc61e9601fa533869cc15baf045a8637949e684cef27141/lib/libHSbase-orphans-0.9.1-264c535ac11fa2bb1dc61e9601fa533869cc15baf045a8637949e684cef27141-ghc9.6.3.so (0x00007fbcacf0d000)
        libHSassoc-1.1-833fe934934ac287ee0125e0f70630bbf79db58c094cac008fb300c306b45c2c-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/assoc-1.1-833fe934934ac287ee0125e0f70630bbf79db58c094cac008fb300c306b45c2c/lib/libHSassoc-1.1-833fe934934ac287ee0125e0f70630bbf79db58c094cac008fb300c306b45c2c-ghc9.6.3.so (0x00007fbcac580000)
        libHStagged-0.8.8-245207977ddabd2449b4b7811802701130827478b7f71185ea9f91ae936b7797-ghc9.6.3.so => /home/wrath/.cabal/store/ghc-9.6.3/tagged-0.8.8-245207977ddabd2449b4b7811802701130827478b7f71185ea9f91ae936b7797/lib/libHStagged-0.8.8-245207977ddabd2449b4b7811802701130827478b7f71185ea9f91ae936b7797-ghc9.6.3.so (0x00007fbcac54f000)
        libHStransformers-0.6.1.0-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHStransformers-0.6.1.0-ghc9.6.3.so (0x00007fbcac432000)
        libHScontainers-0.6.7-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHScontainers-0.6.7-ghc9.6.3.so (0x00007fbcac000000)
        libHStemplate-haskell-2.20.0.0-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHStemplate-haskell-2.20.0.0-ghc9.6.3.so (0x00007fbcabc00000)
        libHSpretty-1.1.3.6-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHSpretty-1.1.3.6-ghc9.6.3.so (0x00007fbcac3bf000)
        libHSghc-boot-th-9.6.3-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHSghc-boot-th-9.6.3-ghc9.6.3.so (0x00007fbcabfbf000)
        libHSdeepseq-1.4.8.1-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHSdeepseq-1.4.8.1-ghc9.6.3.so (0x00007fbcac3a0000)
        libHSarray-0.5.5.0-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHSarray-0.5.5.0-ghc9.6.3.so (0x00007fbcabb7e000)
        libHSbase-4.18.1.0-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHSbase-4.18.1.0-ghc9.6.3.so (0x00007fbcaae00000)
        libHSghc-bignum-1.3-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHSghc-bignum-1.3-ghc9.6.3.so (0x00007fbcabb2a000)
        libHSghc-prim-0.10.0-ghc9.6.3.so => /home/wrath/.ghcup/ghc/9.6.3/lib/ghc-9.6.3/lib/x86_64-linux-ghc-9.6.3/libHSghc-prim-0.10.0-ghc9.6.3.so (0x00007fbcaa800000)
        libgmp.so.10 => /usr/lib/libgmp.so.10 (0x00007fbcaba84000)
        libc.so.6 => /usr/lib/libc.so.6 (0x00007fbcaa61e000)
        /usr/lib64/ld-linux-x86-64.so.2 (0x00007fbcae785000)

As you can see, the only thing bundled is the original library and it still depends on 57 others..

I'm on Ar** Linux and using packages exodus-bundler 2.0.4-2 and musl 1.2.4-1 (if the latter even makes any difference in this scenario..).

"AttributeError: 'file' object has no attribute 'buffer"

I run into the following issue while trying to use exodus.
Any tips?

Btw. very cool idea, many thanks, keep up the good work.

Command output:

me@server's password: 
Traceback (most recent call last):
  File "/home/kuba/.local/bin/exodus", line 11, in <module>
    sys.exit(main())
  File "/home/kuba/.local/lib/python2.7/site-packages/exodus_bundler/cli.py", line 113, in main
    create_bundle(**args)
  File "/home/kuba/.local/lib/python2.7/site-packages/exodus_bundler/bundling.py", line 47, in create_bundle
    output_file = sys.stdout.buffer
AttributeError: 'file' object has no attribute 'buffer'
  • System: Xubuntu 17.10
  • Python 2.7
  • Exodus v1.1.3
  • "echo $LD_LIBRARY_PATH" is empty
  • xfce4-terminal

Include all observed dependency paths in `LD_LIBRARY_PATH`

In Exodus 1.0, all of an executable's dependencies were placed in a single directory which was trivial to set as a library path. Now that the original filesystem is mirrored, it's a lot more complicated to properly set the library paths. We're planning on parsing ld.conf to add additional directories, but I think it also makes sense to ensure that any dependencies are included in the library path as well. This should mostly take care of the ld.conf issues, but will also handle other edge cases as well.

Connects #43

FileNotFoundError('"%s" is not a file.')

On Ubuntu 16.04, following the example in readme:

> exodus htop

Traceback (most recent call last):
  File "/.../.local/bin/exodus-bundler", line 11, in <module>
    sys.exit(main())
  File "/.../.local/lib/python3.5/site-packages/exodus_bundler/cli.py", line 113, in main
    create_bundle(**args)
  File "/.../.local/lib/python3.5/site-packages/exodus_bundler/bundling.py", line 32, in create_bundle
    root_directory = create_unpackaged_bundle(executables, rename=rename, ldd=ldd)
  File "/.../.local/lib/python3.5/site-packages/exodus_bundler/bundling.py", line 109, in create_unpackaged_bundle
    dependencies = find_all_library_dependencies(ldd, executable)
  File "/.../.local/lib/python3.5/site-packages/exodus_bundler/bundling.py", line 170, in find_all_library_dependencies
    new_dependencies |= set(find_direct_library_dependencies(ldd, dependency))
  File "/.../.local/lib/python3.5/site-packages/exodus_bundler/bundling.py", line 177, in find_direct_library_dependencies
    matches = filter(None, (re.search('=>\s*([^(]*?)\s*\(', line) for line in run_ldd(ldd, binary)))
  File "/.../.local/lib/python3.5/site-packages/exodus_bundler/bundling.py", line 194, in run_ldd
    raise FileNotFoundError('"%s" is not a file.')
FileNotFoundError: "%s" is not a file.

Typo in README

The linus-vdso.so.1 dependency refers

Should be

The linux-vdso.so.1 dependency refers

Error when bundling a Godot binary

Operating system, Python and Exodus version: Fedora 27, Python 3.6.4, Exodus 1.1.6

Attempting to bundle a self-compiled Godot binary results in this error:

❯ exodus godot.x11.opt.tools.64 -v
Traceback (most recent call last):
  File "/home/hugo/.local/bin/exodus", line 11, in <module>
    sys.exit(main())
  File "/home/hugo/.local/lib/python3.6/site-packages/exodus_bundler/cli.py", line 118, in main
    create_bundle(**args)
  File "/home/hugo/.local/lib/python3.6/site-packages/exodus_bundler/bundling.py", line 34, in create_bundle
    root_directory = create_unpackaged_bundle(executables, rename=rename, ldd=ldd)
  File "/home/hugo/.local/lib/python3.6/site-packages/exodus_bundler/bundling.py", line 124, in create_unpackaged_bundle
    'The same library filename has been included more than once in a bundle.'
AssertionError: The same library filename has been included more than once in a bundle.

Here's a ZIP archive containing the binary; it is compiled on Fedora 27 with GCC 7.2.1 with LTO enabled. (I've run into the same issue when bundling the Godot binary compiled using Clang with LTO disabled.)

On the same system, I am able to create bundles of other applications such as micro or ezQuake.

Including additional components from a package

Operating system, Python and Exodus version: Ubuntu 17.04, Python 3.5.3, Exodus 1.1.8
Target OS: CentOS 7.4

Some packages like nmap, for example, include additional components inside the /usr/share/[package] folder. Those components (static files, scripts etc) are bundled with the .deb/.rpm, but they're not listed by ldd. One easy way to list those dependencies is using rpm -ql nmap (RedHat/CentOS/Fedora) or dpkg-query -L nmap (Debian/Ubuntu):

$ dpkg-query -L nmap
/.
/usr
/usr/bin
/usr/bin/ncat
/usr/bin/nmap
(...)
/usr/share/nmap
/usr/share/nmap/nmap-mac-prefixes
/usr/share/nmap/nmap-os-db
/usr/share/nmap/nmap-payloads
(...)

Here's what you have to do manually now:

bernardomr@ubuntu:~$ exodus nmap | ssh [email protected]
Pseudo-terminal will not be allocated because stdin is not a terminal.
[email protected]'s password: 
Installing executable bundle in "/home/bernardomr/.exodus"...
Successfully installed, be sure to add /home/bernardomr/.exodus/bin to your $PATH.

Trying to run nmap with scripts:

[bernardomr@centos ~]$ nmap -sV localhost

Starting Nmap 7.40 ( https://nmap.org ) at 2018-02-06 05:12 EST
Unable to find nmap-services!  Resorting to /etc/services
NSE: failed to initialize the script engine:
could not locate nse_main.lua
stack traceback:
	[C]: in ?

QUITTING!

strace output:

[bernardomr@centos ~]$ cat strace.log | grep \.nse
read(4, "erver\nserverview-as   3169/tcp  "..., 4096) = 4096
stat("/home/bernardomr/.nmap/updates/7.30/nse_main.lua", 0x7fffffff9cd0) = -1 ENOENT (No such file or directory)
stat("/home/bernardomr/.exodus/lib/updates/7.30/nse_main.lua", 0x7fffffff9cd0) = -1 ENOENT (No such file or directory)
stat("/home/bernardomr/.exodus/lib/../share/nmap/updates/7.30/nse_main.lua", 0x7fffffff9cd0) = -1 ENOENT (No such file or directory)
stat("/usr/share/nmap/updates/7.30/nse_main.lua", 0x7fffffff9cd0) = -1 ENOENT (No such file or directory)
stat("/home/bernardomr/.nmap/nse_main.lua", 0x7fffffff9cd0) = -1 ENOENT (No such file or directory)
stat("/home/bernardomr/.exodus/lib/nse_main.lua", 0x7fffffff9cd0) = -1 ENOENT (No such file or directory)
stat("/home/bernardomr/.exodus/lib/../share/nmap/nse_main.lua", 0x7fffffff9cd0) = -1 ENOENT (No such file or directory)
stat("/usr/share/nmap/nse_main.lua", 0x7fffffff9cd0) = -1 ENOENT (No such file or directory)
could not locate nse_main.lua

We need to manually copy the /usr/share/nmap folder to ~/.exodus/share/nmap]:

bernardomr@ubuntu:~$ cd /usr/share/ ; tar cpf - nmap | ssh [email protected] "mkdir ~/.exodus/share ; tar xpf - -C ~/.exodus/share"

And now we can properly run the nmap scan with scripts:

[bernardomr@centos ~]$ nmap -sV localhost

Starting Nmap 7.40 ( https://nmap.org ) at 2018-02-06 05:23 EST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00013s latency).
Other addresses for localhost (not scanned): ::1
Not shown: 998 closed ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.4 (protocol 2.0)
25/tcp open  smtp    Postfix smtpd
Service Info: Host:  localhost.localdomain

I wonder if it would be useful to add a command line switch to bundle additional folders with those components automatically. I'm not sure if there's any better way to list the dependencies other than using rpm and dpkg (maybe disassembling the binary?), but it would be interesting to run exodus like this:

$ exodus --tarball nmap --additional-files /usr/share/nmap --output nmap.tgz

Typo in the readme

The "Non-ELF Binaries" bullet point under "Known Limitations" in README.md uses "they're" when it should have used "their". You may want to fix this the next time you're making changes in this project.

Drop toolchain path

I'm evaluating using exodus as an installation method for ArduPilot in the boards that run Linux.

After cross-compiling the plane binary I have this output:

$ readelf -d build/disco/bin/arduplane  | grep NEEDED
 0x00000001 (NEEDED)                     Shared library: [libdl.so.2]
 0x00000001 (NEEDED)                     Shared library: [libiio.so.0]
 0x00000001 (NEEDED)                     Shared library: [libstdc++.so.6]
 0x00000001 (NEEDED)                     Shared library: [libm.so.6]
 0x00000001 (NEEDED)                     Shared library: [libgcc_s.so.1]
 0x00000001 (NEEDED)                     Shared library: [libpthread.so.0]
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]

I'm using a buildroot rootfs + toolchain to cross-compile. By passing the -c option to exodus, it picks ld correctly and works. However the resulting tarball contains the local paths used in the machine creating it, both the tarball's full path and the binary's full path. So I have something like this:

tar -tf exodus-arduplane-bundle.tgz
exodus/bundles/9d9d2e5fe02b776c0e5f278239b087099adf73b729f31d681e979c4f573cd18c/home/ldmartin/p/buildroot/output/target/lib/ld-linux-armhf.so.3
exodus/bundles/9d9d2e5fe02b776c0e5f278239b087099adf73b729f31d681e979c4f573cd18c/home/ldmartin/p/buildroot/output/target/lib/libc.so.6
...
exodus/bundles/9d9d2e5fe02b776c0e5f278239b087099adf73b729f31d681e979c4f573cd18c/home/ldmartin/p/drone/ardupilot/build/disco/bin/arduplane

The option passed to -c was /home/ldmartin/p/buildroot/output/target/. Would it be possible for exodus not to use the full path and make it operate a) relative to the binary and b) to the rootfs? In other words, I was expecting the following output and wonder if it would be feasible:

exodus/bundles/9d9d2e5fe02b776c0e5f278239b087099adf73b729f31d681e979c4f573cd18c/lib/ld-linux-armhf.so.3
exodus/bundles/9d9d2e5fe02b776c0e5f278239b087099adf73b729f31d681e979c4f573cd18c/lib/libc.so.6
...
exodus/bundles/9d9d2e5fe02b776c0e5f278239b087099adf73b729f31d681e979c4f573cd18c/bin/arduplane

A workaround is by binding mounting to, say, /mnt:

$ sudo mount --bind /home/ldmartin/p/buildroot/output/target/ /mnt
$ sudo touch /mnt/bin/arduplane
$ sudo mount --bind /home/ldmartin/p/drone/ardupilot/build/disco/bin/arduplane /mnt/bin/arduplane

then there's only /mnt extra in the path, but I guess it would be nice if this could be supported.

Interchange use of AppName-x and AppName in the launcher

I am not reporting an issue. This is a request for a change.

I am using exodus on a Linux distribution.

Assuming the name of the application ins AppName, the exodus launcher creates a symlink to a shell script with the same name inside the bundle directory. The actual binary is renamed to AppName-x and the AppName script launchies AppName-x.

When the application use the name of the binary for internal use, this creates a problem for applications that load their setup from a file name derived from AppName. Existing setup files (e.g. name "AppName.def") need to also be renamed now to AppName-x.def when the application is launched from exodus launcher.

It will be helpful if the exodus code can be modified to flip the use of AppName-x and AppName script. I.e., AppName-x becomes the launcher script and keep the name of the actual binary as AppName. The top-level symlink then points to AppName-x in the bundle directory which will launch AppName and the above problem disappears.

I have tested this scheme on a simple bundle (with the launcher script being a bash script in Linux) by making these modifications by-hand. I have played around with modifying the code in bundling.py to achieve this, but without full success. I am also not sure if I understand the code well enough to ensure that my changes would cover all use cases. I would therefore appreciate that, if this makes sense and does not break anything, someone more knowledgeable make the necessary modifications. Alternatively, if someone can tell what to do I'll make any attempt myself. Thanks.

Specify that musl-gcc is needed in documentation

On Ubuntu 18.04, installing just the musl library - package musl or musl-dev is not enough, even though I had gcc installed and working.

You need to install musl-tools since exodus looks specifically for musl-gcc which is part of musl-tools.

It might be useful to modify the README to specify that musl-gcc is required. The way the current text reads, it appears as if just having the musl library is enough.

Using exodus 2.0.4

Thanks for your wonderful work!

Manually added library dependencies should default to the entry point's linker

Library dependencies for an entry point that are found using the linker already inherit the entry point's linker. If a library is added manually, using either --add or --detect, then it's secondary dependencies are only included if it has a linker set in its program header. These manually added libraries should also inherit the entry point's linker if they don't have one specified in their program header.

Dynamic discovery of dlopen'ed libraries?

Hi,

Thanks for making this tool.

Do you plan to add a feature to trace a running binary on the host system and create a list of dynamically loaded libraries? It could create automatically the necessary --add based on an execution.

CDE (github, manual) does that, or rather did that because it's not been updated for a while.

Cheers,
Pierre

execv on /proc/self/exe

When CEF3 (Chrome starts the GPU process, and possibly others), it does execv on /proc/self/exe, per below:

[pid 7712] execve("/proc/self/exe", ["/proc/self/exe", "--type=gpu-process", "-
-no-sandbox", "--log-file=/opt/exodus/bundles/1"..., "--log-severity=disable", "
--lang=en-US", "--gpu-preferences=KAAAAAAAAACAAA"..., "--log-file=/opt/exodus/bu
ndles/1"..., "--log-severity=disable", "--lang=en-US", "--service-request-channe
l-token="...], 0x7ffec1cf9ab0 /* 61 vars */) = 0

This does not work! At this time, /proc/self/exe refers to the original executable, and not the starter executable.

I am going to try: in the executable, iff the process name av[0] is /proc/self/exe, rerun with a modified loader, which, in turn will execv the executable with the correct environment. This is not a general solution -- that would probably require a preload of execv within the program starter.

I think that this is responsible for the problems I am having (trying to run a CEF3 based application on RHEL6).

Thanks in advance.
Fred Weigel

--inhibit-rpath "" passed to executable.

Please include the following information if you're reporting an issue.

  • Which operating system you're using. Centos 8. amd64.
  • Which Python version. Python 3.6
  • Which exodus package version. exodus-bundler 2.0.4
  • The command that you're running (please include the --verbose flag so that the stack trace is included).
  • The full output of the command.
centos8$ exodus \
  --verbose \
  --add /lib64/libnss_files.so.2 \
  --add /lib64/libnss_dns.so.2 \
  --add /lib64/libnss_myhostname.so.2 \
  --add /lib64/libresolv.so.2 \
  foo.bar.aksjdkadj.2210311345 > foo.bar.aksjdkadj.2210311345.installer
WARNING: Installing either the musl or diet C libraries will result in more efficient launchers (currently using bash fallbacks instead).
centos8$ 

So the issue appears to be the startup wrapper script.

centos9$ cat ./.exodus/bin/foo.bar.aksjdkadj.2210311345
#! /bin/bash

current_directory="$(dirname "$(readlink -f "$0")")"
executable="${current_directory}/./foo.bar.aksjdkadj.2210311345-x"
library_path="../../lib64:../../usr/lib64:../../lib:../../usr/lib:../../lib32:../../usr/lib32"
library_path="${current_directory}/${library_path//:/:${current_directory}/}"
linker="${current_directory}/./linker-68e1553cd79d844f7efe46e38dadc34b8af4af011c78c701f4b377ccf8f6df9a"
if [ "true" == "true" ]; then
    exec "${linker}" --library-path "${library_path}" --inhibit-rpath "" "${executable}" "$@"
else
    exec "${linker}" --library-path "${library_path}" "${executable}" "$@"
fi
centos9$

The bundled linker looks to support this flag:

centos9$ ./.exodus/bundles/210dfd9330e9bed177209f5e9545314ce45943c20426fc5f859f2ddc4c059d4b/home/witek/linker-68e1553cd79d844f7efe46e38dadc34b8af4af011c78c701f4b377ccf8f6df9a --help | grep inhibit-rpath
  --inhibit-rpath LIST  ignore RUNPATH and RPATH information in object names
centos9$ ./.exodus/bundles/210dfd9330e9bed177209f5e9545314ce45943c20426fc5f859f2ddc4c059d4b/home/witek/linker-68e1553cd79d844f7efe46e38dadc34b8af4af011c78c701f4b377ccf8f6df9a --version
ld.so (GNU libc) stable release version 2.28.
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
centos9$

But when I try to run the wrapper script with extra commands to pass to the target executable, it does not work properly:

foo@centos9$ /home/foo/.exodus/bin/foo.bar.aksjdkadj.2210311345 ./cfg/foo1.json
20221031-18:30:25 [ERROR] WARNING: expected "--inhibit-rpath" to be config filename (file.cc:270)
20221031-18:30:25 [ERROR] Uncaught exception from thread 140441755105152: expected "--inhibit-rpath" to be config filename (log/log.cc:510)
(stack trace from my C++ app)
foo@centos9$ 

Python's venv library bypasses the exodus wrapper

Python's venv creation code bypasses the exodus wrapper, which results in the real Python binary being called directly.

Here's the relevant code: https://github.com/python/cpython/blob/master/Lib/venv/__init__.py#L117

Has anyone found a solution for using exodus with applications that follow this pattern? I haven't been able to come up with a workable solution. Even hacking this particular file still doesn't solve the issue, as pip itself seems to do something similar when launching subprocesses.

Error message isn't correctly formatted

Operating system, Python and Exodus version: Fedora 27, Python 3.6.4, Exodus 1.1.6

The error message about a binary not being in $PATH isn't actually formatted, so the %s is always visible.

Non-verbose output:

❯ exodus non-existing_binary
ERROR: Fatal error encountered, exiting.
ERROR: The "%s" binary could not be found in $PATH.

Verbose output:

❯ exodus non-existing_binary -v
ERROR: Fatal error encountered, exiting.
ERROR: The "%s" binary could not be found in $PATH.
Traceback (most recent call last):
  File "/home/hugo/.local/lib/python3.6/site-packages/exodus_bundler/cli.py", line 118, in main
    create_bundle(**args)
  File "/home/hugo/.local/lib/python3.6/site-packages/exodus_bundler/bundling.py", line 34, in create_bundle
    root_directory = create_unpackaged_bundle(executables, rename=rename, ldd=ldd)
  File "/home/hugo/.local/lib/python3.6/site-packages/exodus_bundler/bundling.py", line 100, in create_unpackaged_bundle
    for name, executable in zip(rename, map(resolve_binary, executables)):
  File "/home/hugo/.local/lib/python3.6/site-packages/exodus_bundler/bundling.py", line 217, in resolve_binary
    raise MissingFileError('The "%s" binary could not be found in $PATH.')
exodus_bundler.errors.MissingFileError: The "%s" binary could not be found in $PATH.

Add suse (zypper) package manager

Please include the following information if you're reporting an issue.

  • Which operating system you're using.: openSUSE Tumbleweed
  • Which Python version. 3.9.9
  • Which exodus package version. : 2.0.4
  • The command that you're running (please include the --verbose flag so that the stack trace is included).
  • The full output of the command.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.