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

发布于 2024-09-18 06:17:51 字数 2606 浏览 6 评论 0原文

我正在尝试在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

追风人 2024-09-25 06:17:51

我在电子邮件中提供了我的答案(因为原始发帖人在电子邮件中向我关注的列表重复了他的问题),并附有按他想要的方式工作的修改后的示例源。请参阅 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++ 类等肯定会让情况变得更加复杂,并导致 Linux 上的 gcc / Windows 上的 gcc (MinGW) / MSVC / 和其他人之间更令人讨厌的差异

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/dllexport) is required for variables, yes
  • to import a variable from the .exe, you need to treat the exe as a dll in the sense that you generate an import library for it to link the shared library with
  • but actually, you don't want to import variables from the exe as that means only an exe with that name can use the shared library in question
  • instead, redesign the software to not have variables in the API boundaries. Just have the an API in the library a function to "register" data in the main (or wherever) needed by subsequent calls to the library instead
  • and actually, just as an advice, don't use variables in the API of libraries either, a pure function-based API is much nicer
  • note that the original poster uses MinGW, so don't bother commenting if you have experience only of MSVC. They might well differ in some key aspects here
  • finally, I am not really a C++ guy, so I talk from a pure C aspect above, sorry. C++ classes etc will definitely make the situation more complex, and cause even more annoying differences between gcc on Linux / gcc on Windows (MinGW) / MSVC / and others
欢你一世 2024-09-25 06:17:51

你没有说你遇到了什么错误,但我在源代码中看到至少有两件事可能会造成严重破坏:

  • __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 导出并导入到主可执行文件中;

示例头:

#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/哪里/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:

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

MYDLL int func( int a );

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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文