min*_*ang 22 c c++ linux windows dll
我想在进程和进程调用的dll之间共享静态/全局变量.exe和dll位于相同的内存地址空间中.我不希望变量在其他进程之间共享.
详述问题:
说是有一个静态/全局变量x在a.cpp.exe foo.exe和dll bar.dll都有a.cpp,所以变量x在两个图像中.
现在,foo.exe动态加载(或静态)bar.dll.然后,问题是变量x是否由exe和dll共享.
在Windows中,这两个人从不分享x:exe和dll将有一个单独的副本x.但是,在Linux中,exe和dll会共享变量x.
不幸的是,我想要Linux的行为.我首先考虑pragma data_seg在Windows上使用.但是,即使我正确设置了共享数据段,foo.exe也bar.dll从不共享x.回想一下,bar.dll加载到地址空间中foo.exe.但是,如果我运行另一个实例foo.exe,则x共享.但是,我不希望x被不同的进程共享.所以,使用data_seg失败了.
我可以通过在exe和dll之间创建一个唯一的名称来使用内存映射文件,我现在正在尝试.
两个问题:
Jam*_*ese 11
要获得主程序和dll共享相同的linux行为x,可以从dll或主程序中导出该变量.另一个模块必须导入该变量.
您可以使用DEF文件(请参阅microsoft的文档),或使用变量的用途标记__declspec(dllexport)它的定义,以及__declspec(dllimport)使用它的任何其他模块(请参阅microsoft的文档).这与在Windows中的模块之间共享任何函数,对象或变量的方式相同.
如果您希望程序在运行时加载库,但主程序可能必须在加载库之前使用该变量,程序应该导出变量,并且dll应该导入它.这里有一点鸡和蛋的问题,因为dll取决于主程序,主程序取决于dll.见http://www.lurklurk.org/linkers/linkers.html#wincircular
我已经编写了一个示例,说明如何使用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
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
dll.h
#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
Run Code Online (Sandbox Code Playgroud)
dll.c
#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
}
Run Code Online (Sandbox Code Playgroud)
dyn_link.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
Run Code Online (Sandbox Code Playgroud)
dyn_link.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;
}
Run Code Online (Sandbox Code Playgroud)
linkage_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
Run Code Online (Sandbox Code Playgroud)
linkage_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
Run Code Online (Sandbox Code Playgroud)
构建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 ..
Run Code Online (Sandbox Code Playgroud)
构建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 ..
Run Code Online (Sandbox Code Playgroud)
构建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 ..
Run Code Online (Sandbox Code Playgroud)
build mingw implicit.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 ..
Run Code Online (Sandbox Code Playgroud)
建立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 ..
Run Code Online (Sandbox Code Playgroud)
构建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 ..
Run Code Online (Sandbox Code Playgroud)
构建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 ..
Run Code Online (Sandbox Code Playgroud)
构建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 ..
Run Code Online (Sandbox Code Playgroud)
构建msvc implicit.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 ..
Run Code Online (Sandbox Code Playgroud)
构建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 ..
Run Code Online (Sandbox Code Playgroud)
首先,我发现这篇文章是关于动态链接库的非常有趣和简洁的阅读(这篇文章仅针对Linux,但这些概念肯定也适用于Windows,你可能会对你的不同行为有所了解看到).特别是静态和动态加载之间的根本区别.
我认为你想要或正在尝试实现的是"跨模块单例"模式.如果您阅读了这个帖子的答案,我不知道我怎么能比Ben Voigt回答那个帖子更好地回答你的问题.我之前(实际上几次)使用他描述的方法实现了一个跨模块单例,它就像一个魅力.
当然,你将无法保持只有全局变量坐在cpp文件中的清洁.您将不得不使用静态指针和一些访问器函数和引用计数.但它可以工作.我不太确定怎么可能避免foo.exe和foo.exe共享同一个全局数据实例一个bar.dll,我从来没有这样做,也无法真正想办法对不起
如果foo.exe总是加载bar.dll,那么你可以在bar.dll中实现该变量并将其导出.例如,某些文件b.cpp只编译成bar.dll,而不是编译成foo.exe:
__declspec(dllexport) int x;
Run Code Online (Sandbox Code Playgroud)
然后将其导入到编译到foo.exe的源文件c.cpp中:
__declspec(dllimport) int x;
Run Code Online (Sandbox Code Playgroud)
但是,如果有时foo.exe没有加载bar.dll,那么这将无法正常工作.另外,我是从内存中写这个,所以可能会有一些语法错误,但希望它足以指出你正确的方向.
我无法回答为什么它与Linux不同.
小智 5
我发现这是一个很有趣的问题,我花了很多时间写了一篇有关如何使用DLL在多个DLL之间(隐式或显式链接)共享数据的教程,但还要确保不在单独的进程之间共享数据相同的可执行文件。
您可以在此处找到完整的文章:http: //3dgep.com/?p=1759
我发现效果很好的一个解决方案是创建一个“公共”或“共享” dll,该DLL定义了您希望在多个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();
};
Run Code Online (Sandbox Code Playgroud)
在编译CommonDLL项目时,必须通过使用修饰类来导出类声明,__declspec(dllexport)并且在使用DLL(例如在应用程序中)时,需要通过使用修饰类来导入类定义__declspec(dllimport)。
通过使用说明__declspec(dllexport)符修饰类来导出类时,所有类的方法和数据(甚至是私有数据)都将从DLL中导出,并且可由隐式链接到公共DLL的任何DLL或EXE使用。
MySingleton类的定义可能类似于以下内容:
MySingleton& MySingleton::Instance()
{
static MySingleton instance;
return instance;
}
Run Code Online (Sandbox Code Playgroud)
编译通用dll时,将生成两个文件:
如果您将应用程序链接到导出的LIB文件,则DLL文件将在运行时隐式链接(只要DLL文件在DLL搜索路径中找到),并且您将可以访问CommonDLL.DLL中定义的单例。文件。
此外,当应用程序动态加载时,也链接到CommonDLL.LIB文件的任何共享库(例如,插件)都可以访问相同的单例实例。
有关此解决方案的完整说明(包括源代码示例),请查看下面我张贴的标题为“使用动态链接库(DLL)创建插件”的文章:
| 归档时间: |
|
| 查看次数: |
49974 次 |
| 最近记录: |