You don't necessarily need to create a statically linked version to get
it to run on a different box. just pack up all required shared libs (use
"ldd" to find out which) plus the dynamic loader itself. The dynamic
loader is normally invoked indirectly via the system, but nothing keeps
you from calling it directly, passing it the name of the dynamically
linked binary to run and the directory where the packed-up libs reside -
see "man ld.so" for details ("ld.so" is the generic name of the dynamic
loader, the actual name on today's 64-bit boxes is typically
ld-linux-x86-64.so.2, which itself is a symlink to ld-.so).
The loader is a statically linked binary, and thus doesn't need any
libs itself.
As I found myself needing something like this rather frequently, I've
put together a little Perl script which automates these steps. Please
find it included below (I've inlined it, as I'm not sure if the mailing
list does allow attachments). Call it without arguments to get a short
usage message.
If you have installed/built a version of mc which works on your local
machine/VirtualBox, you could, for example, say
$ cp-deps mc ~/mytools/mc
(~/mytools/mc is the directory where everything will be put)
The script creates a basic wrapper which you can then tweak as needed.
In the case of mc, you probably want to set the env variable MC_DATADIR
to point to a directory with mc's helper/config files (which you must
copy yourself (e.g. /usr/lib/mc, /usr/share/mc, /etc/mc) - the script
doesn't know anything about the specifics of certain programs, it just
copies the files mentioned in the ldd output):
#!/bin/sh
# adjust this path if you move the installation
myINSTDIR=/home/username/mytools/mc
myEXE=$myINSTDIR/mc.bin
myLIBDIR=$myINSTDIR/lib
myLDSO=$myLIBDIR/ld.so
export MC_DATADIR=$myINSTDIR/mclib
# uncomment to enable debug output (like ldd)
#$myLDSO --library-path $myLIBDIR --list $myEXE
exec $myLDSO --library-path $myLIBDIR $myEXE "$@"
If using MC_DATADIR doesn't work, you might try putting the files mc
warns about not finding in ~/.local/share/mc, ~/.mc or similar.
(Where mc looks for files seems to depend on buildtime configuration -
"strace -efile ..." is your friend to find out where it actually looks)
Finally, scp or rsync everything to your remote box, make sure
myINSTDIR is set correctly, and put the wrapper (or a symlink to it)
somewhere on your $PATH. You should then be able to start mc even
though the remote box has an incompatible glibc version, etc.
Good luck!
--- start of the script cp-deps ---
#!/usr/bin/perl -w
use strict;
sub usage {
print "\nCopy shared library dependencies of an executable into some
directory\n\n";
print "Usage: $0 []\n";
print " e.g. $0 vim [vim_standalone]\n\n";
exit 1;
}
usage() unless @ARGV >= 1;
my ($program, $destdir) = @ARGV;
my ($prg_name) = $program =~ m|([^/]+)/*$|;
$destdir = "./${prg_name}_standalone" unless $destdir;
my $libdir = "$destdir/lib";
sub copy {
my $lib = shift;
print "$lib\n";
system 'cp', '-fa', $lib, $libdir;
}
my $exe = qx(which $program) # ldd doesn't look in PATH
or die "Failed to determine path of $program";
chomp $exe;
for my $dir ($destdir, $libdir) {
unless (-d $dir) {
mkdir $dir or die "Couldn't create $dir: $!";
}
}
for my $dep (split /\n/, qx(ldd $exe) ) {
my ($lib) = $dep =~ m|=>\s+(\S+)\s+\(0x|; # extract lib path
unless (defined $lib) {
# we want the dynamic loader, too
($lib) = $dep =~ m|(/lib.*/ld-linux.*\.so\S*)|;
if (defined $lib) {
my ($ld_so) = $lib =~ m|([^/]+)$|;
symlink $ld_so, "$libdir/ld.so"; # additional unified link
}
}
if (defined $lib) {
unless (-l $lib) {
copy $lib;
} else { # symlink
print "$lib\n";
my ($name) = $lib =~ m|([^/]+)$|; # orig link name
while (-l $lib) { # resolve...
my $path = $lib;
$lib = readlink $lib;
unless ($lib =~ m|^/|) { # relative ?
(my $dir = $path) =~ s|[^/]+$||;
$lib = $dir.$lib;
}
}
copy $lib; # resolved path
my ($file) = $lib =~ m|([^/]+)$|; # name of resolved/copied file
my $lnk = "$libdir/$name";
unlink $lnk;
symlink $file, $lnk; # create directory-local link
}
print "\n";
}
}
my ($exe_name) = $exe =~ m|([^/]+)$|;
system 'cp', '-faL', $exe, "$destdir/$exe_name.bin";
#
use Cwd;
my $instdir = Cwd::realpath($destdir);
my $wrapper = "$destdir/$exe_name";
open my $fh, ">", $wrapper or die "Couldn't create wrapper $wrapper: $!";
print $fh <<"EOF";
#!/bin/sh
# adjust this path if you move the installation
myINSTDIR=$instdir
myEXE=\$myINSTDIR/$exe_name.bin
myLIBDIR=\$myINSTDIR/lib
myLDSO=\$myLIBDIR/ld.so
# uncomment to enable debug output (like ldd)