An efsdeploy customization example: fsf/pari/2.3.5

This will be an experiment to see whether or not I like the blogging infrastructure here at openefs.org…

The installation of fsf/pari/2.3.5 depends on fsf/gmp/5.0.1, and we would like the shared library in fsf/pari/2.3.5 to have an RPATH so that it finds libgmp without any help. However, the autogenerated Makefile for libpari doesn’t use the rpath arguments we specify in the environment. efsdeploy exports the necessary LDFLAGS variable, and most configure implementions do the Right Thing. Not fsf/pari.

So, let’s take a closer look at the auto-generated Makefile, and figure out how to write a configure-post script that bends it to our will. For starters, I’m working with an existing efsdeploy-based build that worked, but simply didn’t have the right RPATH. In order to analyze the auto-generated Makefile, I created a new release (fsf/pari/2.3.5-build003), and took the installation only as far as configure:

efsdeploy download source configure

Now, I can login to one of the compile servers, and poke around in the source tree. You can see which hosts were used for each platform/compiler build using “efsdeploy status-detail”. In this case, the directory I’m interested in is:

$hostname:/var/tmp/fsf-pari-2.3.5-build003-build/x86-64.rhel.5/gcc443/source/pari-2.3.5

There are several Makefile’s generated by pari’s Configure script:

[PWD = /var/tmp/fsf-pari-2.3.5-build003-build/x86-64.rhel.5/gcc443/source/pari-2.3.5]
pmoore@elabibm02$ find . -name Makefile -print
./Makefile
./Olinux-x86_64/Makefile
./doc/Makefile
./examples/Makefile
./Odos/Makefile

The interesting one is ./Olinux-x86_64/Makefile. Here’s the snippet of code that links the shared library:

$(LIBPARI_DYN): ../src/funclist $(OBJS) $(EXPORT_FILE)
        -$(RM) $(LIBPARI_DYN)
        $(DLLD_IGNORE)$(DLLD) -o $(LIBPARI_DYN) $(DLLDFLAGS) $(OBJS) $(EXTRADLLDFLAGS) $(EXPORT_FILE)

The relevant variable definitions are:

CFLAGS     = -O3 -Wall -fno-strict-aliasing -fomit-frame-pointer   -I/efs/dist/fsf/readline/5.2/.exec/x86-64.rhel.5/include -I/efs/dist/fsf/readline/5.2/common/include -I/efs/dist/fsf/gmp/5.0.1/.exec/x86-64.rhel.5/include -I/efs/dist/fsf/gmp/5.0.1/common/include -I/efs/dist/fsf/ncurses/5.6/.exec/x86-64.rhel.5/include -I/efs/dist/fsf/ncurses/5.6/common/include
 
LDFLAGS    = -O3 -Wall -fno-strict-aliasing -fomit-frame-pointer   -I/efs/dist/fsf/readline/5.2/.exec/x86-64.rhel.5/include -I/efs/dist/fsf/readline/5.2/common/include -I/efs/dist/fsf/gmp/5.0.1/.exec/x86-64.rhel.5/include -I/efs/dist/fsf/gmp/5.0.1/common/include -I/efs/dist/fsf/ncurses/5.6/.exec/x86-64.rhel.5/include -I/efs/dist/fsf/ncurses/5.6/common/include -Wl,--export-dynamic -L/efs/dist/fsf/readline/5.2/.exec/x86-64.rhel.5/lib -Wl,-rpath,/efs/dist/fsf/readline/5.2/.exec/x86-64.rhel.5/lib -L/efs/dist/fsf/gmp/5.0.1/.exec/x86-64.rhel.5/lib -Wl,-rpath,/efs/dist/fsf/gmp/5.0.1/.exec/x86-64.rhel.5/lib -L/efs/dist/fsf/ncurses/5.6/.exec/x86-64.rhel.5/lib -Wl,-rpath,/efs/dist/fsf/ncurses/5.6/.exec/x86-64.rhel.5/lib -L/efs/dist/fsf/ncurses/5.6/common/lib -Wl,-rpath,/efs/dist/fsf/ncurses/5.6/common/lib
 
DLLDFLAGS  = -shared  $(CFLAGS) $(DLCFLAGS) -Wl,-shared,-soname=$(LIBPARI_SONAME)

First thing to note is that LDFLAGS is just CFLAGS, plus the -L and -Wl,-rpath arguments. Therefore, if we want to get those additional arguments to be used by the LIBPARI_DYN target, we can change the DLLDFLAGS definition to use LDFLAGS instead of CFLAGS. How do you do this?

By writing a configure-post hook that edits the Makefile. This is relatively straight forward with efsdeploy. Now, before we write the hook, it makes sense to test the idea out. Manually performing the edit described above, we can then simply complete the build process for one platform, and check the results:

efsdeploy build test install —platforms x86-64.rhel.5 —compilers gcc443

Once this done, inspecting the resulting shared object we can see that the desired rpath is generated:

[PWD = /efs/dev/fsf/pari/2.3.5-build003/src]
pmoore@apps923-d$ readelf -d ../install/.exec/x86-64.rhel.5/lib/libpari.so | grep rpath
 0x000000000000000f (RPATH)              Library rpath: [/efs/dist/fsf/readline/5.2/.exec/x86-64.rhel.5/lib:/efs/dist/fsf/gmp/5.0.1/.exec/x86-64.rhel.5/lib:/efs/dist/fsf/ncurses/5.6/.exec/x86-64.rhel.5/lib:/efs/dist/fsf/ncurses/5.6/common/lib:/efs/dist/fsf/gcclib/4.4.3/.exec/x86-64.rhel.5/lib]

To be pendantic, this includes some directories we don’t necessarily need, but the extra directories are harmless. Since we specify ALL of the dependencies in one comprehensive variable (LDFLAGS), they tend to be used for EVERYTHING the build process links. Fine tuning the build to limit the rpath minimally for each distinct binary and library would be a customization that is orders of magnitude more complex.

Now that we know this change stuffs the RPATH into the resulting library, we need to automate the change, so that it’s done for all platforms, and all future builds of this product.

The attached configure-post script does this, and also makes one other change as well. For some reason, the pari authors don’t trust ld.so, and they drop /usr/lib into the RPATH. This is not necessary, so I’ve added a snippet of code that strips the trailing /usr/lib from the two variables that use it.

Questions? :-P