Linux 在进程和 DLL 之间共享全局/静态变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4911994/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sharing a global/static variable between a process and DLL
提问by minjang
I'd like to share a static/global variable only between a process and a dll that is invoked by the process. The exe and dll are in the same memory address space. I don't want the variable to be shared among other processes.
我只想在进程和进程调用的 dll 之间共享一个静态/全局变量。exe 和 dll 位于相同的内存地址空间中。我不希望变量在其他进程之间共享。
Elaboration of the problem:
问题细化:
Say that there is a static/global variable x
in a.cpp
. Both the exe foo.exe
and the dll bar.dll
have a.cpp
, so the variable x
is in both images.
说是有一个静态/全局变量x
在a.cpp
。exefoo.exe
和 dllbar.dll
都有a.cpp
,所以变量x
在两个图像中。
Now, foo.exe
dynamically loads (or statically) bar.dll
. Then, the problem is whether the variable x
is shared by the exe and dll, or not.
现在,foo.exe
动态加载(或静态)bar.dll
。那么,问题是该变量x
是否被exe和dll共享。
In Windows, these two guys nevershare the x
: the exe and dll will have a separate copy of x
. However, in Linux, the exe and dll do share the variable x
.
在 Windows 中,这两个家伙从不共享x
:exe 和 dll 将具有单独的x
. 但是,在 Linux 中,exe 和 dll 共享变量x
.
Unfortunately, I want the behavior of Linux. I first considered using pragma data_seg
on Windows. However, even if I correctly setup the shared data segment, foo.exe
and bar.dll
never shares the x
. Recall that bar.dll
is loaded into the address space of foo.exe
. However, if I run another instance of foo.exe
, then x
is shared. But, I don't want x
to be shared by different processes. So, using data_seg
was failed.
不幸的是,我想要 Linux 的行为。我首先考虑pragma data_seg
在 Windows 上使用。但是,即使我正确设置了共享数据段,foo.exe
并且bar.dll
从不共享x
. 回想一下,bar.dll
加载到 的地址空间中foo.exe
。但是,如果我运行 的另一个实例foo.exe
,则x
是共享的。但是,我不想x
被不同的进程共享。所以,使用data_seg
失败。
I may it use a memory-mapped file by making an unique name between exe and dll, which I'm trying now.
我可以通过在 exe 和 dll 之间创建唯一名称来使用内存映射文件,我现在正在尝试这样做。
Two questions:
两个问题:
- Why the behavior of Linux and Windows is different? Can anyone explain more about this?
- What would be most easiest way to solve this problem on Windows?
- 为什么 Linux 和 Windows 的行为不同?任何人都可以解释更多关于这个吗?
- 在 Windows 上解决此问题的最简单方法是什么?
采纳答案by Mikael Persson
First, I found that this articlewas a very interesting and a concise read on dynamic link libraries (the article is only specific to Linux, but the concepts surely apply to windows as well and you might get some insight as to the different behaviour you are seeing). Especially the fundamental difference between static and dynamic loading.
首先,我发现这篇文章非常有趣且简明扼要地阅读了动态链接库(该文章仅针对 Linux,但这些概念肯定也适用于 Windows,您可能会对自己的不同行为有所了解看到)。尤其是静态加载和动态加载之间的根本区别。
I think what you want or are trying to implement is a "cross-module singleton" pattern. If you read the answers to this thread, I don't know how I could possibly answer your question any better than Ben Voigt answered that post. I have implemented a cross-module singleton before (a few times actually) using the method he describes, and it works like a charm.
我认为您想要或正在尝试实现的是“跨模块单例”模式。如果你阅读了这个帖子的答案,我不知道我怎么可能比 Ben Voigt 回答那个帖子更好地回答你的问题。我之前(实际上有几次)使用他描述的方法实现了一个跨模块的单例,它的作用就像一个魅力。
Of course, you will not be able to retain the cleaniness of just having the global variable sit there in the cpp file. You will have to use a static pointer and some accessor functions and reference counting. But it can work. I'm not so sure how it would be possible to avoid that foo.exe and foo.exe share the same instance of global data one bar.dll, I never had to do that and can't really think of a way to do it, sorry.
当然,您将无法保持仅将全局变量放在 cpp 文件中的清洁度。您将不得不使用静态指针和一些访问器函数和引用计数。但它可以工作。我不太确定如何避免 foo.exe 和 foo.exe 共享同一个 bar.dll 全局数据实例,我从来没有这样做过,也想不出办法它,对不起。
回答by Ciaran Keating
If foo.exe always loads bar.dll then you can implement the variable in bar.dll and export it. For example, some file b.cpp compiled only into bar.dll, not into foo.exe:
如果 foo.exe 总是加载 bar.dll,那么您可以在 bar.dll 中实现变量并将其导出。例如,有些文件 b.cpp 只编译成 bar.dll,没有编译成 foo.exe:
__declspec(dllexport) int x;
Then import it in a source file c.cpp compiled into foo.exe:
然后在编译成foo.exe的源文件c.cpp中导入:
__declspec(dllimport) int x;
However, if sometimes foo.exe doesn't load bar.dll then this won't work. Also, I'm writing this from memory and so there might be some syntactical errors, but hopefully it's enough to point you in the right direction.
但是,如果有时 foo.exe 不加载 bar.dll,那么这将不起作用。另外,我是凭记忆写的,所以可能会有一些语法错误,但希望这足以为您指明正确的方向。
I can't answer why it's different Linux.
我无法回答为什么它与 Linux 不同。
回答by zdan
If I understand your question correctly, you are statically linking a.cpp into foo.exe and bar.dll, so you get 2 instances of x.
如果我正确理解了您的问题,那么您将 a.cpp 静态链接到 foo.exe 和 bar.dll,因此您将获得 2 个 x 实例。
If you created a third dll (say a.dll), and you dynamically link foo.exe and bar.dll to a.dll, you will get the behaviour you desire:
如果您创建了第三个 dll(比如 a.dll),并且您将 foo.exe 和 bar.dll 动态链接到 a.dll,您将获得您想要的行为:
- foo.exe loads a.dll and creates x.
- bar.dll gets loaded and sees that a.dll is loaded and doesn't load it again, they share x.
- Another process loads a.dll, it gets its own x.
- foo.exe 加载 a.dll 并创建 x。
- bar.dll 被加载并看到 a.dll 被加载并且不再加载它,它们共享 x。
- 另一个进程加载 a.dll,它得到自己的 x。
回答by Jeremiah
I found this to be such an interesting question that I took the time to write an extensive tutorial on how to use DLL's to share data among multiple DLLs (either implicitly, or explicitly linked) but also make sure the data is not shared among separate processes of the same executable file.
我发现这是一个非常有趣的问题,所以我花时间写了一篇关于如何使用 DLL 在多个 DLL 之间共享数据(隐式或显式链接)的详细教程,同时还要确保数据不在单独的进程之间共享同一个可执行文件。
You can find the full article here: http://3dgep.com/?p=1759
你可以在这里找到完整的文章:http: //3dgep.com/?p=1759
A solution to this problem that I found to work quite well is to create a "common" or "shared" dll that defines all the data and methods that you want to share across multiple DLL's (but not shared among processes).
我发现这个问题的一个很好的解决方案是创建一个“公共”或“共享”dll,它定义了要在多个 DLL 之间共享(但不在进程之间共享)的所有数据和方法。
Let's suppose you want to define a singleton class that can be accessed from the main application code (the EXE) but you also want to access the singleton instance in shared (either implicitly or explicitly linked DLL). First, you would need to declare the singleton class in the "common" DLL:
假设您想定义一个可以从主应用程序代码(EXE)访问的单例类,但您还想访问共享(隐式或显式链接的 DLL)中的单例实例。首先,您需要在“通用”DLL 中声明单例类:
// Export the class when compiling the DLL,
// otherwise import the class when using the DLL.
class __declspec(dllexport) MySingleton
{
public:
static MySingleton& Instance();
};
When compiling the CommonDLL project, you have to export the class declaratoin by decorating the class with __declspec(dllexport)
and when you are using the DLL (in the application for example), the class definition needs to be imported by decorating the class with __declspec(dllimport)
.
编译CommonDLL工程时,必须通过装饰类来导出类声明,__declspec(dllexport)
使用DLL时(例如在应用程序中),需要通过装饰类来导入类定义__declspec(dllimport)
。
When exporting a class by decorating the class with the __declspec(dllexport)
specifier, all of the class's methods and data (even private data) are exported from the DLL and usable by any DLL or EXE that implicitly links to the common DLL.
通过使用说明__declspec(dllexport)
符修饰类来导出类时,类的所有方法和数据(甚至私有数据)都从 DLL 中导出,并且可供任何隐式链接到公共 DLL 的 DLL 或 EXE 使用。
The definition of the MySingleton class might look something like this:
MySingleton 类的定义可能如下所示:
MySingleton& MySingleton::Instance()
{
static MySingleton instance;
return instance;
}
When compiling the common dll, two files will be produced:
编译通用dll时,会产生两个文件:
- The Common.DLLfile which is the shared library that defines the mehthods and data exported used by the DLL.
- The Common.LIBfile which declares stubs for the methods and members exported from the DLL.
- 所述Common.DLL文件,该文件是共享库定义mehthods和数据导出的所使用的DLL。
- 该Common.LIB文件,声明了从DLL导出的方法和成员存根。
If you link you application against the exported LIB file, then the DLL file will be implicitly linked at runtime (as long as the DLL file is found in the DLL search paths) and you will have access to the singleton defined in the CommonDLL.DLL file.
如果您将应用程序链接到导出的 LIB 文件,则 DLL 文件将在运行时隐式链接(只要在 DLL 搜索路径中找到该 DLL 文件),您将可以访问 CommonDLL.DLL 中定义的单例文件。
Also, any shared library (plug-ins for example) that also links against the CommonDLL.LIB file will have access to the same singleton instances when dynamically loaded by the application.
此外,当应用程序动态加载时,任何也链接到 CommonDLL.LIB 文件的共享库(例如插件)都可以访问相同的单例实例。
For a full explanation of this solution including a source code sample, check-out the following article I posted titled "Using Dynamic Link Libraries (DLL) to Create Plug-Ins":
有关此解决方案的完整说明(包括源代码示例),请查看我发布的以下文章,标题为“使用动态链接库 (DLL) 创建插件”:
回答by James Caccese
To get the behavior of linux where both the main program and a dll share the same x
, you can export that variable from either the dll, or the main program. The other module must import that variable.
要获得主程序和 dll 共享相同的 linux 行为x
,您可以从 dll 或主程序导出该变量。另一个模块必须导入该变量。
You do this by using DEF files (see microsoft's documentation), or by marking the uses with the variable with __declspec(dllexport)
where it's defined, and __declspec(dllimport)
in any other module it's used (see microsoft's documentation). This is the same as how any function, object, or variable is shared between modules in windows.
您可以通过使用 DEF 文件(请参阅 microsoft 的文档)或通过使用变量__declspec(dllexport)
的定义位置以及__declspec(dllimport)
在使用它的任何其他模块中标记用途来完成此操作(请参阅 microsoft 的文档)。这与在 Windows 中的模块之间共享任何函数、对象或变量的方式相同。
In the case where you'd like a program to load a library at runtime, but the main program may have to use the variable before the library is loaded, the program should export the variable, and the dll should import it. There is a little bit of a chicken and egg problem here because the dll depends on the main program, and the main program depends on the dll. See http://www.lurklurk.org/linkers/linkers.html#wincircular
如果您希望程序在运行时加载库,但主程序可能必须在加载库之前使用该变量,则程序应导出该变量,而 dll 应导入它。这里有一点鸡和蛋的问题,因为dll依赖于主程序,而主程序又依赖于dll。见http://www.lurklurk.org/linkers/linkers.html#wincircular
I've written an example of how you can do this using both Microsoft's compiler and mingw (gcc in windows), including all the different ways a program and a library can link to each other (statically, dll loaded at program start, dll loaded during runtime)
我写了一个例子,说明如何使用 Microsoft 的编译器和 mingw(windows 中的 gcc)来做到这一点,包括程序和库可以相互链接的所有不同方式(静态地,在程序启动时加载 dll,加载 dll在运行时)
main.h
主文件
#ifndef MAIN_H
#define MAIN_H
// something that includes this
// would #include "linkage_importing.h"
// or #include "linkage_exporting.h"
// as appropriate
#ifndef EXPLICIT_MAIN
LINKAGE int x;
#endif // EXPLICIT_MAIN
#endif // MAIN_H
main.c
主文件
#ifdef EXPLICIT_DLL
#include "dyn_link.h"
#endif // EXPLICIT_DLL
#include <stdio.h>
#include "linkage_exporting.h"
#include "main.h"
#include "linkage_importing.h"
#include "dll.h"
FNCALL_DLL get_call_dll(void);
int main(int argc, char* argv[])
{
FNCALL_DLL fncall_dll;
fncall_dll = get_call_dll();
if (fncall_dll)
{
x = 42;
printf("Address of x as seen from main() in main.c: %p\n", &x);
printf("x is set to %i in main()\n", x);
fncall_dll();
// could also be called as (*fncall_dll)();
// if you want to be explicit that fncall_dll is a function pointer
printf("Value of x as seen from main() after call to call_dll(): %i\n", x);
}
return 0;
}
FNCALL_DLL get_call_dll(void)
{
#ifdef EXPLICIT_DLL
return get_ptr("dll.dll", "call_dll");
#else
return call_dll;
#endif // EXPLICIT_DLL
}
dll.h
dll文件
#ifndef DLL_H
#define DLL_H
// something that includes this
// would #include "linkage_importing.h"
// or #include "linkage_exporting.h"
// as appropriate
// declaration of type to hold a
// pointer to the function
typedef void(*FNCALL_DLL)(void);
#ifndef EXPLICIT_DLL
LINKAGE void call_dll(void);
#endif // EXPLICIT_DLL
#endif // DLL_H
dll.c
dll文件
#ifdef EXPLICIT_MAIN
#include "dyn_link.h"
#endif // EXPLICIT_MAIN
#include <stdio.h>
#include "linkage_importing.h"
#include "main.h"
#include "linkage_exporting.h"
#include "dll.h"
int* get_x_ptr(void);
LINKAGE void call_dll(void)
{
int* x_ptr;
x_ptr = get_x_ptr();
if (x_ptr)
{
printf("Address of x as seen from call_dll() in dll.c: %p\n", x_ptr);
printf("Value of x as seen in call_dll: %i()\n", *x_ptr);
*x_ptr = 31415;
printf("x is set to %i in call_dll()\n", *x_ptr);
}
}
int* get_x_ptr(void)
{
#ifdef EXPLICIT_MAIN
return get_ptr("main.exe", "x"); // see note in dyn_link.c about using the main program as a library
#else
return &x;
#endif //EXPLICIT_MAIN
}
dyn_link.h
动态链接.h
#ifndef DYN_LINK_H
#define DYN_LINK_H
// even though this function is used by both, we link it
// into both main.exe and dll.dll as necessary.
// It's not shared in a dll, because it helps us load dlls :)
void* get_ptr(const char* library, const char* object);
#endif // DYN_LINK_H
dyn_link.c
动态链接.c
#include "dyn_link.h"
#include <windows.h>
#include <stdio.h>
void* get_ptr(const char* library, const char* object)
{
HINSTANCE hdll;
FARPROC ptr;
hdll = 0;
ptr = 0;
hdll = LoadLibrary(library);
// in a better dynamic linking library, there would be a
// function that would call FreeLibrary(hdll) to cleanup
//
// in the case where you want to load an object in the main
// program, you can use
// hdll = GetModuleHandle(NULL);
// because there's no need to call LoadLibrary on the
// executable if you can get its handle by some other means.
if (hdll)
{
printf("Loaded library %s\n", library);
ptr = GetProcAddress(hdll, object);
if (ptr)
{
printf("Found %s in %s\n", object, library);
} else {
printf("Could not find %s in %s\n", object, library);
}
} else {
printf("Could not load library %s\n", library);
}
return ptr;
}
linkage_importing.h
linking_importing.h
// sets up some macros to handle when to use "__declspec(dllexport)",
// "__declspec(dllimport)", "extern", or nothing.
// when using the LINKAGE macro (or including a header that does):
// use "#include <linkage_importing.h>" to make the LINKAGE macro
// do the right thing for importing (when using functions,
// variables, etc...)
//
// use "#include <linkage_exporting.h>" to make the LINKAGE macro
// do the right thing for exporting (when declaring functions,
// variables, etc).
//
// You can include either file at any time to change the meaning of
// LINKAGE.
// if you declare NO_DLL these macros do not use __declspec(...), only
// "extern" as appropriate
#ifdef LINKAGE
#undef LINKAGE
#endif
#ifdef NO_DLL
#define LINKAGE extern
#else
#define LINKAGE extern __declspec(dllimport)
#endif
linkage_exporting.h
Linked_exporting.h
// See linkage_importing.h to learn how this is used
#ifdef LINKAGE
#undef LINKAGE
#endif
#ifdef NO_DLL
#define LINKAGE
#else
#define LINKAGE __declspec(dllexport)
#endif
build mingw explicit both.sh
构建 mingw 显式 both.sh
#! /bin/bash
echo Building configuration where both main
echo and dll link explicitly to each other
rm -rf mingw_explicit_both
mkdir -p mingw_explicit_both/obj
cd mingw_explicit_both/obj
# compile the source code (dll created with position independent code)
gcc -c -fPIC -DEXPLICIT_MAIN ../../dll.c
gcc -c -DEXPLICIT_DLL ../../main.c
gcc -c ../../dyn_link.c
#create the dll from its object code the normal way
gcc -shared -odll.dll dll.o dyn_link.o -Wl,--out-implib,libdll.a
# create the executable
gcc -o main.exe main.o dyn_link.o
mv dll.dll ..
mv main.exe ..
cd ..
build mingw explicit dll.sh
构建 mingw 显式 dll.sh
#! /bin/bash
echo Building configuration where main explicitly
echo links to dll, but dll implicitly links to main
rm -rf mingw_explicit_dll
mkdir -p mingw_explicit_dll/obj
cd mingw_explicit_dll/obj
# compile the source code (dll created with position independent code)
gcc -c -fPIC ../../dll.c
gcc -c -DEXPLICIT_DLL ../../main.c
gcc -c ../../dyn_link.c
# normally when linking a dll, you just use gcc
# to create the dll and its linking library (--out-implib...)
# But, this dll needs to import from main, and main's linking library doesn't exist yet
# so we create the linking library for main.o
# make sure that linking library knows to look for symbols in main.exe (the default would be a.out)
gcc -omain.exe -shared main.o -Wl,--out-implib,main.a #note this reports failure, but it's only a failure to create main.exe, not a failure to create main.a
#create the dll from its object code the normal way (dll needs to know about main's exports)
gcc -shared -odll.dll dll.o dyn_link.o main.a -Wl,--out-implib,libdll.a
# create the executable
gcc -o main.exe main.o dyn_link.o
mv dll.dll ..
mv main.exe ..
cd ..
build mingw explicit main.sh
构建 mingw 显式 main.sh
#! /bin/bash
echo Building configuration where dll explicitly
echo links to main, but main implicitly links to dll
rm -rf mingw_explicit_main
mkdir -p mingw_explicit_main/obj
cd mingw_explicit_main/obj
# compile the source code (dll created with position independent code)
gcc -c -fPIC -DEXPLICIT_MAIN ../../dll.c
gcc -c ../../main.c
gcc -c ../../dyn_link.c
# since the dll will link dynamically and explicitly with main, there is no need
# to create a linking library for main, and the dll can be built the regular way
gcc -shared -odll.dll dll.o dyn_link.o -Wl,--out-implib,libdll.a
# create the executable (main still links with dll implicitly)
gcc -o main.exe main.o -L. -ldll
mv dll.dll ..
mv main.exe ..
cd ..
build mingw implicit.sh
构建 mingw 隐式.sh
#! /bin/bash
echo Building configuration where main and
echo dll implicitly link to each other
rm -rf mingw_implicit
mkdir -p mingw_implicit/obj
cd mingw_implicit/obj
# compile the source code (dll created with position independent code)
gcc -c -fPIC ../../dll.c
gcc -c ../../main.c
# normally when linking a dll, you just use gcc
# to create the dll and its linking library (--out-implib...)
# But, this dll needs to import from main, and main's linking library doesn't exist yet
# so we create the linking library for main.o
# make sure that linking library knows to look for symbols in main.exe (the default would be a.out)
gcc -omain.exe -shared main.o -Wl,--out-implib,main.a #note this reports failure, but it's only a failure to create main.exe, not a failure to create main.a
# create the dll from its object code the normal way (dll needs to know about main's exports)
gcc -shared -odll.dll dll.o main.a -Wl,--out-implib,libdll.a
# create the executable (exe needs to know about dll's exports)
gcc -o main.exe main.o -L. -ldll
mv dll.dll ..
mv main.exe ..
cd ..
build mingw static.sh
构建 mingw static.sh
#! /bin/bash
echo Building configuration where main and dll
echo statically link to each other
rm -rf mingw_static
mkdir -p mingw_static/obj
cd mingw_static/obj
# compile the source code
gcc -c -DNO_DLL ../../dll.c
gcc -c -DNO_DLL ../../main.c
# create the static library
ar -rcs dll.a dll.o
# link the executable
gcc -o main.exe main.o dll.a
mv main.exe ../
cd ..
build msvc explicit both.bat
构建 msvc 显式 both.bat
@echo off
echo Building configuration where both main
echo and dll link explicitly to each other
rd /s /q win_explicit_both
md win_explicit_both\obj
cd win_explicit_both\obj
rem compile the source code
cl /nologo /c /DEXPLICIT_MAIN ..\..\dll.c
cl /nologo /c /DEXPLICIT_DLL ..\..\main.c
cl /nologo /c ..\..\dyn_link.c
rem create the dll from its object code the normal way
link /nologo /dll dll.obj dyn_link.obj
rem create the executable
link /nologo main.obj dyn_link.obj
move dll.dll ..\
move main.exe ..\
cd ..
build msvc explicit dll.bat
构建 msvc 显式 dll.bat
@echo off
echo Building configuration where main explicitly
echo links to dll, but dll implicitly links to main
rd /s /q win_explicit_dll
md win_explicit_dll\obj
cd win_explicit_dll\obj
rem compile the source code
cl /nologo /c ..\..\dll.c
cl /nologo /c /DEXPLICIT_DLL ..\..\main.c
cl /nologo /c ..\..\dyn_link.c
rem normally when linking a dll, you just use the link command
rem that creates the dll and its linking library.
rem But, this dll needs to import from main, and main's linking library doesn't exist yet
rem so we create the linking library for main.obj
rem make sure that linking library knows to look for symbols in main.exe (the default would be main.dll)
lib /nologo /def /name:main.exe main.obj
rem create the dll from its object code the normal way (dll needs to know about main's exports)
link /nologo /dll dll.obj main.lib
rem create the executable
link /nologo main.obj dyn_link.obj
move dll.dll ..\
move main.exe ..\
cd ..
build msvc explicit main.bat
构建 msvc 显式 main.bat
@echo off
echo Building configuration where dll explicitly
echo links to main, but main implicitly links to dll
rd /s /q win_explicit_main
md win_explicit_main\obj
cd win_explicit_main\obj
rem compile the source code
cl /nologo /c /DEXPLICIT_MAIN ..\..\dll.c
cl /nologo /c ..\..\main.c
cl /nologo /c ..\..\dyn_link.c
rem since the dll will link dynamically and explicitly with main, there is no need
rem to create a linking library for main, and the dll can be built the regular way
link /nologo /dll dll.obj dyn_link.obj
rem create the executable (main still links with dll implicitly)
link /nologo main.obj dll.lib
move dll.dll ..\
move main.exe ..\
cd ..
build msvc implicit.bat
构建 msvc 隐式.bat
@echo off
echo Building configuration where main and
echo dll implicitly link to each other
rd /s /q win_implicit
md win_implicit\obj
cd win_implicit\obj
rem compile the source code
cl /nologo /c ..\..\dll.c
cl /nologo /c ..\..\main.c
rem normally when linking a dll, you just use the link command
rem that creates the dll and its linking library.
rem But, this dll needs to import from main, and main's linking library doesn't exist yet
rem so we create the linking library for main.obj
rem make sure that linking library knows to look for symbols in main.exe (the default would be main.dll)
lib /nologo /def /name:main.exe main.obj
rem create the dll from its object code the normal way (dll needs to know about main's exports)
link /nologo /dll dll.obj main.lib
rem create the executable (exe needs to know about dll's exports)
link /nologo main.obj dll.lib
move dll.dll ..\
move main.exe ..\
cd ..
build msvc static.bat
构建msvc static.bat
@echo off
echo Building configuration where main and dll
echo statically link to each other
rd /s /q win_static
md win_static\obj
cd win_static\obj
rem compile the source code
cl /nologo /DNO_DLL /c ..\..\dll.c
cl /nologo /DNO_DLL /c ..\..\main.c
rem create the static library
lib /nologo dll.obj
rem link the executable
link /nologo main.obj dll.lib
move main.exe ..\
cd ..
回答by Reed Hedges
The difference between GCC and and Visual Studio is that on Linux, it implicitly allows code to see symbols from other, dynamically linked (shared) libraries, without you the programmer having to do anything special. All the symbols are available in the shared (dynamically linked) library for the dynamic linker to resolve when the program runs. On Windows, you have to specifically export the symbol from the DLL, and also explicitly import it into the program or library that's using it. (Usually this is done via a macro (#define) that expands to have the dllexport declaration in a header file when building the dll itself, but when the header file is included by some other program using the dll, it expands to have the dllimport declaration instead. In my opinion this is a pain in the neck, and GCC's behavior is easier, since you don't have to do anything special to get the behavior you usually want.
GCC 和 Visual Studio 之间的区别在于,在 Linux 上,它隐式地允许代码查看来自其他动态链接(共享)库的符号,而程序员不必做任何特殊的事情。所有符号都在共享(动态链接)库中可供动态链接器在程序运行时解析。在 Windows 上,您必须专门从 DLL 中导出符号,并明确地将其导入到使用它的程序或库中。(通常这是通过宏 (#define) 完成的,在构建 dll 本身时,该宏扩展为在头文件中包含 dllexport 声明,但是当头文件被其他使用 dll 的程序包含时,它会扩展为具有 dllimport而是声明。在我看来,这是一个令人头疼的问题,而且 GCC 的行为更容易,因为您不这样做
On newer version of GCC, you can set the default to hide symbols when building a dynamic (shared) library, if you want to.
在较新版本的 GCC 上,如果需要,您可以将默认设置设置为在构建动态(共享)库时隐藏符号。
回答by Zeeshan
Thanks for providing various solution on this. i have looked at these option and decided to implement the cross module singleton using the Shared Memory and it worked well for me as well. i have used Qt QSharedMemory to achieve my task but the prototype i wrote using the Win32 CreateFileMapping & etc.
感谢您为此提供各种解决方案。我查看了这些选项并决定使用共享内存实现跨模块单例,它对我来说也很好用。我已经使用 Qt QSharedMemory 来完成我的任务,但是我使用 Win32 CreateFileMapping 等编写的原型。
回答by Michael Haephrati
I have seen many answers to this question and since it is a bit tricky and unclear I would like to bring the following scenario. We want to share a global variable between a DLL and a main program, and also allow access to this variable from different modules in the DLL and in the main program.
我已经看到这个问题的很多答案,因为它有点棘手和不清楚,我想带来以下场景。我们希望在 DLL 和主程序之间共享一个全局变量,并且还允许从 DLL 和主程序中的不同模块访问该变量。
The variable is a BOOL indicating if the program should continue running or stop. The variable name is ShouldRun;
该变量是一个 BOOL,指示程序是继续运行还是停止。变量名是ShouldRun;
In the main program we need to put:
在主程序中,我们需要放置:
__declspec(dllexport) bool ShouldRun;
In the DLL's main module we need to put:
在 DLL 的主模块中,我们需要放置:
extern "C" BOOL __declspec(dllexport) ShouldRun = TRUE;
In any other module inside the DLL project we will use:
在 DLL 项目中的任何其他模块中,我们将使用:
extern "C" BOOL ShouldRun;