bkchapin has asked for the wisdom of the Perl Monks concerning the following question:

The situation: I'm working on a module that among others uses Curses, DBI, and DBD-Informix, and must run on Linux, HP-UX and SCO. Linux is easy. We have managed to get this to work under HP-UX by building gcc from source, and compiling everything with gcc, including ncurses as the native curses didn't have enough functionality. Even hacked Informix's esql script to use gcc rather than the native compiler. We haven't fooled with SCO much yet.

The customer doesn't want to install libraries. Afraid there will be conflicts, and doesn't want to go through a long approval process. (Not to mention, building gcc from source is a pain.) Also, I've read that SCO can't do dynamic linking the way perl needs it (no Dynaloader?), therefore perl on SCO is statically linked. Is static linking the answer? I learned of "perl Makefile.PL; make perl", which is fine for statically linking just one module. But how to do more than one? Do "make perl" on Curses first, then somehow add in DBI and others? The Camel book doesn't really say.

Replies are listed 'Best First'.
Re: static linking demanded
by ysth (Canon) on Sep 07, 2007 at 05:22 UTC
    I learned of "perl Makefile.PL; make perl", which is fine for statically linking just one module. But how to do more than one? Do "make perl" on Curses first, then somehow add in DBI and others? The Camel book doesn't really say.
    I didn't know just "make perl" worked; the invocation I'm familiar with is "perl Makefile.PL LINKTYPE=static", and that's what I see in the ExtUtils::MakeMaker docs. Making a static module is supposed to include all previously statically built modules automatically. Have you tried it?

    But this only gets you the perl XS libraries statically linked; if those refer to other libraries, that will probably still be dynamic.

Re: static linking demanded
by sgt (Deacon) on Sep 07, 2007 at 12:06 UTC

    Static linking is almost never the answer, but there is one exception which is if you need bindings to an external system that somehow does not give you position-independent code. An example for many years was arsperl.

    If you want to go with static linking then ysth's post is the answer.

    If a system does not support dynamic loading (Is SCO really like this? -- that would IMHO almost qualify as a dinosaur-OS ;), I believe that any XS glue must be compiled statically. If the glue needs shared libraries then they will be called "statically" by the system dynamic loader (at executable startup time usually, but compiler flags can normally enable some on-demand mode) in the usual way i.e the way the system will load the libc shared library.

    Still you have another option: Build a perl with all dependencies inside the distribution tree. I have been doing that for years on HP-UX.

  • First you pick you path: say PREFIX=/var/tmp/p/opt/perl588. This is my "main" PREFIX.
  • Put all your extlibs below $PREFIX/ext say. each extlib in its own dir. In general you'll have {extlib}/inc and {extlib}/lib.
  • Build perl. note that you can currently build once, deploy many i.e have make install say write in /var/tmp/p/opt/perl588 and also /opt/perl588 for example.
  • Build all your external modules. Any build should point at libraries in $PREFIX/ext (say your own libexpat and libxml2 etc...).
  • Check that the previous claim is true. On HP-UX you can use chatr; on others ldd is your friend; on cygwin you'll use cygcheck etc. You are the one in control here: it's you who defines if a library is external or internal to your distribution. (As an example you might like to include say 3 differents versions of oracle client libraries, working with different copies of DBD::Oracle, each one with the right glue! -- and tell me then if 'no ...;' really works;).
  • You have to repeat the process for any client path where you plan to have perl+modules installed. Yes this involves rebuilding all the modules...

    On HP-UX I use a dirty trick to speed up the process. suppose I built all my modules for /var/tmp/opt/perl588. I want them now for /opt/perl588. The install process takes care of the perl core. So for the modules I have to care about a few things:

  • shared libraries that depend on a library inside /var/tmp/opt/perl588/ext
  • special directories needed by a module. Here the solution is easy: just use a common path for all distribs (must not be contained in any final "PREFIX" dir.
  • I deal with the first point by direct (binary) subst on each shared object. I use perl of course ;) 'perl -0pi s{/var/tmp/p/opt/perl588}{///////////opt/perl588}' (or a variant setting a flag to modify only the first "line" seen)
  • binary grep for /var/tmp/p/perl588 just in case ;)

    The result is a tarrable perl dist that you can install almost anywhere (it has two parts the perl dir + special dirs needed by modules).

    Note that I do not like shared libraries with dependencies on other shared libraries. It is just too confusing. When I build my own shared libraries I try to avoid that. The responsability of knowing with what to link should be the responsability of the executable. Of course bindings are another matter.

    Nicholas Clark did some work on making perl more relocatable (IIRC was done after 5.8.8). You can browse the p5p archives to see the details.

    cheers --stephan

    P.S there might be licensing issues...

      What I've heard is SCO does not have libdl or some equivalent. So, no dlopen library function. SCO still has some sort of dynamic linking, just not that kind.

      Took me a moment to understand that dirty trick with the library directory, and yeah, that's pretty cool, sneaky, and dirty. The crucial point is that the length of the directory name is kept the same by padding the front of the name with the correct number of '/' characters. Sort of the NOP of directory names.

        A dirty hack for sure. On cygwin and possibly others you might have to use /. instead of // as // might indicate some network share. Devious things can even be done to defeat checksum schemes.

        Dynamic linking is really when you can load at runtime a shared library; this is what perl needs for "use ...;". What is given by a "dynamic linker" like dld (/usr/lib/ for example) and the such is actually pretty static. The terminology varies a lot with the O.S. True dynamic linking is when a program can use the same API as the "dynamic linker". In perl code the true dynamic nature of a dlopen-like API means you can "use" to load and "no" to unload; this can be useful if you need to maintain a low memory consumption profile (using "use" and "no" as many times as necessary). Note that a process will not give back to the O.S the memory once taken but it can certainly reuse.

        cheers --stephan
Re: static linking demanded
by starX (Chaplain) on Sep 06, 2007 at 19:38 UTC
    Have you considered PAR? I've met with some success in my (admittedly limited) attempts to port things between different platforms. Then again, according to the docs, it loads XS modules by overriding DynaLoader, not by bypassing it. Not sure if that will be an issue for you.
Re: static linking demanded
by andyford (Curate) on Sep 06, 2007 at 19:31 UTC
    I would think that you could install your libraries and modules under a dedicated application tree to avoid conflicts instead of trying to statically compile. Seems much simpler. After all, you have to at least install your own ncurses, right?

    Update: did some research, excuse my delirium.

    non-Perl: Andy Ford