Как построить модуль *.so в Automake и проекте, использующем libtool?

У меня та же проблема, что и другие:

  • У меня есть *.la файл, созданный libtool в проекте Automake (например, module.la),
  • но мне нужен *.so, чтобы использовать его для dlopen() (например, module.so).

Но: проект сконфигурирован и построен с помощью --disable-shared, чтобы убедиться, что созданный основной двоичный файл является одной большой статически связанной программой, например. main.x (проще для развертывания и отладки). Таким образом, файлы *.so не создаются.

Программа main.x представляет собой огромное фреймворк-приложение, способное загружать расширения (модули) через dlopen() - несмотря на то, что оно связано статически.

Это отлично работает, когда я строю module.so вручную. Но сделать это для работы в Makefile.am представляется мне невозможным. Да, я могу написать lib_LTLIBRARIES, но с моим стандартом --disable-shared я не получаю файл *.so.

lib_LTLIBRARIES = module.la
module_so_SOURCES = module.cpp

Создается файл module.la, который dlopen() отказывается загружать (конечно).

Я попытался поместить правила в Makefile.am, строя его вручную, и это работает:

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

SUFFIXES = .so

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

%.so: %.o
    $(CXX) $(LDFLAGS) -shared -fPIC -fpic -o [email protected]  $<

Но это может быть только обходным путем. Я не получаю все хорошие автоматические функции, такие как проверка зависимостей и установка.

Как я могу построить module.so, все еще создавая основную программу с помощью --disable-shared (или с тем же эффектом) в Makefile.am -way?

  • Могу ли я постовать файлы *.la в файлы *.so со специальным правилом automake?
  • Могу ли я настроить процесс lib_LTLIBRARIES для создания файлов *.so в любом случае?

Ответ 1

То, что вы ищете, называется модулем. Вы можете сказать Autotools создать статический двоичный файл (исполняемый файл), добавив -all-static к LDFLAGS приложения. Я думаю, что это предпочтительный способ использования флага настройки --disable-shared (который на самом деле нацелен на библиотеки, а не на исполняемый файл)

Нечто подобное должно сработать:

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

Файл .so (как обычно) .libs/ подкаталоге .libs/ (конечно, если вы его не установите).

И вы можете собрать и свое приложение, и плагины за один раз (даже с одним Makefile.am, поэтому нет необходимости вызывать configure несколько раз.

Использование -fPIC (и друзей) должно быть автоматически определено Autotools.


Обновление: здесь небольшая хитрость, чтобы сделать разделяемые библиотеки доступными там, где вы ожидаете их. Так как все shlibs заканчиваются на .libs/, иногда .libs/ иметь их в не скрытом каталоге.

Следующий фрагмент make файла создает вспомогательные ссылки (на платформах, которые поддерживают символические ссылки; в противном случае они копируются). Простого добавления фрагмента в ваш make файл (я обычно использую -include convenience-link.mk) должно быть достаточно (вам может понадобиться AC_PROG_LN_S в вашем файле 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

Ответ 2

Одна вещь, которая может работать в соответствии с документацией libtool для LT_INIT, состоит в том, чтобы разбить вашу сборку на два пакета: основное приложение и плагины. Таким образом, вы могли бы (теоретически) вызвать:

./configure --enable-shared=plugins

и все будет работать так, как вы ожидали.

Ответ 3

Я решил похожую проблему с помощью макроса noinst_LTLIBRARIES.

Макрос noinst_LTLIBRARIES создает статические, не устанавливаемые библиотеки, предназначенные только для внутреннего использования. все статические библиотеки noinst_LTLIBRARIES создаются также, если вы укажете параметр конфигурации --disable-static.

lib_LTLIBRARIES = libtokenclient.la
noinst_LTLIBRARIES = libtokenclient_static.la 

libtokenclient_la_SOURCES = $(TOKEN_SERVER_CLIENT_SOURCES) cDynlib.c cDynlib.h token_mod.h
libtokenclient_la_CFLAGS = @[email protected]
libtokenclient_la_CXXFLAGS = $(libtokenclient_la_CFLAGS)
libtokenclient_la_LIBADD = @[email protected]
libtokenclient_la_LDFLAGS = @[email protected] @[email protected] $(TOKEN_SERVER_CLIENT_EXPORT_SYMBOLS)

libtokenclient_static_la_SOURCES = $(libtokenclient_la_SOURCES)
libtokenclient_static_la_CFLAGS = $(libtokenclient_la_CFLAGS)
libtokenclient_static_la_CXXFLAGS = $(libtokenclient_static_la_CFLAGS)

token_test_SOURCES = $(TEST_SOURCES)
token_test_LDADD = @[email protected] libtokenclient_static.la
token_test_CFLAGS = @[email protected]
token_test_CXXFLAGS = $(token_test_CFLAGS)

Я использую статические библиотеки noinst_LTLIBRARIES по двум причинам:

  1. чтобы ускорить время компиляции, я создаю статические библиотеки для использования в качестве промежуточных контейнеров для кода, который должен быть связан более одного раза: код компилируется только один раз, в противном случае automake скомпилирует одни и те же исходные файлы один раз для каждой цели
  2. статически связать код с некоторым исполняемым файлом