I've been trying to build CPython with static libs so as to port it into another machine. I've managed to make it work, it compiles fine and is accessible from the other machine. But the moment I try to execute a module that requires bz2 it fails because it cannot find the libbz2.so
I compile Python with:
./configure --prefix=/prj/build/python --enable-shared=no --disable-shared LDFLAGS="-L/usr/local/lib64 -L/usr/lib/x86_64-linux-gnu -l:libffi.a -l:libbz2.a" CFLAGS="-fPIC"
make && make install
As you can see, I've been trying to make the configure use the static lib already. I have installed the library with apt-get install libbz2-dev. It works well for libffi but not for libbz2. It goes straight for the .so instead.
I've read somewhere else people suggest using "-static" as flag. But that makes everything static which I don't want. I only need those two built-in modules static.
Thank you very much.
I believe that if you test more carefully you'll find that your attempt to statically link
libffiandlibbz2is actually ineffectual in both cases.The python3 extension module that interfaces to
libffiiscyctpes. The module that interfaces tolibz2is of coursebz2. If you write a minimal python script that calls intocyctpesand another that calls intobz2, then run each script with the python3 interpreter you've built in this way:then setting
LD_DEBUG=libsin the shell will prompt the runtime linker to display information about each shared library that is loaded to run the program. You'll see that thebz2module tester dynamically loadslibbz2.soand also that thectypestester dynamically loadslibffi, which you aim to avoid.Your
./configure...command misses the markThe setting
LD_FLAGS= ... -l:libffi.a -l:libbz2.athat you passed to./configurefails to link against those libraries in the builds of thectypesandbz2modules and links with the default shared libraries instead. If we run your build and capture the build log, we can see that this is so and why.For the
ctypesmodule, the link step output is:For the
bz2module, the link step output is:Notice first that in both cases the
LDFLAGSvalue you have input to./configure, i.e.precedes all the object files to be linked.
Notice also that the default libraries for the these linkages - the ones that you are trying to knock with
-l:libffi.a -l:libbz2.a- are still in the linkages, but they come after all the object files. In thebz2linkage,-lbz2is there, after the object files. And in thectypeslinkage-lffiis there, after the object files.That's probably what you expected, expecting the default shared libaries to be knocked out by the static ones that you have placed before them. But remember how the linker resolves symbols?
It scans the sequence of input files - explicitly named object files, explicitly named libraries and
-l-libraries discovered by search - just once from left to right.It unconditionally links any object file but it searches a library only to find definitions of undefined symbol references that have accrued earlier in the linkage.
When a static library member, e.g.
libffi.a(objfile.o), is found to provide a needed definition then the object fileobjfile.ois copied out of the archive and statically linked into the output file.When a shared library, e.g.
libffi.sois found to provide a needed definition then the linker just drops a note into the output file that will prompt the dynamic linker at runtime to load the necessary shared library and try to resolve remaining undefined symbols against it - that remainder being the symbols that could not be statically defined from the object files linked at buildtime.When the
cytypesandbz2modules are linked as above,-l:libffi.a -l:libbz2.aspecify the very first two files that the linker encounters. They are both libraries. Since nothing at all has so far been linked into the output file, there are 0 undefined symbol references to resolve, and therefore nothing to search for in libraries.libffi.aandlibbz2.acontribute nothing to the linkage at this point and are never considered again.After
libffi.aandlibbz2.aare ignored, the linker finds the object files and links them all into the output file. That brings undefined symbol references into the linkage and obliges the linker to seach subsequent libraries for definitions. Next come the default-loptions that you wanted to knock out,-lffifor thectypesmodule and-lbz2for thebz2module. We are not doing a-staticlinkage, so the linker will for preference resolve these-loptions to the shared librarieslibffi.soandlibbz2.so. Which it duly does, and finds needed definitions in them. So they are added to the dynamic dependencies of the respective modules, just as they would by default.Why your
./configurecommand makes that mistakeYour
./configurecommand results in-l:libffi.a -l:libbz2.abeing interpolated into linkage commands in a position where it has no effect. This stems from a misunderstanding of the autotools linkage environment variablesLD_FLAGSandLIBS. Their proper roles are clarified by running./configure (-h|--help)in the build directory (of any autotooled package) and looking for those variables in the sectionSome influential environment variables:$LD_FLAGSis interpolated into linkage commands before the object files are consumed,$LIBSafter them. This distinction lets you avoid interpolating-l-options uselessly before the object files.The obvious fix - and why it is a loser
It seems obvious that your
./configurecommand should define:to put
-l:libffi.aand-l:libbz2.ain a linkage position where they matter.But this is ineffective in a different way. If you build like that and save the buildlog, you'll now see that whereas previously
-l:libffi.a -l:libbz2.aappeared uselessly in the linkage of every module, now they will appear in the linkage of none.Once again,
./configure -hexplains.All of the extension module builds depend on upstream libraries whose package maintainers define the compilation and linkage options that downstream builds require. These options are expressed in the library.
pcfile that comes with the library's development package and is installed in the like ofusr/lib/x86_64-linux-gnu/pkgconfig/. There, thepkg-configtool can retrieve and query them with commands like1:The
./configure -houtput shows that the python3 build will source theLIBSvalue for linking with any of the upstream extension module librariesLIBNAMEfrom the expansion of$(LIBNAME_LIBS), ifLIBNAME_LIBSis defined, and by default source it from the expansion of$(pkg-config --libs LIBNAME)(Since python3 does not build these upstream libraries,LIBNAME_CFLAGSis irrelevant.)This is just as it should be. But it means that the
./configure-ed value ofLIBSis unused in the extension module builds.The correct
./configure ...command - and why even that is insufficentTo replace the
LIBSvalues sourced frompkg-configin the module builds forctypesandbz2, your./configurecommand should pass:If you build on that basis, you'll get conclusive proof that
libffi.aandlibbz2.ahave been used - because when either of these libraries is used in a-sharedlinkage the build will fail with a relocation linkage error, like:That happens because the packaged static libraries contain object files, like
libbz2.a(bzlib.o), that have not been compiled as position independent code (-fPIC). They can't be linked into a shared library, which must be PIC; they're not intended for-sharedlinkage.Passing
CFLAGS=-fPICin you own./configurecommand can't fix this, because-fPICis a compilation option, and you are not compiling the non-PIC object files in your static libraries, you're just trying to link them-shared. The relocation error diagnostic:is telling you that the object file
libbz2.a(bzlib.o)needs to be recompiled-fPIC. But you haven't got the source code.What else you need to do for success
So before you fix the
./configurecommand for the python3 build, you first need to get the source packages forbzip2andlibffiand build local static librarieslibbz2.aandlibff1.aspecifying-fPICin theCFLAGS.It looks as if
/usr/local/lib64is where you want local libraries, so you could install your-fPICstatic libraries there. Maybe rename themlibbz2-PIC.aandlibff1-PIC.afor clarity and amend your python3./configurecommandline accordingly.You'll then be able to build python3 successfully and the
LD_DEBUG=libstest will show you that thebz2module does not loadlibbz2.soand the thectypesmodule does not loadlibffi.solibbz2-devsource package lacks apkg-config.pcfile. In this case the python3 build just goes ahead with-lbz2to link the libary.