RE: Static build of mc

Thank you Erdmut.  I'll look at Yury's solution and yours and see what
happens.  At least you've given me hope to keep trying (and I'll learn even
more in the process!)

-----Original Message-----
From: Erdmut Pfeifer [mailto:e pfeifer science-computing de] 
Sent: Monday, September 12, 2016 06:24 PM
To: david leighweb com
Cc: mc gnome org
Subject: Re: Static build of mc

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" for
details ("" is the generic name of the dynamic loader, the actual name
on today's 64-bit boxes is typically, which itself is a
symlink to ld-<version>.so).
The loader is a statically linked binary, and thus doesn't need any libs

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):

  # adjust this path if you move the installation
  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
    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/";   # 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
            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";

# adjust this path if you move the installation myINSTDIR=$instdir


# uncomment to enable debug output (like ldd) #\$myLDSO --library-path
\$myLIBDIR --list \$myEXE

exec \$myLDSO --library-path \$myLIBDIR \$myEXE "\$@"

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 
( 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: 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 

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:
dnight-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' \

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
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]