Как построить модуль *.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 по двум причинам:
- чтобы ускорить время компиляции, я создаю статические библиотеки для использования в качестве промежуточных контейнеров для кода, который должен быть связан более одного раза: код компилируется только один раз, в противном случае automake скомпилирует одни и те же исходные файлы один раз для каждой цели
- статически связать код с некоторым исполняемым файлом