Fra*_*cis 9 c++ static-libraries dynamic-library
在win32上,我构建了一个名为A.dll的动态库,它链接到一个名为B.lib的静态库,并且还构建了一个名为C.exe的可执行文件,它只依赖于A.dll.
但是现在,在C.exe中如果我想使用只在B.lib中有定义的函数foo,我必须再次将C.exe与B.lib链接.
现在的问题是我可以导出FOO从B.LIB直接进入A.DLL建设时A.DLL,怎么样?
我还想知道在与GCC打交道时会有什么.
Mik*_*han 13
foo可以从DLL导出函数,前提是: -
例如foo,在__declspec(dllexport)将函数编译为目标文件时,使用该属性声明foo.obj
您链接foo.obj到DLL.
如何foo.obj链接到DLL 并不重要.
也许您foo.obj在DLL的链接中明确指定.
也许你把foo.obj它放在静态库中,比如说foobar.lib,DLL的链接包含对函数的一些引用foo.然后链接器将提取foo.obj自foobar.lib并将其链接到DLL,以解决引用.
如果foo.obj通过从静态库中提取foo.obj而链接,则链接与按名称链接的链接完全相同.静态库只是一个目标文件包,链接器可以从中选择它需要在链接上携带的目标文件.链接完成后,生成的程序或DLL不依赖于静态库.如果它需要包中的任何目标文件,它现在已经得到它们.它不需要包.
下面是使用GCC mingw-w64工具链的一个例子,说明如何在静态库中链接DLL导出的函数:
C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev0>echo off
Microsoft Windows [Version 10.0.15063]
(c) 2017 Microsoft Corporation. All rights reserved.
C:\>cd develop\so\scrap
C:\develop\so\scrap>dir
Volume in drive C has no label.
Volume Serial Number is 16C7-F955
Directory of C:\develop\so\scrap
16/12/2017 17:50 <DIR> .
16/12/2017 17:50 <DIR> ..
16/12/2017 12:41 116 greeting.cpp
16/12/2017 12:42 99 greeting.h
16/12/2017 12:10 109 hello.cpp
16/12/2017 12:12 90 hello.h
16/12/2017 16:21 197 main.cpp
16/12/2017 12:25 117 niceday.cpp
16/12/2017 12:26 96 niceday.h
7 File(s) 824 bytes
2 Dir(s) 101,878,943,744 bytes free
Run Code Online (Sandbox Code Playgroud)
HELLO.CPP
#include "hello.h"
#include <iostream>
void hello()
{
std::cout << "Hello world!" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
hello.h
#ifndef HELLO_H
#define HELLO_H
extern __declspec(dllexport) void hello();
#endif
Run Code Online (Sandbox Code Playgroud)
我们将编译hello.cpp:
C:\develop\so\scrap>g++ -Wall -c -o hello.obj hello.cpp
Run Code Online (Sandbox Code Playgroud)
同理:
niceday.cpp
#include "niceday.h"
#include <iostream>
void niceday()
{
std::cout << "What a nice day!" << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
niceday.h
#ifndef NICEDAY_H
#define NICEDAY_H
extern __declspec(dllexport) void niceday();
#endif
Run Code Online (Sandbox Code Playgroud)
我们会编译 niceday.cpp
C:\develop\so\scrap>g++ -Wall -c -o niceday.obj niceday.cpp
Run Code Online (Sandbox Code Playgroud)
现在我们将这两个目标文件放在一个静态库中. libgreet.lib
ar rcs libgreet.lib hello.obj niceday.obj
Run Code Online (Sandbox Code Playgroud)
另一个源文件和标题:
greeting.cpp
#include "greeting.h"
#include "hello.h"
#include "niceday.h"
void greeting()
{
hello();
niceday();
}
Run Code Online (Sandbox Code Playgroud)
greeting.h
#ifndef GREETING_H
#define GREETING_H
extern __declspec(dllexport) void greeting();
#endif
Run Code Online (Sandbox Code Playgroud)
我们还将编译:
g++ -Wall -c -o greeting.obj greeting.cpp
Run Code Online (Sandbox Code Playgroud)
现在我们将创建一个DLL libgreeting.dll,使用greeting.obj和静态库libgreet.lib:
C:\develop\so\scrap>g++ -shared -o libgreeting.dll greeting.obj libgreet.lib
Run Code Online (Sandbox Code Playgroud)
这里有一个程序源文件:
main.cpp中
#include "hello.h"
#include "niceday.h"
#include "greeting.h"
#include <iostream>
int main()
{
hello();
niceday();
std::cout << "I said..." << std::endl;
greeting();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我们还将编译:
C:\develop\so\scrap>g++ -Wall -c -o main.obj main.cpp
Run Code Online (Sandbox Code Playgroud)
最后,我们将通过我们的链接使程序main.obj有libgreeting.dll.
只有用libgreeting.dll.
C:\develop\so\scrap>g++ -o prog main.obj libgreeting.dll
Run Code Online (Sandbox Code Playgroud)
运行程序:
C:\develop\so\scrap>prog
Hello world!
What a nice day!
I said...
Hello world!
What a nice day!
Run Code Online (Sandbox Code Playgroud)
调用所有三个DLL导出的函数hello,niceday和greeting.重要的是,为了实现这一点,所有这些都被宣布,__declspec(dllexport)并且所有这些都libgreeting.dll
以某种方式联系在一起.碰巧,其中两个(hello,niceday)从静态库链接而另一个(greeting)直接从目标文件链接:这无关紧要.
如果你有兴趣......
以下是使用Visual Studio 2017工具链执行相同操作的方法:
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.4.3
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'
C:\Users\mikek\source>cd C:\develop\so\scrap
C:\develop\so\scrap>dir
Volume in drive C has no label.
Volume Serial Number is 16C7-F955
Directory of C:\develop\so\scrap
16/12/2017 18:31 <DIR> .
16/12/2017 18:31 <DIR> ..
16/12/2017 12:41 116 greeting.cpp
16/12/2017 12:42 99 greeting.h
16/12/2017 12:10 109 hello.cpp
16/12/2017 12:12 90 hello.h
16/12/2017 16:21 197 main.cpp
16/12/2017 12:25 117 niceday.cpp
16/12/2017 12:26 96 niceday.h
7 File(s) 824 bytes
2 Dir(s) 101,877,473,280 bytes free
Run Code Online (Sandbox Code Playgroud)
编译hello.cpp:
C:\develop\so\scrap>cl /W4 /EHsc /c /Fohello.obj hello.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.11.25547 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
hello.cpp
Run Code Online (Sandbox Code Playgroud)
编译niceday.cpp:
C:\develop\so\scrap>cl /W4 /EHsc /c /Foniceday.obj niceday.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.11.25547 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
niceday.cpp
Run Code Online (Sandbox Code Playgroud)
制作静态库:
C:\develop\so\scrap>lib /out:libgreet.lib hello.obj niceday.obj
Microsoft (R) Library Manager Version 14.11.25547.0
Copyright (C) Microsoft Corporation. All rights reserved.
Run Code Online (Sandbox Code Playgroud)
编译greeting.cpp:
C:\develop\so\scrap>cl /W4 /EHsc /c /Fogreeting.obj greeting.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.11.25547 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
greeting.cpp
Run Code Online (Sandbox Code Playgroud)
链接libgreeting.dll:
C:\develop\so\scrap>link /dll /out:libgreeting.dll greeting.obj libgreet.lib
Microsoft (R) Incremental Linker Version 14.11.25547.0
Copyright (C) Microsoft Corporation. All rights reserved.
Creating library libgreeting.lib and object libgreeting.exp
Run Code Online (Sandbox Code Playgroud)
在这里,正如您所知,Microsoft链接器创建了一个导入库 libgreeting.lib
(不要与静态库混淆libgreet.lib),用于链接libgreeting.dll到程序或其他DLL.
编译main.cpp:
C:\develop\so\scrap>cl /W4 /EHsc /c /Fomain.obj main.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.11.25547 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
main.cpp
Run Code Online (Sandbox Code Playgroud)
链接我们的程序(使用导入库libgreeting.lib代替
libgreeting.dll):
C:\develop\so\scrap>link /out:prog.exe main.obj libgreeting.lib
Microsoft (R) Incremental Linker Version 14.11.25547.0
Copyright (C) Microsoft Corporation. All rights reserved.
Run Code Online (Sandbox Code Playgroud)
并运行:
C:\develop\so\scrap>prog
Hello world!
What a nice day!
I said...
Hello world!
What a nice day!
Run Code Online (Sandbox Code Playgroud)
后来
如果我
foo没有编译,__declspec(dllexport)并且void foo()在构建B.lib时有这样的声明.但是当我构建C.exe时,我改变了foo的声明__declspec(dllexport) void foo().问题是我仍然可以做到以上吗?
原则上,如果你编译的对象文件具有一定的声明foo在其头文件,然后更改随后该项声明#include的头文件中的某些其它目标文件的编译,那么你很可能在说谎编译器在第二编译,当您将这些目标文件链接到某个程序或DLL时,您可能会发生不好的事情.
但是,在这种情况下,你可以逃脱它.在上面的示例中,您可以首先编译,例如,hello.cpp使用以下声明hello.h:
extern void hello(void);
Run Code Online (Sandbox Code Playgroud)
后来,当您编译greeting.cpp,其中#includes ^ hello.h,你可能会改变声明:
extern __declspec(dllexport) void hello(void);
Run Code Online (Sandbox Code Playgroud)
以及链接时hello 将为 DLL_exported 的结果libgreeting.dll.
宣言与__declspec(dllexport)精炼,而不是与没有的人相矛盾.在链接中libgreeting.dll,链接器会看到一个非DLL导出的helloin 引用hello.obj和一个DLL导出的引用greeting.obj.它DLL导出符号,因为它已经看到至少一个DLL导出的引用.
毫无疑问,这是一个黑客.
| 归档时间: |
|
| 查看次数: |
4987 次 |
| 最近记录: |