Как собрать модуль *.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 $@  $<

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

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

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

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

person towi    schedule 19.12.2012    source источник


Ответы (3)


То, что вы ищете, называется модулем. Вы можете указать 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/ (конечно, если вы его не установите).

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

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


Обновление: вот небольшая хитрость, позволяющая сделать общие библиотеки доступными там, где вы их ожидаете. Поскольку все шлибы заканчиваются в .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
person umläute    schedule 08.01.2013
comment
Чувак, мне пришлось прыгать через обручи из-за проблем с libtool. Я заменил -all-static в ''application'' на -static-libtool-libs в других моих удобных библиотеках (не в той, которую мы обсуждаем) -- мне пришлось это сделать, потому что dl_blahblah()-штуки приводили к сбою программы, когда я делал -all-static (я совершенно уверен, что это было виновник). В любом случае: увы, я все еще получаю .libs/mm_cpp_logger.so -- что мне кажется немного неудобным при написании тестов для модуля. Загрузка из .libs/ кажется... неправильной. Это нормально, что он всегда попадает туда, независимо от того, что я делаю? - person towi; 24.01.2013
comment
я обновил свой ответ для возможного решения для получения библиотек, доступных за пределами .libs - person umläute; 24.01.2013
comment
@umläute: хорошее решение! К сожалению, чистая часть не работает, так как все файлы, содержащие dlname=(.*), удаляются до запуска части (поэтому grep ничего не возвращает). Я скопировал ваш фрагмент в свой файл Makefile.am. - person Stasik; 04.02.2014

Я решил аналогичную проблему, используя 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 = @BASE_CFLAGS@
libtokenclient_la_CXXFLAGS = $(libtokenclient_la_CFLAGS)
libtokenclient_la_LIBADD = @B_BASE_OS_LIBS@
libtokenclient_la_LDFLAGS = @LT_PLUGIN_LIBS_FLAGS@ @LIBS_FLAGS@ $(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 = @B_BASE_OS_LIBS@ libtokenclient_static.la
token_test_CFLAGS = @BASE_CFLAGS@
token_test_CXXFLAGS = $(token_test_CFLAGS)

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

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

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

./configure --enable-shared=plugins

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

person ldav1s    schedule 19.12.2012
comment
Ваш ответ дал мне хорошие ключевые слова для Google, и я нашел руководство . Увы, это также предполагает, что я строю все с помощью --enable-shared. Однако есть пара хороших советов. Но в документе, на который вы указали, не упоминаются плагины. В упаковке? Это означает суб-configure.in, верно? Да, это может сработать. Каталог с модулем получит свой configure.in, наверное? - person towi; 20.12.2012
comment
Да, точно. Под плагином я подразумеваю динамически загружаемое расширение. Они (основное приложение и расширения) получат какую-то дополнительную настройку для их настройки. Возможно, вы могли бы просто обойтись только одной дополнительной настройкой для расширений. - person ldav1s; 21.12.2012