Видимость, общие переменные Fortran, загрузка общих библиотек во время выполнения
Среда: Intel Linux, Red Hat 5. Компилятор: gcc 3.4.6 (старые вещи, устаревшая среда с серьезной инфраструктурой, извините)
У меня есть несколько версий определенной разделяемой библиотеки (назовите ее что-то вроде "shared_lib.so"), полученной из Fortran, которая содержит блок COMMON и различные вычисления со ссылками на переменные в этом COMMON.
Мне нужно иметь возможность (из кода C в другом месте исполняемого файла конечного продукта) использовать dlclose() и dlopen() для переключения между версиями этой библиотеки (в которой все версии содержимого COMMON идентичны) во время работы. В некоторых случаях тот же COMMON также появляется в коде, который является частью статической библиотеки (назовите ее "static_lib.a"), которая также связана с исполняемым файлом и поддерживается отдельно от моего проекта, но которая имеет функциональность, которая взаимодействует с ней в моя общая библиотека
Кажется, я вижу, что несколько экземпляров COMMON оказываются в исполняемом файле и (что более важно), что нет никакой связи между значениями переменных в экземпляре из статической библиотеки и значениями "одинаковых" переменных в экземпляр из разделяемой библиотеки извлекается с помощью dlopen().
В общем, мне нужно (в общем исполняемом файле) для загруженного dlopen() shared_lib.so, чтобы иметь возможность устанавливать / использовать переменную XYZ в COMMON ABC, и для кода в static_lib.a, чтобы устанавливать / использовать XYZ, и пусть это будет один и тот же экземпляр XYZ, или, по крайней мере, для того, чтобы оба были синхронизированы. Это возможно?
Мои команды компиляции для источников в shared_lib.so имеют вид:
g77 –c –g –m32 -fPIC –o shared_src.o shared_src.f
Моя команда для создания shared_lib.so имеет вид:
gcc -g -m32 -fPIC -shared -o shared_lib.so *.o
Моя команда для сборки исполняемого файла имеет вид:
gcc –g -m32 –rdynamic –o exec exec.o static_lib.a shared_lib.so –lm –ldl –lg2c
Мне нужно сделать что-то из кода C в форме:
handle1 = dlopen ("shared_lib.so", RTLD_NOLOAD);
dlclose (handle1);
handle2 = dlopen ("shared_lib2.so", RTLD_NOW | RTLD_GLOBAL);
...
Начальная конфигурация запуска действительно работает правильно относительно необходимых переменных, но результат последующих последовательностей dlclose() и dlopen() - нет. Возможно, основная проблема в том, что dlopen() не хватает некоторого интеллекта, который есть у gcc, когда он связывается.
2 ответа
Короткий ответ
Сделали / можете ли вы перекомпилировать исполняемый файл с -fPIC
? Я обнаружил, что необходимо скомпилировать совместно используемую библиотеку и исполняемый файл с -fPIC
чтобы получить COMMON
блоки должны быть правильно распознаны.
Длинный ответ
Недавно я столкнулся с немного похожей проблемой, связанной с общими блоками между исполняемым файлом и общей библиотекой FORTRAN. Тем не менее, я использую компиляторы Intel НЕ GNU
компиляторы. Исполняемый файл смешан C/C++
а также FORTRAN
,
Существующая (рабочая) версия кода для Windows работает, разделяя общие блоки между исполняемым файлом и DLL через DLLEXPORT
/ DLLIMPORT
ATTRIBUTE директивы. Согласно документации компилятора Intel, эти директивы атрибутов не распознаются в Linux. Действительно, компилятор Linux Intel просто выдает предупреждения для этих директив.
Основные изменения в преобразовании кода из Windows в Linux были заменой Windows LoadLibrary
а также GetProcAddress
с Linux dlopen
а также dlsym
рутины, соответственно, с использованием #ifdef
разделы. Общая библиотека была скомпилирована с использованием -fpic
и связано с -shared
,
В то время как общая библиотека была скомпилирована с -fpic
, исполняемый файл не был. При выполнении кода, скомпилированного таким образом, переменные, переданные в общую библиотеку через вызовы подпрограмм, были переданы правильно, однако COMMON
переменные блока не были установлены правильно (или были неинициализированы).
В отчаянии я наконец попытался скомпилировать сам исполняемый файл с -fpic
вариант компилятора, а затем COMMON
блоки были правильно распознаны в общей библиотеке.
Это не совсем ответ, но может помочь вам.
Вот что говорит стандарт 2008 года COMMON
:
5.7.2.4 Общая ассоциация
1 Внутри программы последовательности хранения общих блоков всех общих блоков ненулевого размера с одним и тем же именем имеют один и тот же первый блок хранения, а последовательности хранения общих блоков всех общих блоков нулевого размера с одним и тем же именем являются хранилищами, связанными с одним другой. Внутри программы последовательности хранения общих блоков всех пустых общих блоков ненулевого размера имеют один и тот же первый блок хранения, а последовательности хранения всех пустых общих блоков нулевого размера связаны друг с другом и с первым блоком хранения любого ненулевого размер пустых общих блоков. Это приводит к объединению объектов в разных областях видимости. Использование или связь с хостом может привести к тому, что эти связанные объекты будут доступны в одном и том же блоке области действия.
Короче, COMMON
разделы с одинаковыми именами в одной программе занимают одно и то же хранилище.
Программа определяется следующим образом.
2.2.2 Программа
1 Программа должна состоять из ровно одной основной программы, любого числа (включая ноль) других видов программных модулей, любого количества (включая ноль) внешних процедур и любого количества (включая ноль) других объектов, определенных с помощью средств, отличных от Fortran., Основная программа должна быть определена программным модулем основной программы Фортрана или другими средствами, кроме Фортрана, но не обоими.
Стандарт ничего не говорит о статических и динамических связях и не ограничивает предыдущие операторы статическими связями. Поэтому, похоже, что динамически загружаемая библиотека должна совместно использовать COMMON
блок с основной программой (что, я не уверен, даже технически возможно) и, следовательно, реализация GNU некорректна.
С другой стороны, стандарт также ничего не говорит о возможности динамической загрузки библиотек. Программные модули, "определяемые другими средствами, кроме Fortran", должны включать библиотеки C, но это не говорит нам, как эти программные модули связаны с основной программой. Фортран, в общем, не очень динамичный язык.
Конечно, вы можете обойти все это, просто не используя COMMON
блоки. Если процедуре необходимо прочитать / записать некоторые данные, просто передайте их как параметр с намерением ввода / вывода. Вы также можете группировать данные в производном типе и передавать их вместе как единое целое. В настоящее время (Fortran 2003+) вы даже можете использовать объектно-ориентированное программирование, поэтому глобальные переменные больше не нужны.