Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.82/11: Рейтинг темы: голосов - 11, средняя оценка - 4.82
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 486
1

Создание глобальной переменной в динамической библиотеке

04.12.2021, 07:13. Показов 2264. Ответов 15

Author24 — интернет-сервис помощи студентам
Доброе утро,

В своей динамической библиотеке мне необходимо хранить значение переменной (у которой тип определен в сторонней библиотеке) и по запросу передавать это значение в другие библиотеки (то есть моя библиотека будет зависимостью нескольких библиотек при работе моего приложения), при чем всем библиотекам должно приходить одно и то же значение. Также сторонние библиотеки должны иметь возможность задавать значение этой переменной (например через set функции)

Поискал в интернете, не до конца понял, вроде мне необходимо сделать следующее:
my.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
#ifndef MY_H
#define MY_H
 
class OGRSpatialReference 
 
extern OGRSpatialReference SpatialReference;
 
#include "my_export.h"
 
MY_EXPORT void setSpatialReference(OGRSpatialReference sr);
 
#endif
my.cpp
C++
1
2
3
4
5
6
7
8
#include "my.h"
 
#include <gdal/gdal.h>
#include <gdal/gdal_priv.h>
 
void setSpatialReference(OGRSpatialReference sr){
  SpatialReference = sr;
}
Тогда при компиляции я получаю ошибку:

relocation R_X86_64_PC32 against undefined symbol `_ZN5h5geo2sr12_GLOBAL__N_116SpatialReferenceE' can not be used when making a shared object; recompile with -fPIC


Правильно ли я понимаю что сторонняя библиотека, где определен тип OGRSpatialReference (GDAL библиотека) скомпилирована как статическая?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
04.12.2021, 07:13
Ответы с готовыми решениями:

Ошибка при обращении к динамической глобальной переменной
использую в файле Unit1(Form1) 2 переменные, которые обьявляю как глобальные в начале файла:...

Создание класса в динамической библиотеке
Доброго времени суток! Прочел статью в на cyberguru: как написать динамическую библиотеку, и решил...

Создание глобальной переменной по ходу работы программы
И так, мне нужно создать глобальную переменную в ходе исполнения программы. На самом деле всё чуть...

Создание глобальной переменной
Использую code igniter. Как создать переменную? Такую же как например base_url();

Создание глобальной переменной
Добрый день! Помогите, пожалуйста, с такой ситуацией: Есть записанный макрос в определенном...

15
фрилансер
5498 / 5094 / 1047
Регистрация: 11.10.2019
Сообщений: 13,338
04.12.2021, 07:38 2
Kerim_Geophysic, определения переменной то нету

my.cpp
C++
1
2
#include "my.h"
OGRSpatialReference SpatialReference{};
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 486
04.12.2021, 16:36  [ТС] 3
Спасибо, не заметил

На самом деле у меня как-то странно работает эта глобальная переменная. То есть какие то функции работают, а какие то нет.
У меня также определены несколько других функций:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
OGRSpatialReference SpatialReference {};
 
void setSpatialReference(OGRSpatialReference sr){
  SpatialReference = sr;
}
 
void setSpatialReferenceFromUserInput(
    const std::string& authName, const std::string& code){
  SpatialReference.SetFromUserInput((authName + ":" + code).c_str());
}
 
OGRSpatialReference& getSpatialReference(){
  return SpatialReference;
}
 
void setLengthUnits(const std::string& units){
  double coef = units::convert(
      units::unit_from_string(units),
      units::unit_from_string("meter"));
  SpatialReference.SetLinearUnitsAndUpdateParameters(units.c_str(), coef);
}
 
std::string getLengthUnits(){
  const char *units = nullptr;
  SpatialReference.GetLinearUnits(&units);
  return std::string(units);
}
 
std::string getAuthorityName(){
  char *name = nullptr;
  return std::string(SpatialReference.GetAuthorityName(name));
}
 
std::string getAuthorityCode(){
  char *code = nullptr;
  return std::string(SpatialReference.GetAuthorityCode(code));
}
При работе своего приложения я выставляю следующие значения:
C++
1
2
setSpatialReferenceFromUserInput("EPSG","32056");
setLengthUnits("m");
а затем пытаюсь вернуть эти значения:
C++
1
2
std::cout << getLengthUnits() << std::endl; // возвращает "м"
std::cout << getAuthorityName() << std::endl; // выбрасывает исключение: basic_string::_M_construct null not valid
То есть единицы измерения длины сохраняются, а наименование координатной системы вернуть не получается.
При этом если я запускаю тест этой библиотеки, где я проделываю все тоже самое, все работает нормально (а в приложении как было сказано выбрасывает исключение).

В чем может быть причина такого поведения?
0
фрилансер
5498 / 5094 / 1047
Регистрация: 11.10.2019
Сообщений: 13,338
04.12.2021, 17:01 4
Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
std::string getAuthorityName(){
  char *name = nullptr;
  return std::string(SpatialReference.GetAuthorityName(name));
}
почему туда передаётся нулевой указатель? Что в этой функции делается ?
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 486
04.12.2021, 17:25  [ТС] 5
Алексей1153,
Цитата Сообщение от Алексей1153 Посмотреть сообщение
почему туда передаётся нулевой указатель?
по ссылке описание этой функции
Я это так понимаю: pszTargetKey используется для ускорения поиска AuthorityName, и если не знаешь какой pszTargetKey использовать, то используешь nullptr (в гугл тестах пробовал работает).

Детально я описать не могу что происходит внутри этой функции, но в целом работа с данным классом происходит примерно так:
есть база данных с описанием пространственных координатных систем (их названия, размеры эллипсоида, и другие параметры необходимые для математического описания каждой координатной системы). Когда я создаю объект типа OGRSpatialReference и выставляю необходимую координатную систему (в данном случае с помощью функции SetFromUserInput) то библиотека делает запрос в базу данных и если такая координатная система существует то функция SetFromUserInput возвращает какое то значение типа INT (грубо говоря если все нормально то 0, если ошибка то -1 например).
Затем я могу выставить единицы измерения длины (футы/метры и тд).
С помощью других классов я уже могу производить пересчет координат из одной системы в другую на основании этих объектов OGRSpatialReference .

Кстати в этом же файле написано что при создании экземпляра этого класса используется счетчик ссылок на объект

И здесь тоже описание есть
0
6105 / 3460 / 1405
Регистрация: 07.02.2019
Сообщений: 8,791
04.12.2021, 18:04 6
Kerim_Geophysic, этот метод может вернуть nullptr (что в вашем случае происходит). Вы не можете передавать в конструктор std::string nullptr. Проверяйте результат и, если он nullptr, возвращайте дефолтную строку.
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 486
04.12.2021, 18:41  [ТС] 7
zayats80888, спасибо за ответ,

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

Представьте я работаю с координатной системой OGRSpatialReference SpatialReference. Я могу определить координатную систему с помощью AuthorityName и Code например так:
C++
1
2
3
4
OGRSpatialReference SpatialReference;
std::string authName = "EPSG";
std::string code = "32056";
SpatialReference.SetFromUserInput((authName + ":" + code).c_str());
Затем я могу вернуть эти значения:
C++
1
2
char *pszTargetKey= nullptr;
std::string authName = SpatialReference.GetAuthorityName(pszTargetKey);
и если SpatialReference это локальная переменная, то никаких проблем нет, все возвращается. Но если эта переменная глобальная и я проделываю все то же самое но уже в своем приложении то я получаю указанную выше ошибку. При этом в тесте даже с глобальной переменной SpatialReference следующий код работает:
C++
1
2
setSpatialReferenceFromUserInput("EPSG","32056");
std::cout << getAuthorityName() << std::endl;
а в приложении выскакивает ошибка.

НО с юнитами все работает нормально в обоих случаях:
C++
1
2
setLengthUnits("mm");
std::cout << getLengthUnits() << std::endl; // mm
0
фрилансер
5498 / 5094 / 1047
Регистрация: 11.10.2019
Сообщений: 13,338
04.12.2021, 19:11 8
Kerim_Geophysic, тут не нужно гадать. Правильно будет примерно так:

C++
1
2
3
4
5
std::string getAuthorityName()
{
  if( auto* p=SpatialReference.GetAuthorityName({}) )return p;
  return {};
}
1
6105 / 3460 / 1405
Регистрация: 07.02.2019
Сообщений: 8,791
04.12.2021, 19:27 9
Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
а в приложении выскакивает ошибка
Трудно понять, что там у вас. Взять хотя бы объявление этого объекта: зачем оно сделано, если этот объект не экспортируется? Где находятся ваши функции и откуда вызываются. Поясните вкратце архитектуру вашего приложения.
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 486
04.12.2021, 20:01  [ТС] 10
Алексей1153,
Цитата Сообщение от Алексей1153 Посмотреть сообщение
тут не нужно гадать. Правильно будет примерно так:
это я исправлю, спасибо

zayats80888, это Qt десктопное приложение.

Цитата Сообщение от zayats80888 Посмотреть сообщение
Трудно понять, что там у вас. Взять хотя бы объявление этого объекта: зачем оно сделано, если этот объект не экспортируется? Где находятся ваши функции и откуда вызываются. Поясните вкратце архитектуру вашего приложения.
Объявлять или не объявлять переменную через extern я не знаю надо ли. Цель просто хранить значение SpatialReference так чтобы при вызове сеттеров/геттеров SpatialReference устанавливался/выдавал одинаковые значения для всех функций всех загруженных библиотек/приложения которые вызывают эти сеттеры/геттеры.

Само приложение это Qt десктопное приложение. Построено на множестве динамических библиотек.
Юзер через графический интерфейс выбирает authName и code которые через одну динамическую библиотеку устанавливают соответствующие значения в SpatialReference и для проверки я пытаюсь сразу вывести эти значения:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void ProjectionSettingsPanel::onCRSChanged(
    const QString& name,
    const QString& authName,
    const QString& code)
{
  Q_D(ProjectionSettingsPanel);
  h5geo::sr::setSpatialReferenceFromUserInput(
        authName.toStdString(), code.toStdString());
  h5geo::sr::setLengthUnits(
        d->CRSWidget->getUnitsLineEdit()->text().toStdString());
 
  std::cout << "getLengthUnits: " << h5geo::sr::getLengthUnits() << std::endl;  // выводит правильно
  std::cout << "getAuthorityName: " << h5geo::sr::getAuthorityName() << std::endl;  // выдает исключение (ну или пустую строку)
  std::cout << "getAuthorityCode: " << h5geo::sr::getAuthorityCode() << std::endl;  // выдает исключение (ну или пустую строку)
}
Но в тестах нет такой проблемы. Вообще не понимаю почему.
0
6105 / 3460 / 1405
Регистрация: 07.02.2019
Сообщений: 8,791
04.12.2021, 20:17 11
Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
Объявлять или не объявлять переменную через extern я не знаю надо ли. Цель просто хранить значение SpatialReference так чтобы при вызове сеттеров/геттеров SpatialReference устанавливался/выдавал одинаковые значения для всех функций всех загруженных библиотек/приложения которые вызывают эти сеттеры/геттеры.
Если никто не обращается к этому объекту напрямую, а только через экспортируемый интерфейс библиотеки, то это объявление не нужно, иначе нужно его дополнить атрибутом экспорта/импорта.
В первом случае в cpp файле с определениями функций этой библиотеки просто определите глобальный объект в анонимном неймспэйсе.

Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
Юзер через графический интерфейс выбирает authName и code которые через одну динамическую библиотеку устанавливают соответствующие значения в SpatialReference и для проверки я пытаюсь сразу вывести эти значения:
Вы для начала напишите простое консольное тестовое приложение, линкуйтесь только с этой библиоткой и проверяйте её функционал.
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 486
04.12.2021, 22:44  [ТС] 12
Цитата Сообщение от zayats80888 Посмотреть сообщение
Вы для начала напишите простое консольное тестовое приложение, линкуйтесь только с этой библиоткой и проверяйте её функционал.
Сделал так сейчас, все работает если я линкуюсь к этой библиотеке и ее зависимостям. Пока не пойму что не так
0
6105 / 3460 / 1405
Регистрация: 07.02.2019
Сообщений: 8,791
04.12.2021, 23:01 13
Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
Пока не пойму что не так
Пройдитесь отладчиком. Убедитесь что UI работает корректно и что передаёте правильные параметры в функции. Большинство функций(SetFromUserInput в частности) возвращают коды ошибок, но вы это игнорируете.

Добавлено через 3 минуты
А с библиотекой, а которой OGRSpatialReference, все ваши "модули" линкуются динамически?
И нет ли конкурентных(из разных потоков) вызовов функций вашей библиотеки?
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 486
04.12.2021, 23:23  [ТС] 14
zayats80888, по моему важная деталь вскрылась...
упрощенная схема приложения:

экзекютабл состоит только из main.cxx (назовем exe)
основная динамическая библиотека, содержащая mainwindow.cxx в том числе (назовем exelib)
модуль (динамическая библиотека) зависящий от exelib (назовем его module)
+еще различные загружаемые модули, но они не должны играть роли в данном контексте.

Раньше я пытался установить/вернуть значения authName и code внутри загружаемого модуля module.
А только что я попытался сделать то же самое внутри MainWindow (то есть внутри основного модуля) и все прекрасно работает.
Дальше не выключая приложения я "нажимаю кнопки" чтобы приложение по старому вывело те же самые значения но из модуля module и как обычно он выводит пустоту (или выбрасывает исключение как было до исправлений в коде, что не меняет сути).

Может ли быть такое, что играет роль порядок загрузки модулей? Или может я не подключаю к модулю какую-то зависимость? Модуль компилируется отдельно и exelib линкуется к нему (exelib это зависимость модуля module).

Добавлено через 5 минут
Цитата Сообщение от zayats80888 Посмотреть сообщение
А с библиотекой, а которой OGRSpatialReference, все ваши "модули" линкуются динамически?
По моему я как раз в этом накосячил... сейчас попробую
0
6105 / 3460 / 1405
Регистрация: 07.02.2019
Сообщений: 8,791
05.12.2021, 00:23 15
Не особо понял.
Есть matlab.dll(экспортирует класс OGRSpatialReference),
Есть exelib.dll(вот эта библилотека), линкуется с(зависит от) matlab.dll.
Есть module.dll, линкуется с(зависит от) matlab.dll и exelib.dll.
Есть exe, линкуется с(зависит от) matlab.dll, exelib.dll и module.dll.
Правильно?

Далее, если вызывать функции exelib.dll из exe, то всё норм, а если опосредованно через module.dll, то не норм?

Цитата Сообщение от Kerim_Geophysic Посмотреть сообщение
Может ли быть такое, что играет роль порядок загрузки модулей?
Вроде нет, если dll уже загружена в процесс, она не будет "перезагружаться".
Или вы в рантайме что-ли сами загружаете/выгружаете?
1
2 / 2 / 0
Регистрация: 08.01.2016
Сообщений: 486
05.12.2021, 01:29  [ТС] 16
zayats80888,
Цитата Сообщение от zayats80888 Посмотреть сообщение
Не особо понял.
Есть matlab.dll(экспортирует класс OSGReference),
Есть exelib.dll(вот эта библиотека), линкуется с(зависит от) matlab.dll.
Есть module.dll, линкуется с(зависит от) matlab.dll и exelib.dll.
Есть exe, линкуется с(зависит от) matlab.dll, exelib.dll и module.dll.
Правильно?
Ранее я неправильно/неполно изложил структуру (извиняюсь). Еще раз попробую:

Есть matlab.dll (экспортирует класс OSGReference).
Есть mylib.dll, линкуется с matlab.dll (экспортирует глобальную переменную OGRSpatialReference SpatialReference и сеттеры/геттеры которые мы обсуждали ранее).
Есть exelib.dll(вот эта библиотека где все работает), линкуется с mylib.dll и следовательно с matlab.dll.
Есть module.dll(здесь встречается указанная проблема), линкуется с mylib.dll и следовательно с matlab.dll (модуль встраиваемый, то есть приложение и без него сможет работать).
Есть exe, линкуется только с exelib.dll

Все это дело контролируется через СМАКЕ
Кстати для общего понимания я на Ubuntu 20.04 сейчас

Цитата Сообщение от zayats80888 Посмотреть сообщение
А вы в рантайме что-ли сами загружаете/выгружаете?
Модули загружаются автоматически при запуске приложения, но вроде можно на программном уровне ставить зависимости одного модуля от другого (то есть у каждого модуля есть метод QStringList Dependencies(), то есть возвращает зависимости этого модуля, и может быть это используется при их загрузке). Мое приложение базируется на платформе Slicer 3D

Добавлено через 57 минут
zayats80888, кстати для работы matlab.dll необходима переменная окружения PROJ_LIB указывающая на папку где лежит база данных sqlite с координатными системами.
Эта переменная устанавливается при запуске приложения, но возможно загружаемый модель ее игнорирует?
0
05.12.2021, 01:29
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
05.12.2021, 01:29
Помогаю со студенческими работами здесь

Создание глобальной переменной
Доброго времени суток, форумчане! После ввода пароля в поле стартовой формы Аксесс 2003, при ее...

Создание глобальной переменной
Добрый день, столкнулся с такой проблемой. Создаю чат - бот для вк, чтобы соединить двоих...

Создание массива в качестве глобальной переменной (по аналогии с VB.net)
Здравствуйте, коллеги. Обращаюсь к Вам за помощью. Пытаюсь создать глобальную переменную в...

Различие глобальной и глобальной статической переменной
у нас есть заголовочный файл со стражами, допустим global.h , его используют несколько других...

Создание динамической переменной в android
Такая особенность в случае с windows все работает в SOAP функции возвращается переменная...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru