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

  # 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 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/";   # 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";

# adjust this path if you move the installation


# 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 

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

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