Skip to content
/ pelf Public

Pack an ELF. Turn your binaries into single-file executables [.AppBundle|.blob], similar to AppImages and compatible with AppDirs. LIBC-independent, works on *BSDs.

License

Notifications You must be signed in to change notification settings

xplshn/pelf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

85 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PELF

License GitHub code size in bytes

PELF (Pack an ELF) is a toolset designed to simplify the process of turning your binaries into single-file executables, similar to AppImages. The format used by PELF is called .AppBundle or .blob. The files are portable across systems of the same architecture and ABI. Architecture-independent bundles can be achieved using Wrappers, and Libc-independent ones can be achieved by using --add-ld-and-libc (it is recommended that you generate the bundles on Musl-based systems, so that they are lighter and will work on other systems)

If you only intend on using .AppBundles, not necesarily work with them, you don't need any of this. You can get started by simply executing the bundle. The helper daemon is optional.

NOTE: Your tar command must support GZIP archives. (which covers most tar implementations, including the BSDs and Busybox's)

2024-07-01-023335_1280x720_scrot

Example AppBundles/Binaries for you to try (amd64):

  • POSIX = Runs on any Unix clone that has some degree of POSIX compatibility/compliance
  • MUSL = Runs on Musl-based Linux distros
  • GLIBC = Runs on Glibc-based Linux distros
  • Linux = Runs on any Linux distro

These are .small.AppBundle, so these are (VERY) compressed and do require gunzip to be available, most systems have it.

If you don't know what this means, you should select Linux or alternatively, Glibc.

Tools Included

pelf pin

pelf is the main tool used to create an .AppBundle of your binaries. It takes your executable files and packages them into a single file for easy distribution and execution.

Usage:

Usage: ./pelf [--main-bin [BINARY]|--add-appdir [AppDir] [EXE_NAME]] [--output-to OUTPUT.AppBundle] <--add-library [LIB_PATH]|--add-binary [BIN_PATH]|--add-metadata [icon128x128.xpm|icon128x128.png|icon.svg|app.desktop]|--add-arbitrary [DIR|FILE]>

pelf_linker

pelf_linker is a utility that facilitates access to binaries inside an .AppBundle for other programs. It ensures that binaries and dependencies within the (open, overlayed) bundles are accesible to external programs. This relies on the concept of Bundle Overlays.

Usage:

pelf_linker [--export] [binary]

pelf_extract

pelf_extract allows you to extract the contents of a PELF bundle to a specified folder. This can be useful for inspecting the contents of a bundle or for modifying its contents.

Usage:

./pelf_extract [input_file] [output_directory]

pelfd pin

pelfd is a daemon written in Go that automates the "installation" of .AppBundle files. It automatically puts the metadata of your .AppBundles in the appropriate directories, such as .local/share/applications and .local/share/icons. So that the .AppBundles you put in ~/Programs (for example) will appear in your menus.

Usage:

pelfd &

Overlaying Bundles pin

One of the key features of PELF is its ability to overlay bundles on top of each other. This means that programs inside one bundle can access binaries and libraries from other bundles. For example, if you bundle wezterm as a single file and add wezterm-mux-server to the same bundle using --add-binary, programs run by wezterm will be able to see all of the binaries and libraries inside the wezterm bundle.

This feature is particularly powerful because you can stack an infinite number of PELF bundles. For instance:

  • spectrwm.AppBundle contains dmenu, xclock, and various X utilities like scrot and rofi.
  • wezterm.AppBundle contains some Lua programs and utilities.
  • mpv.AppBundle contains ani-cli, ani-skip, yt-dlp, fzf, and curl.

Using the pelf_linker, the mpv.AppBundle can access binaries inside spectrwm.AppBundle as well as its own binaries. By doing mpv.AppBundle --pbundle_link ani-cli, you can launch an instance of the ani-cli included in the bundle, as well as ensure that it can access other utilities in the linked/stacked bundles.

SpectrWM window manager AppBundle/.blob that contains all of my X utils including Wezterm As you can see, I have my window manager and all of my X utilities, including my terminal (Wezterm) as a single file, named SpectrWM.AppBundle. You can also see the concept of overlays in action, the ani-cli binary inside of the mpv.AppBundle, will have access to the ROFI binary packed in my SpectrWM.AppBundle, because it will be running as a child of that process. There is PATH and LD_LIBRARY_PATH inheritance.

Installation pin

To install the PELF toolkit, follow these steps:

  1. Clone the repository:
    git clone https://github.com/xplshn/pelf.git ~/Programs
    cd ~/Programs
    rm LICENSE README.md
    cd cmd && go build && mv ./pelfd && cd - # Build the helper daemon
    rm -rf ./cmd ./examples
  2. Add ~/Programs to your $PATH in your .profile or .shrc (.kshrc|.ashrc|.bashrc)

Usage Examples pin

Creating an .AppBundle

To create an .AppBundle from your binaries, use the pelf tool:

./pelf --main-bin /usr/bin/wezterm --output-to ./wezterm.AppBundle --add-binary /usr/bin/wezterm-mux-server --add-metadata /usr/share/applications/wezterm.desktop --add-metadata ./wezterm128x128.png --add-metadata ./wezterm128x128.svg --add-metadata ./wezterm128x128.xpm
Partial AppDir support
  • You can use AppDirs that have an AppRun, but in order to integrate them (add metadata), you will have to use the --add-metadata option, also, there are various libraries which your AppRun can rely on from within an AppBundle, make sure you use them.
./pelf --add-appdir ./wezterm_AppDir wezterm --output-to ./wezterm.AppBundle --add-metadata ./wezterm_AppDir/usr/share/applications/wezterm.desktop --add-metadata ./wezterm_AppDir/.DirIcon

Using binaries inside of an .AppBundle from outside it, or from other programs

To leverage access to the binaries inside of your (open & overlayed) PELFs to other programs, you can use the pelf_linker tool:

pelf_linker ytfzf

Overlayed access: Here we made ytfzf be able to access all the PATHs set in $PELF_BINDIRS

mpv.AppBundle --pbundle_link ytfzf

Scoped access: In this other example, we made ytfzf gain access to the programs inside of the example mpv.AppBundle.

Extracting an .AppBundle

To extract the contents of an .AppBundle to a folder, use the pelf_extract tool:

./pelf_extract openArena.AppBundle ./openArena_bundleDir

Running the pelfd Daemon

To start the pelfd daemon and have it automatically manage your .AppBundle files:

pelfd &

On the first-run, it will create a config file which you can modify: ~/.config/pelfd.json, this is how your config would look after the first run:

{
  "options": {
    "directories_to_walk": [
      "~/Programs"
    ],
    "probe_interval": 90,
    "icon_dir": "/home/anto/.local/share/icons",
    "app_dir": "/home/anto/.local/share/applications",
    "probe_extensions": [
      ".AppBundle",
      ".blob"
    ]
  },
  "tracker": {}
}
  • "directories_to_walk": This is an array of directories that the pelfd daemon will monitor for .AppBundle or .blob files. By default, it is set to ["~/Programs"], meaning the daemon will only check for AppBundles in the ~/Programs directory. You can add more directories to this array if you want the daemon to watch multiple locations.
  • "probe_interval": This specifies the interval in seconds at which the pelfd daemon will check the specified directories for new or modified AppBundles. By default, it is set to 90 seconds.
  • "icon_dir": This is the directory where icons extracted from .AppBundles will be copied to pelfd. By default, it is set to "~/.local/share/icons", which is a common location for application icons on modern Unix clones.
  • "app_dir": This is the directory where the desktop files extracted from .AppBundles will be copied to by pelfd. By default, it is set to "~/.local/share/applications". .desktop files provide information about the application, such as its name, icon, and command to execute. By default, it is set to "~/.local/share/applications", which is the standard location for application shortcuts on modern Unix clones.
  • "probe_extensions": This is an array of file extensions that pelfd will look for when probing the specified directories. By default, it is set to [".AppBundle", ".blob"], meaning the daemon will only consider files with these extensions as AppBundles. (CASE-SENSITIVE)
  • The "tracker" object in the config file is used to store information about the tracked AppBundles, this way, when an AppBundle is removed, its files can be safely "uninstalled", etc.
  • "correct_desktop_files": This option makes PELFD automatically correct the .desktop files provided by the bundles. So that they can be found by your menu application.

Editions!

.AppBundles may come archived with different formats or encodings. For example, the included pelf_small edition, will create bundles without using base64 and using GZIP directly with -9, for the best available compression, it may even end up being faster, due to avoiding base64. Remember to ALWAYS signal which edition a bundle was made with by adding it to the bundle's name! For example, .raw.AppBundle if your PELF tool was patched/modified to remove base64 encoding, .small.AppBundle if you used the pelf_small example included here.

Current roadmap:

  1. Optionally provide the option to mount the TAR archive instead of instead of copying the files. Or replace TAR altogether for a format that is also widely available.
  2. Employ the same tricks that the APE loader uses to be recognized as an ELF, preferably, implement a tool that can be used to turn any SH script into a (fake) "ELF".
  3. Simplify everything by splitting the loader into a very barebones loader and some helper binaries written in shell, for example, the embedded thumbnail generator could be one such helper. The idea being that even if the user isn't able to run the .AppBundle, he can always extract it and repackage it again without having to start from scratch.

Current setbacks:

  • Code has to be readable to stay hackable, given that this is SH, it may end up being an unbearable, disgusting mess, so I have to be specially careful.
  • My time to work on PELF is limited
Read these two if you are interested in how APE works:
  1. https://justine.lol/ape.html
  2. https://github.com/jart/cosmopolitan/blob/master/ape/loader.c
  3. https://github.com/jart/cosmopolitan/blob/master/ape/ape.S

Contributing

Contributions to PELF are welcome! If you find a bug or have a feature request, please open an Issue. For direct contributions, fork the repository and submit a pull request with your changes.

License

PELF and its associated tools are licensed under the 3BSD License. See the LICENSE file for more details.

Special thanks to: