Видимость, общие переменные 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+) вы даже можете использовать объектно-ориентированное программирование, поэтому глобальные переменные больше не нужны.

Другие вопросы по тегам