coin-or-tools / BuildTools

Macros and patches for GNU autotools
https://coin-or-tools.github.io/BuildTools/
Other
3 stars 7 forks source link

Native support for building statically #136

Closed tkralphs closed 4 years ago

tkralphs commented 4 years ago

After all the time spent trying to figure out how to build fully static executables, I now realized that SYMPHONY already had a recipe for that baked into its build system. See here:

https://github.com/coin-or/SYMPHONY/blob/master/SYMPHONY/src/Makefile.am#L353

Ugh, that all-important -all-static flag was sitting right there the whole time. I guess one of my co-developers figured that out long ago. Would it make sense to provide a --fully-static flag to configure? I guess maybe not, since to get truly static libraries, it seems necessary to ensure that no system libraries that are shared are linked in, etc. Or I guess we could also forbid that at configure time in the case of fully static? What do you think?

svigerske commented 4 years ago

I extra made the LT_LDFLAGS variable more accessible in d1d64dc, so that it is easier to set the -all-static flag for libtool. I would think that there is no need for an extra configure flag that just sets this flag.

svigerske commented 4 years ago

I probably didn't understand what you meant by " forbid that at configure time". You mean adding -static to LDFLAGS?

tkralphs commented 4 years ago

I just meant basically transferring the recipe that is now in coinbrew (here) to configure. We would just ignore any request to link to libraries we know will prevent the fully static executable from being created. One of the sticking points that was not at all obvious was just that even when you specify -static and do everything right, libtool will happily link to shared libraries anyway and you end up with a non-static executable even though you explicitly said you don't want one.

svigerske commented 4 years ago

That thing in coinbrew seems to assume that bzlib, readline, lapack, amd, etc are only available as shared libraries and have to be disabled. Also it seems to think that third-party needs to be disabled. I don't think that such restrictive and specific rules are what one would want to have in BuildTools.

I get it that a -static in the libtool flags just tells libtool to build a static library, which may depend on other libs that may be available as shared library only. With -all-static in the libtool flags, a -static should be passed on to the linker, as far as I understood. For executables this would then fail when some lib is not available as shared library.

Maybe a call of configure with LT_LDFLAGS=-all-static LDFLAGS=-static --disable-shared would do something to also prevent configure from recognizing packages that are not available as static libraries. For coin-or packages, we just believe that the flags from the .pc file are working, though, and do not try linking something during configure.

tkralphs commented 4 years ago

Hmm, OK, I see your point. Yes, I am assuming that those libraries that are disabled are only available as shared libraries, since that's the typical case and when it's not, the person doing the building will presumably know enough to build by hand. So I guess it's betters as is.

It seems to me that libtool linking doesn't ever fail because it cannot find a static library, though, even when -all-static and -static are specified. This is what was so frustrating in trying to make static executables. I couldn't ever get libtool to explain when things were going wrong. I just had to try and see if I get what I wanted, there was never an error.

svigerske commented 4 years ago

So I can get pretty far with the above mentioned LT_LDFLAGS=-all-static LDFLAGS=-static --disable-shared

e38d1115 changes the lapack test to only warn if lapack.pc is present, but linking doesn't work.

I updated the Makefile.am of the unittest of CoinUtils, Osi, Clp, Cgl, and Cbc to acknowledge LT_LDFLAGS, so their binary is build with -static, too.

On my system, which has only shared library versions of gfortran and lapack, I can get static executables of cbc and clp and static libs lib/libCbc.a lib/libCgl.a lib/libClpSolver.a lib/libcoinglpk.a lib/libCoinUtils.a lib/libOsiCbc.a lib/libOsiCommonTest.a lib/libCbcSolver.a lib/libClp.a lib/libcoinasl.a lib/libcoinmetis.a lib/libOsi.a lib/libOsiClp.a lib/libOsiGlpk.a if I omit trying to build Mumps and HSL.

Maybe these configure flags are something you want to mention in https://coin-or.github.io/user_introduction#additional-useful-information

tkralphs commented 4 years ago

So you did not need to disable all the libraries that I did? And you managed to get fully static binaries? I tried many incantations and couldn't get fully static executables without manually disabling libraries. I can try again, but something strange is going on here.

svigerske commented 4 years ago

The flags mentioned are all the ones for configure necessary for me.

I got "fully static binaries":

