Re: Static build of mc
- From: Erdmut Pfeifer <e pfeifer science-computing de>
- To: david leighweb com
- Cc: mc gnome org
- Subject: Re: Static build of mc
- Date: Mon, 12 Sep 2016 18:24:04 +0200
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-<version>.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 <program> [<dest_dir>]\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)
#\$myLDSO --library-path \$myLIBDIR --list \$myEXE
exec \$myLDSO --library-path \$myLIBDIR \$myEXE "\$@"
EOF
close $fh;
chmod 0755, $wrapper, "$destdir/$exe_name.bin";
--- end of script ---
On Mon, Sep 12, 2016 at 02:19:27PM +0200, david leighweb com wrote:
I'm on a web host shared server that I like VERY much: O2Switch (o2switch.fr) They give a LOT of
functionality for the money, including
shell access. Unfortunately they don't have mc installed and are not willing to install it.
I've tried to find other ncurses-based file managers and editors but nothing even comes CLOSE to mc and
what it does for me. I've got the
python ranger file manager to work but I DON'T know and don't have time to learn vim key-bindings so it's
almost useless to me. mc simply
works the way I do and I would really like to get it working on this environment. The hosting company says
I'm free to put on there things
that I can get to run within the limitations of being a standard user. I can't run package installers, nor
can I compile anything. I've
gotten other small statically-linked programs to run fine in my user environment. So I would like a
statically-linked, user-environment
version of mc (even if some of the more esoteric features don't fully work - though what's esoteric for me
may not be for someone else).
They told me that the server is a CentOS 6 box. I see traces of CloudLinux and CageFS in my user space as
well.
So I created a VirtualBox CentOS 6.8 machine (Win 10 Pro host). I installed the mc yum package and it runs
fine in my VM. So then I tried
to copy the appropriate files to my web hosting user space (/etc/mc >>> ~/etc/mc, ~/usr..., and so on).
Unfortunately it complained about
the version of glibc (2.12) on the server. I saw ONE statically linked mc on the web here:
https://github.com/linux-static/linux-static-i386/downloads but it will only run if placed under /opt and I
don't have access to that on my
user space (in .Cagefs there is an /opt. I tried putting it there, but mc wouldn't start, complaining of
something missing/wrong
version...sorry don't remember the details - I've tried SO MANY things)
While I have a programming background (IBM mainframe assembler and COBOL and LOTS of various scripting),
none of it is in Linux so I've
been getting a crash, self-taught course in linking/loading elf-style, etc. I'm still in WAY over my head
though.
It looked like I was going to need to compile it myself. So I tried to compile it statically on my CentOS
box using hints from this site:
https://namelythehedgehog.wordpress.com/2010/04/20/compile-static-copy-of-midnight-commander/ where he
suggests this configure line:
./configure --with-glib-static --without-x --disable-shared --enable-static \
CC='gcc -static -static-libgcc -fno-exceptions' \
CXX='g++ -static -static-libgcc -fno-exceptions' \
LDFLAGS='-Wl,-static -static -lc' \
LIBS='-lc'
The CentOS 6.8 had a problem with glibc versions and the mc source version I tried (4.8.17). So I read
more and found out that I really
needed to have the static versions of glibc as well so I went to create a user-space static version of
glibc. I couldn't get that to work
with my CentOS VM and VirtualBox with CentOS is is EXTREMELY painful. So I fell back to my xubuntu VM and
succeeded in compiling the
latest glibc to a non-system directory. So I modified the configure line to the following:
./configure --with-glib-static --without-x --disable-shared --enable-static \
CC='gcc -static -static-libgcc -fno-exceptions' \
CXX='g++ -static -static-libgcc -fno-exceptions' \
LDFLAGS='-Wl,-static -static -L/root/myglibc/build/lib -lc' \
LIBS='-L/root/myglibc/build/lib -lc'
For good measure and because it wasn't finding a static glibc, I also did:
export GLIB_LIBDIR=/root/myglibc/build/lib
export LD_LIBRARY_PATH=/root/myglibc/build/lib
The end result though is still the same message:
configure: error: Cannot find static glib
and it stops right there. If I look in /root/myglibc/build/lib, there is a libc.a so I really am at the
end of my understanding and
patience and time. I can't imagine that there is NOT a solution, but I need help from people who know this
MUCH better than I do.
So, if any of you smart people can point out to me the error of my ways or point me to other copies of
statically linked mc that should
work (that I can simply do copies of the relevant files into my user-space), please let me know. I'll be
very grateful and I promise to
pass on my eventual success to others in my same situation.
Many thanks in advance!
_______________________________________________
mc mailing list
https://mail.gnome.org/mailman/listinfo/mc
--
Science + Computing AG
Vorstandsvorsitzender/Chairman of the board of management:
Dr. Martin Matzke
Vorstand/Board of Management:
Johannes Barthmes, Yvonne Veyhelmann
Vorsitzender des Aufsichtsrats/
Chairman of the Supervisory Board:
Philippe Miltin
Aufsichtsrat/Supervisory Board:
Martin Wibbe, Winfried Holz
Sitz/Registered Office: Tuebingen
Registergericht/Registration Court: Stuttgart
Registernummer/Commercial Register No.: HRB 382196
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]