использование внешней переменной в C ++ в разделяемой библиотеке - создание разделяемой библиотеки (dll) с использованием MinGW g ++ - PullRequest
2 голосов
/ 10 сентября 2010

Я пытаюсь создать общую библиотеку в Windows. Я могу создать эту общую библиотеку в Linux, но в Windows я получаю ошибки компоновщика. Я использую MinGW G ++ 4.5 компилятор. Сначала я предоставлю исходный код примера в Linux, а затем представлю файл, который я пытался изменить в Windows.

/home/nxd/Progs/C++/shared-lib>cat lib_interface.h 

#ifndef LIBINTERFACE_H
#define LIBINTERFACE_H

int func(int a);

#endif /* LIBINTERFACE_H */
/home/nxd/Progs/C++/shared-lib>cat sh_lib.cpp 
extern int b;

int func(int a)
{
 return a+b;
}
/home/nxd/Progs/C++/shared-lib>cat main.cpp 
#include <iostream>
#include "lib_interface.h"

int b;

int main()
{
 b=10;
 std::cout << func(20) << std::endl;
}

/home/nxd/Progs/C++/shared-lib>cat Makefile 
OBJS = main.o sh_lib.o

test: main.o libshared.so
 g++ -L. -o$@ main.o -lshared

main.o: main.cpp lib_interface.h
 g++ -c -Wall -fPIC $<

sh_lib.o: sh_lib.cpp lib_interface.h
 g++ -c -Wall -fPIC $<

libshared.so: sh_lib.o
 ld -shared -soname=libshared.so -o libshared.so.1 $<
 ln -s libshared.so.1 libshared.so

.PHONY: clean

clean:
 rm *.o *.so *.so.1
/home/nxd/Progs/C++/shared-lib>make
g++ -c -Wall -fPIC main.cpp
g++ -c -Wall -fPIC sh_lib.cpp
ld -shared -soname=libshared.so -o libshared.so.1 sh_lib.o
ln -s libshared.so.1 libshared.so
g++ -L. -otest main.o -lshared
/home/nxd/Progs/C++/shared-lib>LD_LIBRARY_PATH=. ./test
30

Я пытался создать общую библиотеку из sh_lib.cpp, используя MinGW g ++ в Windows. Причина, по которой так много комментариев, заключается в том, что я попробовал много вещей, прежде чем я решил опубликовать это.

/home/nxd>cat sh_lib.cpp 
//extern "C" __declspec(dllimport) int b;
//#ifdef __cplusplus 
//extern "C" { 
//#endif 

__declspec(dllimport) extern int b;
//__declspec(dllimport) int b;
//extern int b;

//#ifdef __cplusplus 
//} 
//#endif 

int func(int a)
{
 return a+b;
}

Вот соответствующая часть Makefile с различными настройками. Параметры, переданные компоновщику, который вы видите ниже, были добавлены по одной, чтобы попытаться избавиться от ошибки ссылки. Команда ld ниже была просто для того, чтобы убедиться, что компоновщик действительно получает параметры. Предыдущий дефис указывает программе make выполнить следующую команду, даже если текущая содержит ошибки.

sh_lib.o: sh_lib.cpp lib_interface.h
 g++ -c -Wall -fPIC $<

libshared.so: sh_lib.o
 -ld -shared --enable-auto-import --unresolved-symbols=ignore-in-shared-libs   -soname=libshared.so --allow-shlib-undefined -o libshared.so.1 $<
 g++ -shared  -Wl,--unresolved-symbols=ignore-in-shared-libs  -Wl,--enable-auto-import -Wl,--allow-shlib-undefined -Wl,-soname,libshared.so -o libshared.so.1 $<

Мой вопрос: как я могу скомпилировать sh_lib.cpp в dll, используя переменную extern, как это работает в linux ?. Я прочитал статью stackoverflow: Невозможно получить доступ к переменной в C ++ DLL из приложения C , но "я думаю" между этими двумя случаями есть небольшая разница. Там он пытается связать файл, здесь я пытаюсь создать общую библиотеку, используя переменную, для которой не было выделено хранилище (extern), и я хочу сказать компоновщику игнорировать хранилище этой переменной при создании библиотеки. - это будет решено, когда я связываюсь с exe. В настоящее время я решаю эту проблему с помощью статического связывания.

