How to make a portable Linux app?

5,498

Solution 1

I have a few ways to do this, easy ones first:

Making the install prefix flexible is hard - I would just make the install prefix to your home directory, or somewhere that you can access on any of the machines, and use

make install DESTDIR=/path/to/place/where/binaries/should/be/installed

to install them to somewhere other than the prefix.

I personally have my binaries in $HOME/bin, so my commands would look like this:

./configure --prefix=$HOME

Some programs (I know FFmpeg is one) can be build with all libraries compiled into the program, avoiding shared libraries. In ffmpeg's case (and possibly others) the configure flags are --disable-shared --enable-static.

You can use ldd (name-of-binary-file) to check which shared objects it needs, and copy those to your flash drive.

Edit 1

I have just made a way to get only the names of the libraries being linked to, which is very helpful.

ldd binary-name|sed 's/=>.*//'|sed 's/\t//'|sed 's/\ (0x.*//'

will get a list of all the libraries linked to.

Additionally, this will get you only the files that have hardcoded paths:

ldd binary-name|sed 's/=>.*//'|sed 's/\t//'|sed 's/\ (0x.*//'|grep --color=never /

This works because only libraries with hardcoded paths have slashes in their names usually. It gives you an idea what you should look for when doing the next possibility.

Edit 2

You can use LD_PRELOAD and/or LD_LIBRARY_PATH to load symbols from manually specified libraries, thus negating the 'hardcoded paths' problem mentioned below.

If your libraries have paths that are hardcoded in, I've heard of a tool called chrpath that can change the runpaths. I have had (limited) success in simply opening my binaries in a hex editor and changing the paths to the shared libraries as long as they are shorter than the ones that were originally compiled in. They must end with the string terminator character. (In C this is almost always 00). To make sure you will have enough space to change the path, I would (on the system I compile it on) set the prefix to something ridiculously long with symlinks, like this if your libraries are in /usr/lib:

sudo mkdir /OH_THIS_IS_A_VERY_VERY_VERY_VERY_VERY_LONG_DIRECTORY_NAME/
sudo ln -s /usr/lib /OH_THIS_IS_A_VERY_VERY_VERY_VERY_VERY_LONG_DIRECTORY_NAME/lib
mkdir destdir
./configure --prefix=/OH_THIS_IS_A_VERY_VERY_VERY_VERY_VERY_LONG_DIRECTORY_NAME
make
make install DESTDIR=$PWD/DESTDIR

($PWD is the current directory, by the way.)

That will give you plenty of room to change the paths. If you have space left over after the actual path, you can just keep adding 00 until you reach the end of the usual space. I have only had to resort to this with binaries I compiled for an Android phone, which had ncurses's path hardcoded into the binary.

One last thing I just found: you can make the location of ld-linux.so.* not hardcoded by adding this (adapt for your systems' locations, run something like locate ld-linux and find one similar to the below:

-Wl,--dynamic-linker=/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2

to your LDFLAGS variable.

Solution 2

I was able to make a portable version of Emacs 24 on CentOS 7. The same approach should work on Debian. The first thing I did was to install a virtual machine with a fresh copy of the OS, to ensure that I have root and can install any required libraries and tools.

My initial attempt to create a portable install involved installing the emacs package on a virtual machine and copying over the binary and libraries into custom folder, then setting LD_LIBRARY_PATH to the folder with the libraries. This was enough to get Emacs to start on the target system, but unfortunately, it seems Emacs uses hard-coded values for some of its configuration settings, and I was unable to find a work-around the following error about the missing charsets directory:

Warning: arch-dependent data dir (/usr/libexec/emacs/24.3/x86_64-redhat-linux-gnu/) does not exist.
Warning: arch-independent data dir (/usr/share/emacs/24.3/etc/) does not exist.
Warning: Lisp directory `/usr/share/emacs/24.3/lisp' does not exist.
Warning: Lisp directory `/usr/share/emacs/24.3/leim' does not exist.
Error: charsets directory not found:
/usr/share/emacs/24.3/etc/charsets
Emacs will not function correctly without the character map files.
Please check your installation!

I don't have access to create a link or folder in /usr/share on the target system, so this halted my progress.

My second attempt involved downloading the source code for Emacs (more than a gig!) into the VM and building my own copy with the ./configure --prefix=<DIR> command. I found instructions for getting and building Emacs at http://ergoemacs.org/emacs/building_emacs_from_git_repository.html, which uses Debian commands. My workflow was:

git clone https://github.com/mirrors/emacs.git
cd emacs
git pull
./autogen.sh
# Here, I tell make to install emacs to ~/bin/centos
./configure --prefix=~/bin/centos
make bootstrap
make install

I did have to make a couple of detours to install library dependencies specific to CentOS (sudo yum install texinfo ncurses-devel.x86_64).

Now I can copy my ~/bin/centos folder – which contains all the binaries and libraries needed to run Emacs – to the same location on other CentOS 7 systems, add ~/bin/centos/bin to my PATH, and Emacs is ready to go. I did have to copy over my .emacs file and .emacs.d folder to keep my settings and themes. It's basically a self-contained, portable Emacs installation in my home directory on systems where I don't have privileges to install the system Emacs package.

If you give the configure command a folder on a USB drive (like ./configure --prefix=/media/usb/bin) and always mount the USB drive in the same location, you should be able to just mount the USB drive, set your PATH variable, and run Emacs. There doesn't seem to be a way to specify a custom .emacs file or .emacs.d folder when invoking emacs itself, but you could just use a symbolic link from ~/.emacs to /media/usb/.emacs or similar.

Solution 3

I had the same problem as yours (a Linux with some "securizations"). I carried out an already installed version, on the same Linux OS (all the /usr/share/emacs and /usr/libexec trees and all the /usr/bin/emacs* files) and put it on the securized machine.

After running emacs24-x, it asked for a shared library (.so) I cannot remember which one ...

I have also carried it on the destination machine and encapsulated the emacs24-x call (with the function parameters "$@"), in a function which adds the .so location in the LD_LIBRARY_PATH variable (surrounded by () to avoid accumulation).

Then, I have got the messages listed above, about the /usr/share and libexec locations.

I have modified ALL the references to /usr/share/emacs and /usr/libexec in the executables, using a binary editor (like madedit for example) and in a dozen of ASCII files in the copied trees, replacing every "/usr/share" by "/tmp/share" and /tmp/libexec).

In my "emacs" function, I have added the mkdir /tmp/share and two symbolic links (after testing they did not already exist) to connect to the copied emacs trees.

After that, running

emacs <myfile>

works for me perfectly. I have a real portable Emacs version (without having configured it).

Share:
5,498

Related videos on Youtube

user3275006
Author by

user3275006

Updated on September 18, 2022

Comments

  • user3275006
    user3275006 over 1 year

    I'd like to make a "portable" version of Emacs 24.3. I am using some Debian 7 systems, where I don't have root access. Since Debian 7 is missing Emacs 24, I'd like to build a portable version of it, which I can carry with me on a USB thumb drive. My specific questions are:

    1. Can I make the install prefix flexible, or is it hardwired by configure --prefix=...?
    2. How can I bundle all neccessary .so-files with the installation?