Запрошенное объяснение: libtool, automake, разделяемые библиотеки (и Fortran)

#shared-libraries #automake #libtool

#разделяемые библиотеки #automake #libtool

Вопрос:

Проблема, с которой я столкнулся, решена. Я публикую это, чтобы получить объяснение того, почему решение действительно работает. Я уже получал здесь отличные отзывы.

У меня есть устаревшая кодовая база, в которой использовалась очень упрощенная система сборки, и мой проект заключается в переносе ее на Autotools для настройки и, в частности, создания разделяемых библиотек. Основная библиотека написана на C, но также должна быть подключена к Fortran (для устаревших целей) и распространяется с некоторыми тестовыми кодами в F77. Авторы разбили исходный код на модули…

 src_module1/
src_module2/
...
testc/
testf77/
  

Они создали библиотеку lib/libmain.a путем компиляции кода в каталогах src_ * / и архивирования объектов с помощью ranlib.

Мой первый подход состоял в том, чтобы создать разделяемую библиотеку из каждого src_ * / отдельно и «связать» все это в одну разделяемую библиотеку. Используя Autotools, src_module1/Makefile.am будет содержать

 noinst_LTLIBRARIES = libmodule1.la
libmodule1_la_SOURCES = ...
  

и так далее для других модулей, и, наконец, lib/Makefile.am потребуется только:

 lib_LTLIBRARIES = libmain.la
libmain_la_SOURCES =
libmain_la_LIBADD = $(top_srcdir)/src_module1/libmodule1.la ...
  

Казалось, что это работает отлично. Однако, когда код в testc / был скомпилирован и связан с libmain.la была выдана ошибка «символы не найдены».

Думая, что это проблема с libtool или разделяемыми библиотеками, я попытался создать только static, в основном изменив all .la на .a и all _LTLIBRARIES на _LIBRARIES . Та же проблема. Однако на этот раз при попытке связать сам libmain.a замечаю ошибку «ranlib: предупреждение для библиотеки: libmain.a оглавление пустое (никакие элементы объектного файла в библиотеке не определяют глобальные символы)».

Решение, которое я нашел, похоже на взлом. Я не создавал Makefile-ы ни для одного из каталогов src_*/, а вместо этого использовал только для каталога lib/ и его Makefile.у меня были строки:

 lib_LTLIBRARIES = libmain.la
libmain_la_SOURCES = [all sources from all ../src_modules/ ]
  

Это сработало. Скомпилированные программы в testc / связаны с libmain.la без проблем. Один из «модулей» представляет собой набор привязок Fortran, которые переносят другие функции C в библиотеку. Даже коды Fortran в testf77 / связаны с libmain.исправлено должным образом.

Не мог бы кто-нибудь подробно объяснить, что происходит, когда libtool создает разделяемую библиотеку? Или даже при создании статической библиотеки? Почему несколько статических библиотек не могут быть связаны вместе, чтобы создать одну статическую библиотеку? Почему символы доступны только тогда, когда libtool / ranlib создает библиотеку «из исходных текстов»? А как насчет установки разделяемой / статической библиотеки, т. Е. перемещения ее в /usr/local/lib — что там происходит? Статья Википедии о статических и разделяемых библиотеках на самом деле недостаточно подробная для меня.

Я ценю все усилия, направленные на то, чтобы разобраться в моем длинном вопросе.

Ответ №1:

То, что вы попробовали в первый раз, должно сработать. Я постоянно использую такого рода настройки (в контексте C ). Это также задокументировано и является частью набора тестов Automake (хотя, возможно, не с Fortran).

Библиотека libtool, которая не подлежит установке, то есть объявлена с помощью noinst_LTLIBRARIES , называется удобной библиотекой libtool. Это noinst_ имеет большое значение для того, что создается. Даже если Libtool настроен для создания разделяемых библиотек, удобная библиотека libtool на самом деле не является разделяемой библиотекой: это просто набор объектных файлов (скомпилированных в виде PIC, чтобы их можно было использовать в разделяемой библиотеке), хранящихся в архиве. Вы можете использовать библиотеку libtool convenience library везде, где использование этого набора объектов имело бы смысл, например, для создания разделяемой библиотеки.

Когда несколько удобных библиотек libtool добавляются к устанавливаемой библиотеке libtool (такой как ваша libmain.la ), Libtool должен распаковать архивы, содержащие объекты каждой удобной библиотеки, и связать их с конечной библиотекой.

Здесь стоит отметить ловушку: при создании разделяемой библиотеки из удобных библиотек, если _SOURCES переменная пуста, Automake не знает, какой компоновщик использовать, и по умолчанию использует компоновщик C. Если вы хотите обмануть Automake, заставив его использовать правило связывания для некоторого определенного языка, вы можете объявить nodist_EXTRA_..._SOURCES исходный файл, который не обязательно должен существовать. (Пример см. в разделе «Libtool Convenience Libraries» руководства по Automake.)

Возможно, это была ваша проблема? Если у вас есть какие-либо файлы Fortran в исходных текстах некоторых ваших модулей (согласно вашему описанию, это только файлы C), компоновщик Fortran будет использоваться для сборки libmain.la только в том случае, если файл Fortran присутствует в исходных файлах, объявленных для этой библиотеки libtool. И компоновщик C будет использоваться, когда libmain_la_SOURCES он пуст.

В противном случае я понятия не имею, почему это не сработало.

В вашем примере есть небольшая ошибка:

 libmain_la_LIBADD = $(top_srcdir)/src_module1/libmodule1.la
  

должно быть

 libmain_la_LIBADD = $(top_builddir)/src_module1/libmodule1.la
  

поскольку библиотека создана не в исходном каталоге. Однако я предполагаю, что это просто опечатка, и вы не увидите разницы, если не выполните сборку или запуск VPATH make distcheck .


Ожидается, что ваша вторая попытка использования _LIBRARIES без Libtool не сработает.
_LIBRARIES может использоваться только для объявления статических архивов, и в этом случае _LIBADD может содержать только объектные файлы, а не другие статические архивы. Распаковку архива для повторного использования его объектов в другой архив может быть сложно выполнить переносимо. Ответ Automake на эту проблему всегда был таким: установите Libtool и используйте _LTLIBRARIES (Libtool можно настроить для создания только статических библиотек).

Комментарии:

1. Я вернулся и скорректировал, libmain_la_LIBADD чтобы отразить top_builddir , как вы предложили. (К счастью, я только прокомментировал все исходные настройки на Makefile.am s.) Из всех вещей, на этот раз это сработало! Я прочитал раздел об удобных библиотеках в документации Automake, что и привело меня к этой идее. Ваш ответ очень ясен, и я принимаю его. Я чувствую, что у меня получается работать с Autotools. Каждая новая вещь, которую я узнаю, приходит с несколькими часами, потраченными на эксперименты и поиск документации.