Большое спасибо за вашу помощь заранее.

Ответы [ 2 ]

2 голосов
/ 12 сентября 2010

Я предоставил свой ответ по электронной почте (поскольку первоначальный постер повторил свой вопрос по электронной почте в список, за которым я следую) в комплекте с измененным исходным кодом, который работает так, как он хотел. См. http://mingw -users.1079350.n2.nabble.com / using-an-external-variable-in-C-in-a-shared-library-tp5521039p5521149.html . Я не буду повторять все это здесь. Просто некоторые ключевые моменты:

  • declspec (dllimport / dllexport) требуется для переменных, да
  • чтобы импортировать переменную из .exe, вам нужно рассматривать exe как dll в том смысле, что вы генерируете библиотеку импорта для нее, чтобы связать общую библиотеку с
  • но на самом деле вы не хотите импортировать переменные из exe, так как это означает, что только exe с таким именем может использовать общую библиотеку, о которой идет речь
  • Вместо этого измените дизайн программного обеспечения, чтобы не иметь переменных в границах API. Просто используйте API в библиотеке, чтобы функция «регистрировала» данные в основном (или там, где это необходимо) последующем обращении к библиотеке вместо
  • и на самом деле, просто для справки, не используйте переменные в API библиотек, чистый API, основанный на функциях, намного лучше
  • обратите внимание, что в оригинальном постере используется MinGW, поэтому не беспокойтесь о комментариях, если у вас есть опыт работы только с MSVC. Они могут отличаться в некоторых ключевых аспектах здесь
  • наконец, я на самом деле не парень C ++, поэтому я говорю из чисто C-аспекта выше, извините. Классы C ++ и т. Д. Определенно усложнят ситуацию и вызовут еще более раздражающие различия между gcc в Linux / gcc в Windows (MinGW) / MSVC / и другими
0 голосов
/ 10 сентября 2010

вы не говорите, какие ошибки вы получаете, но я вижу по крайней мере две вещи в источнике, которые могут вызвать хаос:

  • __ declspec (dllimport) int b: с этим оператором вы говорите, что b нужно импортировать (из библиотеки импорта для библиотеки DLL), но это не сработает, так как вы хотите использовать «b» из вашего exe.(редактирование начинается здесь) Сначала я думал, что 'extern int b' сделает это, но это также не сработает: компоновщик должен знать, где находится b, чтобы иметь возможность создавать dll, именно такработает на Windows (насколько я понимаю, пожалуйста, кто-нибудь поправьте меня, если я ошибаюсь).Сказать 'extern int' компилятору - все равно, что сказать 'эй, где-то есть int, но его нет в этом модуле компиляции, не беспокойтесь, компоновщик это выяснит'.И есть проблема: компоновщик не находит его.Я не вижу другого варианта, кроме как переписать a, чтобы принять b в качестве аргумента, или избавиться от 'extern', чтобы 'b' было в dll.

  • int func (inta): имеет в основном ту же проблему, она должна быть экспортирована из dll и импортирована в основной исполняемый файл;

пример заголовка:

#ifdef BUILD_DLL
  #define MYDLL __declspec( dllexport )
#else
  #define MYDLL __declspec( dllimport )
#endif

MYDLL int func( int a );

При построенииdll, вы определяете BUILD_DLL (передайте -DBUILD_DLL в gcc) и попросите компоновщика создать библиотеку импорта (передача -Wl, - out-implib, libmylib.a).

При сборке исполняемого файла ничего не определяйтеи макрос преобразуется в dllimport, так что компоновщик знает, что он должен найти func где-то еще, а именно в библиотеке импорта для dll (передача -lmylib и, в конечном итоге, -L / path / to / dir / where / lib / is)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...