How to make a portable Linux app?
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.