I often use exodus to move software onto a Synology NAS (after hosing my installation in the past through haphazard use of alternative package managers) and it has been incredibly helpful. It's great to be able to bring over utilities without fighting with docker, building appimages, or the like.
Thank you so much for it!
It just works most of the time, which is wild given how diverse the environments it operates in can be. One piece of software I have struggled with however is w3m.
I'm pretty sure __data_start/__data_end is the symbol for the first/last initialized data in an ELF binary, so possibly a conflicting glibc or a conflicting or missing library
This probably won't work on binaries that contain references to system files necessary in order to run the binary that aren't code. You usually can't detect them other than running the program and watching it die, or running the program with strace and looking for the files it's trying to stat/open.
In the past what I've done when I have to copy a binary somewhere, is statically compile it in a Docker container and export the install files, then copy those over. I have about a half dozen tools prepped like that (gdb, curl, strace, busybox, etc)
You usually can't detect them other than running the program and watching it die, or running the program with strace and looking for the files it's trying to stat/open.
You can actually pipe the output of strace into exodus and it will include the files that were accessed by the program in the bundle. For example:
You could also use a package manager utility to list which files are needed, assuming the target binary was installed that way. (pkgs.org lists the files every package installs, or locally you could run something like `apt-files`).
That will detect files in a system package, but not files in a system package depended on by a system package depended on by a system package. It depends on how the distro packages deps and how apps use them. There are apps which use non-linked files that are only provided in extra packages. And even if you walk the whole dependency graph for a single package and export all listed files, you miss files that are created and updated during the setup steps of a package install (which are not listed in the package).
Just trying to put out there to expect undefined behavior or failures. Users might not understand how applications work and so might expect more than is possible. The strace trick is a nice workaround but I didn't see it in the readme
Could this be used to relocate Android-native libraries to other platforms? Even if the architecture matches, the bionic libc calls is what I found more challenging.
The tool moves runs the application and all of its dependencies in a container for compatibility, but on Android with bionic that would probably imply moving all of libc with the app. I don't think that'll go down as easily, as the entire bionic framework is integrated quite deeply with the rest of the system.
For "simple" bionic libc calls, an LD_PRELOAD shim might be enough for many binaries, though. You'd need to translate all the bionic libc calls to your system's libc calls, but that might just be easier than it seems because the level of compatibility between the two. Bionic is actually a subset of POSIX libc, so you should be able to map all calls to your normal system calls.
I think not. The landscape of software packaging is too unpleasant and chaotic, the goals of its participants--users vs package collection (distro) maintainers vs. software authors--too misaligned.
Instead, what I think (hope) will happen is a simultaneous increase in prevalence of two things: "effectively static" software releases (whether that's an actual static binary or a container/flatpak/exodus-bundled folder/whatever), and sandboxing/isolation tools at the OS level, to prevent the statically linked dependencies in installed programs from causing harm to the system.
There will probably always be exceptions made for software that by necessity must be integrated tightly with the whole computer (window managers etc.), but I don't think people are going to rediscover dynamic linking en masse.
After this, we will get back to shared libraries, because updating that libpng would require updating all those static binaries. This is already happening with many go and rust programs.
And eventually maybe it'll all converge back to the rational way to do things: a base set of shared libraries provided by the OS that maintain strict ABI compatibility, and everything else static.
I think the end goal is what we all want - be able to do any of the options - single binary to external libraries and anything in between easily. Not with the one way going in fashion and the other out but both supported and accessible.
The cool thing would be multi-host static binaries i.e. binaries that host multiple "apps" and its dependencies and use commandline option to launch specific "app" from the binary(or without commandline option, provide a app list from which the user can select that app to run)
There is also something similar that can make binaries that run even bare metal or as EFI apps. But I can't find at the moment. (Maybe someone else has the link?)
$ ./foo
Installing executable bundle in "${HOME}/.exodus"...
Successfully installed, be sure to add ${HOME}/.exodus/bin to your $PATH.
$ ~/.exodus/bin/git --version
fatal: cannot handle x as a builtin
The docs explain that internally ~/.exodus/bin/git is actually a shell wrapper that calls ~/.exodus/bin/git-x (which itself might be a symlink). The -x suffix is added by exodus.
My guess is that git is parsing argv[0] to try and determine which porcelain command to launch and gets very confused by the -x because it is not a git builtin command.
I get literally the same error with --detect. And honestly when the README says "transferring a piece of software that's working on one computer to another is as simple as this" you can't blame me for taking that at face value.
I'm the author and I agree that you're correct in assuming that what you ran should work. I just tested this with git on arch and I was able to reproduce the issue. I'll look into why this is happening and hopefully push up a fix soon, but I also invite you to try it out with another binary in the meantime. There seems to be something particular about git, and I think you'll have better luck trying it with almost any other ELF binary.
Oh hi, thanks for replying! So funny enough, git was literally the first thing I tried, because it was easily the first thing I could think of where being able to move later versions of it to earlier versions of Linux would've made my life easier. I'm not sure if anything else really falls in this category for me. But on your suggestion, I just tried Python 3.9, clang++, and g++, and didn't get errors for any of them. It's pretty nifty! Thanks for writing it.
`clang++-x` matches none of these. Then the same logic is applied to the name with any of "0123456789." trimmed from the right. Still no match. Then the trailing `-component` is stripped, and `clang++` matches.
> TIL: if you symlink ++ -> clang it works as a compiler in C++ mode.
Note that this is only about the compiler driver mode, i.e. the default libraries, search paths, include directories, etc. The source language is determined by the file extension unless specified with e.g. `-x c++`.
Fun anecdote about that: at work we added a wrapper around nvcc to point it at the right compiler, and renamed the original "nvcc" binary to ".nvcc-wrapped". But nvcc looks at argv[0] to print out its name in the --version output, and it truncates anything after a period (presumably to handle things like "nvcc.exe"?). And CMake's CUDA detection looks at nvcc --version. So CMake went down a really weird path where it knew that nvcc existed but didn't really believe it was nvcc, which was extremely confusing until I looked at some log output and went "wait, why isn't nvcc printing its own name".
See my comment in the parent thread but basically Git commands like ‘git thing’ actually dispatch to lower level commands, usually with the name git-thing (I’m not a git expert, just something I’ve noticed). And it seems that git builtins are dispatched into by calling the git binary with a different basename, and this conflicts with your convention of adding -x to binary names.
The tilde is usually parsed/replaced by the shell, so yes it you can use it for path definitions in the shell. The parsing is disabled by single quotes however. A lot of my colleagues were confused by that.
In this case it is not parsed by the shell. Double quotes disable parsing just as well as single quotes for ~. Try running the command in the video and then run "env".
Sometimes you can't run Docker (maybe you don't have root permissions to install and start the service). Someone else in the tread said that they're using in their Synology NAS, that don't have access to a package manager.
Docker also will have a much bigger overhead since you basically need to include a whole distro instead of just a few libraries. And I particularly find Docker applications to be sufficient slow to start that I never want to use CLI tools via Docker.
Thank you so much for it!
It just works most of the time, which is wild given how diverse the environments it operates in can be. One piece of software I have struggled with however is w3m.
I get the above error messages which I understand to be related to libc, but I cannot get around it. Is this something anyone has seen before?