在 C++ 中使用外部变量在共享库中 - 使用 MinGW g++ 创建共享库 (dll)
我正在尝试在 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 文章: 无法从 C 应用程序访问 C++ DLL 中的变量 ,但是“我认为”这两种情况之间存在细微的差别。在那里他试图链接一个文件,在这里我试图创建一个共享库,使用一个尚未分配存储空间的变量(外部),我想告诉链接器在创建库时忽略这个变量的存储- 当我与 exe 链接时它将得到解决。我目前正在通过静态链接来解决这个问题。
非常感谢您提前的帮助。
I am trying to create a shared library on Windows. I am able to create this shared library on linux but on windows I get linker errors. I am using the MinGW G++ 4.5 compiler. I will first present the source code to the example on linux , and then present the file which I tried to change on 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 lt;
sh_lib.o: sh_lib.cpp lib_interface.h
g++ -c -Wall -fPIC lt;
libshared.so: sh_lib.o
ld -shared -soname=libshared.so -o libshared.so.1 lt;
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
I tried to make a shared library out of sh_lib.cpp using MinGW g++ on Windows. The reason there are so many comments is because of the many things I tried before I decided to post this.
/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;
}
Here is the relevant portion of the Makefile with various tweaks. The options passed to the linker that you see below were added one by one to try to get rid of the link error. The ld command below was just to be sure that the linker was indeed getting the options. The preceding hyphen tells make to run the next command even if the current one had errors.
sh_lib.o: sh_lib.cpp lib_interface.h
g++ -c -Wall -fPIC lt;
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 lt;
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 lt;
My Question: how can I compile sh_lib.cpp into a dll using the extern variable like the way it works in linux?. I did read the stackoverflow article :
Can't access variable in C++ DLL from a C app , but "I think" there is a subtle difference here between the 2 cases. There he was trying to link with a file, here I am trying to create a shared library, using a variable for which storage has not been allocated (extern), and I want to tell the linker to ignore this variable's storage when creating the library - it will be resolved when I am linking with an exe. I am currently managing this problem with static linking.
Many thanks for your help in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我在电子邮件中提供了我的答案(因为原始发帖人在电子邮件中向我关注的列表重复了他的问题),并附有按他想要的方式工作的修改后的示例源。请参阅 http://mingw-users.1079350.n2.nabble.com/using-an-external-variable-in-C-in-a-shared-library-tp5521039p5521149.html 。我不想在这里重复整个事情。只是一些关键点:
I provided my answer in email (because the original poster repeated his question in email to a list I follow) complete with modified sample source that works as he wanted. See http://mingw-users.1079350.n2.nabble.com/using-an-external-variable-in-C-in-a-shared-library-tp5521039p5521149.html . I won't bother repeating the whole thing here. Just some key points:
你没有说你遇到了什么错误,但我在源代码中看到至少有两件事可能会造成严重破坏:
__declspec(dllimport) int b: 使用这个语句,你是说 b 必须是导入(从 dll 的导入库)库,但这不起作用,因为您想使用 exe 中的“b”。 (编辑从这里开始)起初我以为'extern int b'可以做到这一点,但这也行不通:链接器需要知道b在哪里才能创建dll,这就是这样的适用于Windows(据我了解,如果我错了,请有人纠正我)。对编译器说“extern int”就像说“嘿,某个地方有一个 int,但它不在这个编译单元中,不用担心链接器会弄清楚”。问题是:链接器找不到它。除了重写 a 以将 b 作为参数,或者删除“extern”以使“b”位于 dll 中之外,我没有其他选择。
int func(int a):有基本相同的问题,这必须从 dll 导出并导入到主可执行文件中;
示例头:
构建 dll 时,定义 BUILD_DLL(将 -DBUILD_DLL 传递给 gcc)并让链接器创建导入库(传递 -Wl,--out-implib,libmylib.a)。
构建可执行文件时,不定义任何额外的内容,并且宏解析为 dllimport,因此链接器知道它必须在其他地方找到 func,即在 dll 的导入库中(传递 -lmylib,最终 -L/path/to/dir/哪里/lib/是)
you don't say what error(s) you are getting, but I see at least two things in the source that may cause havoc:
__declspec(dllimport) int b: with this statement, you are saying b has to be imported (from an import library for a dll) library, but that will not work since you want to use the 'b' from your exe. (edit starts here) At first I thought 'extern int b' would do it, but that won't work as well: the linker needs to know where b is in order to be able to create the dll, that is just how this works on Windows (to my understanding, please someone correct me if I'm wrong). Saying 'extern int' to the compiler is like saying 'hey there's an int somewhere but it's not in this compilation unit, don't worry the linker will figure it out'. And there's the problem: the linker does not find it. I see no other option than to rewrite a to take b as an argument, or get rid of the 'extern' so that 'b' is in the dll.
int func(int a): has basically the same problem, this must be exported from the dll and imported into the main executable;
example header:
When building the dll, you define BUILD_DLL (pass -DBUILD_DLL to gcc) and have the linker create an import library (pass -Wl,--out-implib,libmylib.a).
When building the executable, define nothing extra and the macro resolves to dllimport so the linker knows it has to find func somewhere else, namely in the import library for the dll (pass -lmylib, and eventually -L/path/to/dir/where/lib/is)