$ ldd bin/*
bin/cbc:
    not a dynamic executable
bin/cbc-generic:
    not a dynamic executable
bin/clp:
    not a dynamic executable
bin/glpsol:
    not a dynamic executable

I haven't tried whether --disable-shared is indeed necessary or whether configure will figure out by itself that it cannot build shared libraries with LDFLAGS=-static.

tkralphs commented 4 years ago

I built Clp with LT_LDFLAGS=-all-static LDFLAGS=-static --disable-shared and got this.

~/tmp/dist/bin > ldd clp
        linux-vdso.so.1 (0x00007fffd4f7e000)
        libbz2.so.1.0 => /lib/x86_64-linux-gnu/libbz2.so.1.0 (0x00007ff3603d0000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007ff3601b0000)
        liblapack.so.3 => /usr/lib/x86_64-linux-gnu/liblapack.so.3 (0x00007ff35f910000)
        libgfortran.so.4 => /usr/lib/x86_64-linux-gnu/libgfortran.so.4 (0x00007ff35f530000)
        libblas.so.3 => /usr/lib/x86_64-linux-gnu/libblas.so.3 (0x00007ff35f2c0000)
        libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007ff35f030000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ff35ee10000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ff35ea80000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff35e6e0000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ff35e4c0000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff35e0c0000)
        libquadmath.so.0 => /usr/lib/x86_64-linux-gnu/libquadmath.so.0 (0x00007ff35de80000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ff361000000)
svigerske commented 4 years ago

So what should I do with that? I cannot look into your system to see what has happening to get you there.

tkralphs commented 4 years ago

I wasn't expecting you to do anything with that, just providing a data point. Anyway, I realized that I was accidentally building 2.10.5 and the behavior is much different there. There seems to be no hope of static binaries there.

I tried your recipe with master and I did now get some errors when things are not working, which helps immensely. I still needed to disable readline, but I no longer need to disable the other things I was previously disabling. Thanks!

svigerske commented 4 years ago

Well, I was curious why you had gotten this, but there was so little information... :).

If there are errors that should rather be warnings, then we can look into it. If there is only a shared libgfortran, there is not much one can do from within configure - you just cannot build mumps or hsl then. What do you get if you don't disable readline? An error or a dependency on a shared library?

tkralphs commented 4 years ago

It looked like a dependency on a shared library, but let me do it again and see.

tkralphs commented 4 years ago

With readline, I get a bunch of errors like this, which I take to mean that I will not get a static executable in the end.

/mnt/c/Users/tkral/Documents/tmp/dist/lib/libcoinasl.a(funcadd1.o): In function `dl_open.isra.0':
funcadd1.c:(.text+0x129): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libreadline.a(complete.o): In function `rl_username_completion_function':
(.text+0x4419): warning: Using 'getpwent' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

Strangely, although there is an error with ASL, it goes away if I disable readline.

tkralphs commented 4 years ago

I'll see if this is fixed by -static-libgcc and -static-libstdc++.

svigerske commented 4 years ago

These are warning, not errors. I also get the one regarding dlopen in codes that use it (like ASL), but I get a static binary at the end. I guess they will at least work until these specific functions are called.

tkralphs commented 4 years ago

Ah, OK. Those are warnings, but there are errors because the build stops. There are a bunch of errors like these:

/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libreadline.a(display.o): In function `_rl_move_cursor_relative':(.text+0xf86): undefined reference to `tputs'
(.text+0xfec): undefined reference to `tputs'
(.text+0x11ac): undefined reference to `tputs'

Not sure how to interpret that. There seems to be a mismatch between the static version of readline installed and some other libraries. Guess I could do an update and see if that helps.

svigerske commented 4 years ago

Maybe it just misses to link against -lncurses. AC_COIN_CHK_GNU_READLINE seems to look for it, but doesn't add it to LFLAGS

svigerske commented 4 years ago

Maybe it just misses to link against -lncurses. AC_COIN_CHK_GNU_READLINE seems to look for it, but doesn't add it to LFLAGS

Maybe this would do:

diff --git a/coin.m4 b/coin.m4
index 0707ed1..c4389c6 100644
--- a/coin.m4
+++ b/coin.m4
@@ -1895,7 +1895,7 @@ AC_DEFUN([AC_COIN_CHK_GNU_READLINE],
     fi
     if test $coin_has_readline = yes ; then
       m4_foreach_w([myvar],[$1],
-        [m4_toupper(myvar)_LFLAGS="-lreadline $m4_toupper(myvar)_LFLAGS"
+        [m4_toupper(myvar)_LFLAGS="$LIBS $m4_toupper(myvar)_LFLAGS"
         ])
       AC_DEFINE([COIN_HAS_READLINE],[1],[Define to 1 if readline is available])
     fi
tkralphs commented 4 years ago

Yes, that worked.

tkralphs commented 4 years ago

Excellent, static libraries without any special recipe! Wahoo!

tkralphs commented 4 years ago

Will you apply the fix then?

svigerske commented 4 years ago

yes, done

tkralphs commented 4 years ago

Are you going to re-run autotools for all the projects?

svigerske commented 4 years ago

I should get there later today as I'm doing some other changes in BuildTools anyway.