How to statically-link a complex program - linux

In Linux, downloaded a program source and want it to be statically linked.
Have a huge Makefile there,
I
./configure
make
to compile.
prehpes it's a bit too general to ask, but how can I make the binary statically linked?
EDIT: the reason for this is wanting to make sure the binary will
have no dependencies (or at least as few as possible), making it possible to run on any Linux based computer, even one without Internet connection, and non-updated Linux.

Most autoconf generated configure script will allow you to make a static build:
./configure --enable-static
make
If that doesn't work, you may be able to pass linker flags in via LDFLAGS, like this:
./configure LDFLAGS=-static

Yeah, you need to edit the make file and add the -static parameter to gcc during the link.

I assume it's using gcc to compile a series of c programs, although you will have to look in the Makefile to find out.
If so, you can adjust the gcc lines in the makefile to do static linking, although depending upon the structure of the program, this may be a complex change. Take a look at man gcc to see how this is done.
I'd be interested to know why you are statically linking. Have you considered using prelinking instead?
You should be aware that there may be licence problems to doing this if all components are not GPL.

If you cannot compile a static binary, I've had good results using Statifier.

Related

Why does uClibc UCLIBC_BUILD_NOEXECSTACK not actually use the linker flag -Wl,-z,noexecstack

One modern Linux security hardening tactic is to compile & link code with the option -Wl,-z-noexecstack, this marks the DLL or binary as not needing an executable stack. This condition can be checked using readelf or other means.
I have been working with uClibc and noticed that it produces objects (.so files) that do not have this flag set. Yet uClibc has a configuration option UCLIBC_BUILD_NOEXECSTACK which according to the help means:
Mark all assembler files as noexecstack, which will mark uClibc
as not requiring an executable stack. (This doesn't prevent other
files you link against from claiming to need an executable stack, it
just won't cause uClibc to request it unnecessarily.)
This is a security thing to make buffer overflows harder to exploit.
...etc...
On some digging into the Makefiles this is correct - the flag is only applied to the assembler.
Because the flag is only passed to the assembler does this mean that the uClibc devs have missed an important hardening flag? There are other options, for example UCLIBC_BUILD_RELRO which do result in the equivalent flag being added to the linker (as -Wl,-z,relro)
However a casual observer could easily misread this and assume, as I originally did, that UCLIBC_BUILD_NOEXECSTACK is actually marking the .so file when it is in fact not. OpenWRT for example ensures that that flag is set when it builds uClibc.
Why would uClibc not do things the 'usual' way? What am I missing here? Are the libraries (e.g. librt.so, libpthread.so, etc) actually not NX?
EDIT
I was able to play with the Makefiles and get the noexecstack bit by using the -Wl,-z,noexecstack argument. So why would they not use that as well?
OK, it turns out after list conversation and further research that:
the GNU linker sets the DLL / executable stack state based on the 'lowest common denominator' i.e. if any linked or referenced part has an exec stack then the whole object is set this way
the 'correct' way to resolve this problem is actually to find and fix assembly / object files that use an exec stack when they dont need to.
Using the linker to 'fix' things is a workaround if you can't otherwise fix the root cause.
So for uClibc solution is to submit a bug so that the underlying objects get fixed. Otherwise anything linked with static libraries wont get a non-exec stack.
For my own question, if building a custom firmware not using any static libraries it is possibly sufficient to use the linker flag.
References:
Ubuntu Security Team - Executable Stacks

Static linking of Libc

I'd need to statically link all the dependencies of a binary in the binary itself (that is also the libc). I've tried the option -static-libgcc but it did not worked, the size of compiled binary is the same as the dynamic compiled one (that is without the static option).
Is it possible to do that? If so, how?
The answer was pretty simple and has been given in a comment by the user Faust, merely just add -static as gcc option.

Can I install both shared .so and static .a versions of a library?

My questions is related to this: Creating both static and shared C++ libraries
I'm compiling a library in order to install it in ~/local on two different systems. It seems that every time I do this I end up with linker problems that take me hours to figure out. The specific library I'm looking at is primesieve. In that library, it's the default to build static libraries only. Unfortunately the example code count_primes.cpp wouldn't link with the static version of the library on one of my systems, for whatever reason. Eventually I figured out how to build the shared version and the code now compiles nicely, with no ugly hacks necessary.
Given the above, it seems to be that compiling both static and shared versions is a good idea if you're working with multiple systems and want the best chance of having your code compile. Is this true? Are there reasons not to build both versions? I realize that this is a bit of a subjective question but it's a serious programming issue that I think many people here have probably encountered.
PS.
This is what I ended up using to compile and install both shared and static versions of primesieve to ~/local:
make
make lib
make install PREFIX=~/local
make clean
make lib SHARED=yes
make install PREFIX=~/local
The make clean is because of this. I then added this to my .bash_profile:
export LIBRARY_PATH=$LIBRARY_PATH:~/local/lib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/local/lib
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:~/local/include
Alternatively, without changing the environment variables I was able to compile the example program count_primes.cpp like this:
g++ -I ~/local/include/ -L ~/local/lib/ -lprimesieve count_primes.cpp
To use a static library you can just include it in the compilation as if it were a regular object file, e.g.
g++ -o foo foo.cpp /path/to/mylib.a
Of course, this means static linking too.
You can still statically link with a dynamic library, so there's not much use for static libraries really.
There is no reason not to build both. Neither library will "do" anything. The shared library will only be loaded if it is in a path viable to the dynamic linker (like you did by adding it to your LD library path). The static one won't be used unless you explicitly link against it - but that is only done at compile (link) time.

dynamic linker dependency info embedded in an archive

Dynamic libraries are nice. The have embedded information in them that help the runtime linker figure what other libraries the final executable needs to load. It also tells the executable what symbols will be loaded
Static libraries, however, are a pain in the neck. The linker won't automatically link an archive's dependencies. This get heinous when statically linking a library that is moderately complicated or has a deep dependency graph.
So why can't archives just include their dependency information? I tried to do just that. The key to my idea is /usr/lib/libc.so. This file is not a shared object file but a linker script.
Linker scripts give you a lot of control over the final linker output, but all I want is to specify dependencies which you can with:
INPUT( -ldependency -ldependecy2 )
Here are my questions.
This seems pretty simple, why hasn't this been done before? I can't be the first person who thought of this. This seems easier and more intuitive than pkg-config or libtool (especially libtool ugh).
I tried to embed the linker script in the archive, it doesn't work. Why not? Can it be made to work? I suspect some clever use of ranlib might do the trick, but it is beyond me.
My current solution is create a linker script called libMyLibrary.a. It contains
INPUT( -lMyRealLibrary -ldependency1 -ldependency2 )
I have to put in the dependencies by hand, it would be nice if ld could for me, but that is problem for another day.
To answer the second part of your question, ar p ARCHIVE SCRIPT will cat the contents of SCRIPT contained in ARCHIVE. Or ar x ARCHIVE SCRIPT to extract the file and then pass it to the linker like ld blah blah -TSCRIPT.
Linker scripts of this form are supported only by GNU-ld (the new Gold ELF linker has limited support as well). If you have any portability requirements, you better not depend on linker script support.
libtool is written specifically to help with portability in creating shared libraries (details of which vary greatly between platforms).
If you don't need portability, then of course you don't need libtool and its complexity.

Can autotools create multi-platform makefiles

I have a plugin project I've been developing for a few years where the plugin works with numerous combinations of [primary application version, 3rd party library version, 32-bit vs. 64-bit]. Is there a (clean) way to use autotools to create a single makefile that builds all versions of the plugin.
As far as I can tell from skimming through the autotools documentation, the closest approximation to what I'd like is to have N independent copies of the project, each with its own makefile. This seems a little suboptimal for testing and development as (a) I'd need to continually propagate code changes across all the different copies and (b) there is a lot of wasted space in duplicating the project so many times. Is there a better way?
EDIT:
I've been rolling my own solution for a while where I have a fancy makefile and some perl scripts to hunt down various 3rd party library versions, etc. As such, I'm open to other non-autotools solutions. For other build tools, I'd want them to be very easy for end users to install. The tools also need to be smart enough to hunt down various 3rd party libraries and headers without a huge amount of trouble. I'm mostly looking for a linux solution, but one that also works for Windows and/or the Mac would be a bonus.
If your question is:
Can I use the autotools on some machine A to create a single universal makefile that will work on all other machines?
then the answer is "No". The autotools do not even make a pretense at trying to do that. They are designed to contain portable code that will determine how to create a workable makefile on the target machine.
If your question is:
Can I use the autotools to configure software that needs to run on different machines, with different versions of the primary software which my plugin works with, plus various 3rd party libraries, not to mention 32-bit vs 64-bit issues?
then the answer is "Yes". The autotools are designed to be able to do that. Further, they work on Unix, Linux, MacOS X, BSD.
I have a program, SQLCMD (which pre-dates the Microsoft program of the same name by a decade and more), which works with the IBM Informix databases. It detects the version of the client software (called IBM Informix ESQL/C, part of the IBM Informix ClientSDK or CSDK) is installed, and whether it is 32-bit or 64-bit. It also detects which version of the software is installed, and adapts its functionality to what is available in the supporting product. It supports versions that have been released over a period of about 17 years. It is autoconfigured -- I had to write some autoconf macros for the Informix functionality, and for a couple of other gizmos (high resolution timing, presence of /dev/stdin etc). But it is doable.
On the other hand, I don't try and release a single makefile that fits all customer machines and environments; there are just too many possibilities for that to be sensible. But autotools takes care of the details for me (and my users). All they do is:
./configure
That's easier than working out how to edit the makefile. (Oh, for the first 10 years, the program was configured by hand. It was hard for people to do, even though I had pretty good defaults set up. That was why I moved to auto-configuration: it makes it much easier for people to install.)
Mr Fooz commented:
I want something in between. Customers will use multiple versions and bitnesses of the same base application on the same machine in my case. I'm not worried about cross-compilation such as building Windows binaries on Linux.
Do you need a separate build of your plugin for the 32-bit and 64-bit versions? (I'd assume yes - but you could surprise me.) So you need to provide a mechanism for the user to say
./configure --use-tppkg=/opt/tp/pkg32-1.0.3
(where tppkg is a code for your third-party package, and the location is specifiable by the user.) However, keep in mind usability: the fewer such options the user has to provide, the better; against that, do not hard code things that should be optional, such as install locations. By all means look in default locations - that's good. And default to the bittiness of the stuff you find. Maybe if you find both 32-bit and 64-bit versions, then you should build both -- that would require careful construction, though. You can always echo "Checking for TP-Package ..." and indicate what you found and where you found it. Then the installer can change the options. Make sure you document in './configure --help' what the options are; this is standard autotools practice.
Do not do anything interactive though; the configure script should run, reporting what it does. The Perl Configure script (note the capital letter - it is a wholly separate automatic configuration system) is one of the few intensively interactive configuration systems left (and that is probably mainly because of its heritage; if starting anew, it would most likely be non-interactive). Such systems are more of a nuisance to configure than the non-interactive ones.
Cross-compilation is tough. I've never needed to do it, thank goodness.
Mr Fooz also commented:
Thanks for the extra comments. I'm looking for something like:
./configure --use-tppkg=/opt/tp/pkg32-1.0.3 --use-tppkg=/opt/tp/pkg64-1.1.2
where it would create both the 32-bit and 64-bit targets in one makefile for the current platform.
Well, I'm sure it could be done; I'm not so sure that it is worth doing by comparison with two separate configuration runs with a complete rebuild in between. You'd probably want to use:
./configure --use-tppkg32=/opt/tp/pkg32-1.0.3 --use-tppkg64=/opt/tp/pkg64-1.1.2
This indicates the two separate directories. You'd have to decide how you're going to do the build, but presumably you'd have two sub-directories, such as 'obj-32' and 'obj-64' for storing the separate sets of object files. You'd also arrange your makefile along the lines of:
FLAGS_32 = ...32-bit compiler options...
FLAGS_64 = ...64-bit compiler options...
TPPKG32DIR = #TPPKG32DIR#
TPPKG64DIR = #TPPKG64DIR#
OBJ32DIR = obj-32
OBJ64DIR = obj-64
BUILD_32 = #BUILD_32#
BUILD_64 = #BUILD_64#
TPPKGDIR =
OBJDIR =
FLAGS =
all: ${BUILD_32} ${BUILD_64}
build_32:
${MAKE} TPPKGDIR=${TPPKG32DIR} OBJDIR=${OBJ32DIR} FLAGS=${FLAGS_32} build
build_64:
${MAKE} TPPKGDIR=${TPPKG64DIR} OBJDIR=${OBJ64DIR} FLAGS=${FLAGS_64} build
build: ${OBJDIR}/plugin.so
This assumes that the plugin would be a shared object. The idea here is that the autotool would detect the 32-bit or 64-bit installs for the Third Party Package, and then make substitutions. The BUILD_32 macro would be set to build_32 if the 32-bit package was required and left empty otherwise; the BUILD_64 macro would be handled similarly.
When the user runs 'make all', it will build the build_32 target first and the build_64 target next. To build the build_32 target, it will re-run make and configure the flags for a 32-bit build. Similarly, to build the build_64 target, it will re-run make and configure the flags for a 64-bit build. It is important that all the flags affected by 32-bit vs 64-bit builds are set on the recursive invocation of make, and that the rules for building objects and libraries are written carefully - for example, the rule for compiling source to object must be careful to place the object file in the correct object directory - using GCC, for example, you would specify (in a .c.o rule):
${CC} ${CFLAGS} -o ${OBJDIR}/$*.o -c $*.c
The macro CFLAGS would include the ${FLAGS} value which deals with the bits (for example, FLAGS_32 = -m32 and FLAGS_64 = -m64, and so when building the 32-bit version,FLAGS = -m32would be included in theCFLAGS` macro.
The residual issues in the autotools is working out how to determine the 32-bit and 64-bit flags. If the worst comes to the worst, you'll have to write macros for that yourself. However, I'd expect (without having researched it) that you can do it using standard facilities from the autotools suite.
Unless you create yourself a carefully (even ruthlessly) symmetric makefile, it won't work reliably.
As far as I know, you can't do that. However, are you stuck with autotools? Are neither CMake nor SCons an option?
We tried it and it doesn't work! So we use now SCons.
Some articles to this topic: 1 and 2
Edit:
Some small example why I love SCons:
env.ParseConfig('pkg-config --cflags --libs glib-2.0')
With this line of code you add GLib to the compile environment (env). And don't forget the User Guide which just great to learn SCons (you really don't have to know Python!). For the end user you could try SCons with PyInstaller or something like that.
And in comparison to make, you use Python, so a complete programming language! With this in mind you can do just everything (more or less).
Have you ever considered to use a single project with multiple build directories?
if your automake project is implemented in a proper way (i.e.: NOT like gcc)
the following is possible:
mkdir build1 build2 build3
cd build1
../configure $(YOUR_OPTIONS)
cd build2
../configure $(YOUR_OPTIONS2)
[...]
you are able to pass different configuration parameters like include directories and compilers (cross compilers i.e.).
you can then even run this in a single make call by running
make -C build1 -C build2 -C build3

Resources