How to build *.so module in Automake and a libtool-using project?

towi picture towi · Dec 19, 2012 · Viewed 12.3k times · Source

I have the same problem as others have:

  • I have a *.la file generated by libtool in an Automake project (e.g. module.la),
  • but I need the *.so of it to use it for dlopen() (eg. module.so).

But: project is configured and built with --disable-shared to make sure the created main binary is one big statically linked program, e.g. main.x (easier for deployment and debugging). Thus *.so files are not created.

The program main.x is a huge framework-like application which is capable of loading extensions (modules) via dlopen() -- despite it being linked statically.

This works fine when I build module.so by hand. But putting this to work in Makefile.am seems impossible to me. Yes, I can write lib_LTLIBRARIES, but with my standard --disable-shared I do not get a *.so file.

lib_LTLIBRARIES = module.la
module_so_SOURCES = module.cpp

The file module.la is created, which dlopen() refuses to load (of course).

I tried to put rules into Makefile.am building it manually and that works:

# Makefile.am (yes, .am)
all: mm_cpp_logger.so

SUFFIXES = .so

%.so: %.cpp
    $(CXX) $(CXXFLAGS) -fPIC -fpic -c -I $(top_srcdir)/include -o $@  $<

%.so: %.o
    $(CXX) $(LDFLAGS) -shared -fPIC -fpic -o $@  $<

But this can only be a workaround. I do not get all the nice auto-features like dependency-checking and installation.

How can I build module.so with still building the main program with --disable-shared (or with the same effect) in the Makefile.am-way?

  • can I postprocess *.la files to *.so files with a special automake rule?
  • can I tweak the lib_LTLIBRARIES process to create *.so files in any case?

Answer

uml&#228;ute picture umläute · Jan 8, 2013

What you are looking for is called a module. You can tell Autotools to create a static binary (executable) by adding -all-static to the LDFLAGS of the application. I think this is the preferred way over using --disable-shared configure flag (which really is aimed at the libraries rather than the executable)

Something like this should do the trick:

AM_CPPFLAGS=-I$(top_srcdir)/include

lib_LTLIBRARIES = module.la
module_la_LDFLAGS = -module -avoid-version -shared
module_la_SOURCES = mm_cpp_logger.cpp

bin_PROGRAMS = application
application_LDFLAGS = -all-static
application_SOURCES = main.cpp

The .so file will (as usual) end up in the .libs/ subdirectory (unless you install it, of course).

And you can build both your application and plugins in one go (even with a single Makefile.am), so there is no need to call configure multiple times.

The use of -fPIC (and friends) should be auto-detected by Autotools.


Update: here's a little trick to make the shared-libraries available where you expect them. Since all shlibs end up in .libs/, it is sometimes nice to have them in a non-hidden directory.

The following makefile snippet creates convenience links (on platforms that support symlinks; otherwise they are copied). Simply adding the snippet to your makefile (i usually use an -include convenience-link.mk) should be enough (you might need an AC_PROG_LN_S in your configure.ac)

.PHONY: convenience-link clean-convenience-link

convenience-link: $(lib_LTLIBRARIES)
    @for soname in `echo | $(EGREP) "^dlname=" $^ | $(SED) -e "s|^dlname='\(.*\)'|\1|"`; do  \
        echo "$$soname: creating convenience link from $(abs_builddir)/.libs to $(top_builddir)"; \
        rm -f $(top_builddir)/$$soname ; \
        test -e $(abs_builddir)/.libs/$$soname && \
        cd $(top_builddir) && \
        $(LN_S) $(abs_builddir)/.libs/$$soname $$soname || true;\
    done 

clean-convenience-link:
    @for soname in `echo | $(EGREP) "^dlname=" $(lib_LTLIBRARIES) | $(SED) -e "s|^dlname='\(.*\)'|\1|"`; do  \
        echo "$$soname: cleaning convenience links"; \
        test -L $(top_builddir)/$$soname && rm -f $(top_builddir)/$$soname || true; \
    done 
        
all-local:: convenience-link

clean-local:: clean-convenience-link