在共享库中使用C ++中的外部变量 - 使用MinGW g ++创建共享库(dll)

时间:2010-09-10 17:32:49

标签: c++ mingw shared

我正在尝试在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

我尝试在Windows上使用MinGW g ++从sh_lib.cpp创建一个共享库。有这么多评论的原因是因为在我决定发布之前我尝试了很多东西。

/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 $<

我的问题:如何使用extern变量将sh_lib.cpp编译成dll,就像它在linux中的工作方式一样?我确实读过stackoverflow文章: Can't access variable in C++ DLL from a C app,但“我认为”这两种情况之间存在细微差别。在那里他试图链接文件,这里我试图创建一个共享库,使用一个尚未分配存储的变量(extern),我想告诉链接器在创建库时忽略这个变量的存储 - 当我与exe链接时,它将被解决。我目前正在使用静态链接来解决这个问题。

非常感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

我在电子邮件中提供了我的答案(因为原始海报在电子邮件中将他的问题重复到我所遵循的列表中),完成了修改后的样本源,可以按照自己的意愿运行。见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也要好得多
  • 请注意,原始海报使用MinGW,所以如果您只有MSVC的经验,请不要打扰评论。他们可能在这里的一些关键方面有所不同
  • 最后,我不是一个真正的C ++人,所以我从上面的纯C方面谈起,抱歉。 C ++类等肯定会使情况变得更复杂,并且在Windows(MinGW)/ MSVC /上的Linux / gcc上的gcc之间引起更加烦人的差异

答案 1 :(得分:0)

你没有说出你得到了什么错误,但我发现源中至少有两件可能造成破坏的事情:

  • __ declspec(dllimport)int b:使用此语句,您说b必须导入(从dll的导入库)库,但由于您要使用'b',这将无效来自你的exe。 (编辑从这里开始)起初我认为'extern int b'会这样做,但那也行不通:链接器需要知道b在哪里才能创建dll,这就是这个适用于Windows(据我所知,如果我错了,请有人纠正我)。对编译器说'extern int'就像是说'嘿,某个地方有一个int,但它不在这个编译单元中,不要担心链接器会弄明白'。而且存在问题:链接器找不到它。除了重写a以将b作为参数,或者除去'extern'以便'b'在dll中之外,我认为没有别的选择。

  • int func(int a):基本上有同样的问题,必须从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) /目录/其中/ LIB /是)