在构建链接静态库的动态库时,我可以导出静态库的函数吗?
Can I export functions of a static library when building a dynamic library linking against that static library?
在 win32 上,我构建了一个名为 A.dll 的动态库,它 link 针对名为 [=47= 的静态库进行了编辑],还构建了一个名为 C.exe 的可执行文件,其中 仅 依赖于 A.dll.
但是现在,如果我想在 C.exe 中使用函数 foo,它只在 [=18= 中有定义]B.lib,我要linkC.exe反对B.lib 再次.
问题是我可以将 foo 从 B.lib 直接导出到 A.dll 构建时 A.dll,如何构建?
我也想知道在处理GCC的时候会怎么样
函数 foo
可以从 DLL 导出,前提是:-
当您使用 __declspec(dllexport)
属性声明 foo
将函数编译成目标文件,比如 foo.obj
你linkfoo.obj
进入DLL.
foo.obj
如何 link 进入 DLL 并不重要。
也许您在 DLL 的 linkage 中明确指定 foo.obj
。
也许你把 foo.obj
放在一个静态库里,比如 foobar.lib
,linkage
DLL 包含一些对函数 foo
的引用。然后 linker 会
从foobar.lib
和link中提取foo.obj
到DLL中,解析
那个参考。
如果 foo.obj
是通过从静态库中提取出来的 linked,linkage
与 foo.obj
是按名称 link 完全相同。静态库很简单
一袋目标文件,linker 可以从中挑选需要携带的文件
在 link 年龄。 linkage完成后,产生的程序或DLL没有依赖性
在静态库上。如果它需要包中的任何目标文件,它现在已经得到了它们。它不需要包。
这是一个使用 GCC mingw-w64 工具链的插图 Windows
DLL 导出的函数是从静态库中 link 编辑的:
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
hello.cpp
#include "hello.h"
#include <iostream>
void hello()
{
std::cout << "Hello world!" << std::endl;
}
hello.h
#ifndef HELLO_H
#define HELLO_H
extern __declspec(dllexport) void hello();
#endif
我们将编译hello.cpp
:
C:\develop\so\scrap>g++ -Wall -c -o hello.obj hello.cpp
同理:
niceday.cpp
#include "niceday.h"
#include <iostream>
void niceday()
{
std::cout << "What a nice day!" << std::endl;
}
niceday.h
#ifndef NICEDAY_H
#define NICEDAY_H
extern __declspec(dllexport) void niceday();
#endif
我们将编译niceday.cpp
C:\develop\so\scrap>g++ -Wall -c -o niceday.obj niceday.cpp
现在我们将把这两个目标文件放在一个静态库中。 libgreet.lib
ar rcs libgreet.lib hello.obj niceday.obj
另一个源文件和头文件:
greeting.cpp
#include "greeting.h"
#include "hello.h"
#include "niceday.h"
void greeting()
{
hello();
niceday();
}
greeting.h
#ifndef GREETING_H
#define GREETING_H
extern __declspec(dllexport) void greeting();
#endif
我们还将编译:
g++ -Wall -c -o greeting.obj greeting.cpp
现在我们将制作一个 DLL,libgreeting.dll
,使用 greeting.obj
和静态
图书馆 libgreet.lib
:
C:\develop\so\scrap>g++ -shared -o libgreeting.dll greeting.obj libgreet.lib
这里有一个程序源文件:
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;
}
我们还将编译:
C:\develop\so\scrap>g++ -Wall -c -o main.obj main.cpp
最后,我们将通过 link 将我们的 main.obj
与 libgreeting.dll
相结合来制作一个程序。
只有 和 libgreeting.dll
。
C:\develop\so\scrap>g++ -o prog main.obj libgreeting.dll
运行程序:
C:\develop\so\scrap>prog
Hello world!
What a nice day!
I said...
Hello world!
What a nice day!
所有三个 DLL 导出的函数,hello
、niceday
和 greeting
,
被称为。 要做到这一点,重要的是
声明为 __declspec(dllexport)
并且所有这些都被 link 编辑为 libgreeting.dll
不知何故。碰巧的是,其中两个 (hello
、niceday
) 是从静态库 link 编辑的,另一个 (greeting
) 是直接从静态库 link 编辑的目标文件:这无关紧要。
如果您有兴趣...
以下是使用 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
编译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
编译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
制作静态库:
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.
编译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
Link 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
在这里,如您所知,Microsoft linker 创建了一个 导入库 libgreeting.lib
(不要与静态库 libgreet.lib
混淆)用于
linking 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
Link 我们的程序(使用导入库 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.
和运行:
C:\develop\so\scrap>prog
Hello world!
What a nice day!
I said...
Hello world!
What a nice day!
以后
If foo
firstly was compiled without __declspec(dllexport)
and has a declaration like this void foo()
when I built B.lib.
But when I built C.exe I changed foo's declaration to __declspec(dllexport) void foo()
. The question is can I still make above happen?
原则上,如果你编译一个目标文件,在它的头文件中声明foo
然后 更改 该声明随后 #include
中的头文件
编译一些其他的目标文件,那么你很可能在欺骗编译器
第二次编译,当你 link 这些目标文件变成一些程序或 DLL 时
可以预料到坏事的发生。
然而,在这种情况下,您可以侥幸逃脱。在上面的例子中,你
可以先用 hello.h
:
中的声明编译,比如说 hello.cpp
extern void hello(void);
稍后,当你编译greeting.cpp
,其中#include
s hello.h
,你
可以将声明更改为:
extern __declspec(dllexport) void hello(void);
当您 link libgreeting.dll
.
时,hello
将 变为 DLL_exported
带有 __declspec(dllexport)
的声明完善了而不是与
那个没有。在 linking libgreeting.dll
中,linker 看到一个非 DLL 导出的引用
hello.obj
中的 hello
和 greeting.obj
中的 DLL 导出引用。它
DLL 导出该符号,因为它至少看到一个 DLL 导出的引用。
毫无疑问,这是一个 hack。
在 win32 上,我构建了一个名为 A.dll 的动态库,它 link 针对名为 [=47= 的静态库进行了编辑],还构建了一个名为 C.exe 的可执行文件,其中 仅 依赖于 A.dll.
但是现在,如果我想在 C.exe 中使用函数 foo,它只在 [=18= 中有定义]B.lib,我要linkC.exe反对B.lib 再次.
问题是我可以将 foo 从 B.lib 直接导出到 A.dll 构建时 A.dll,如何构建?
我也想知道在处理GCC的时候会怎么样
函数 foo
可以从 DLL 导出,前提是:-
当您使用
__declspec(dllexport)
属性声明foo
将函数编译成目标文件,比如foo.obj
你link
foo.obj
进入DLL.
foo.obj
如何 link 进入 DLL 并不重要。
也许您在 DLL 的 linkage 中明确指定 foo.obj
。
也许你把 foo.obj
放在一个静态库里,比如 foobar.lib
,linkage
DLL 包含一些对函数 foo
的引用。然后 linker 会
从foobar.lib
和link中提取foo.obj
到DLL中,解析
那个参考。
如果 foo.obj
是通过从静态库中提取出来的 linked,linkage
与 foo.obj
是按名称 link 完全相同。静态库很简单
一袋目标文件,linker 可以从中挑选需要携带的文件
在 link 年龄。 linkage完成后,产生的程序或DLL没有依赖性
在静态库上。如果它需要包中的任何目标文件,它现在已经得到了它们。它不需要包。
这是一个使用 GCC mingw-w64 工具链的插图 Windows DLL 导出的函数是从静态库中 link 编辑的:
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
hello.cpp
#include "hello.h"
#include <iostream>
void hello()
{
std::cout << "Hello world!" << std::endl;
}
hello.h
#ifndef HELLO_H
#define HELLO_H
extern __declspec(dllexport) void hello();
#endif
我们将编译hello.cpp
:
C:\develop\so\scrap>g++ -Wall -c -o hello.obj hello.cpp
同理:
niceday.cpp
#include "niceday.h"
#include <iostream>
void niceday()
{
std::cout << "What a nice day!" << std::endl;
}
niceday.h
#ifndef NICEDAY_H
#define NICEDAY_H
extern __declspec(dllexport) void niceday();
#endif
我们将编译niceday.cpp
C:\develop\so\scrap>g++ -Wall -c -o niceday.obj niceday.cpp
现在我们将把这两个目标文件放在一个静态库中。 libgreet.lib
ar rcs libgreet.lib hello.obj niceday.obj
另一个源文件和头文件:
greeting.cpp
#include "greeting.h"
#include "hello.h"
#include "niceday.h"
void greeting()
{
hello();
niceday();
}
greeting.h
#ifndef GREETING_H
#define GREETING_H
extern __declspec(dllexport) void greeting();
#endif
我们还将编译:
g++ -Wall -c -o greeting.obj greeting.cpp
现在我们将制作一个 DLL,libgreeting.dll
,使用 greeting.obj
和静态
图书馆 libgreet.lib
:
C:\develop\so\scrap>g++ -shared -o libgreeting.dll greeting.obj libgreet.lib
这里有一个程序源文件:
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;
}
我们还将编译:
C:\develop\so\scrap>g++ -Wall -c -o main.obj main.cpp
最后,我们将通过 link 将我们的 main.obj
与 libgreeting.dll
相结合来制作一个程序。
只有 和 libgreeting.dll
。
C:\develop\so\scrap>g++ -o prog main.obj libgreeting.dll
运行程序:
C:\develop\so\scrap>prog
Hello world!
What a nice day!
I said...
Hello world!
What a nice day!
所有三个 DLL 导出的函数,hello
、niceday
和 greeting
,
被称为。 要做到这一点,重要的是
声明为 __declspec(dllexport)
并且所有这些都被 link 编辑为 libgreeting.dll
不知何故。碰巧的是,其中两个 (hello
、niceday
) 是从静态库 link 编辑的,另一个 (greeting
) 是直接从静态库 link 编辑的目标文件:这无关紧要。
如果您有兴趣...
以下是使用 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
编译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
编译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
制作静态库:
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.
编译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
Link 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
在这里,如您所知,Microsoft linker 创建了一个 导入库 libgreeting.lib
(不要与静态库 libgreet.lib
混淆)用于
linking 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
Link 我们的程序(使用导入库 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.
和运行:
C:\develop\so\scrap>prog
Hello world!
What a nice day!
I said...
Hello world!
What a nice day!
以后
If
foo
firstly was compiled without__declspec(dllexport)
and has a declaration like thisvoid foo()
when I built B.lib. But when I built C.exe I changed foo's declaration to__declspec(dllexport) void foo()
. The question is can I still make above happen?
原则上,如果你编译一个目标文件,在它的头文件中声明foo
然后 更改 该声明随后 #include
中的头文件
编译一些其他的目标文件,那么你很可能在欺骗编译器
第二次编译,当你 link 这些目标文件变成一些程序或 DLL 时
可以预料到坏事的发生。
然而,在这种情况下,您可以侥幸逃脱。在上面的例子中,你
可以先用 hello.h
:
hello.cpp
extern void hello(void);
稍后,当你编译greeting.cpp
,其中#include
s hello.h
,你
可以将声明更改为:
extern __declspec(dllexport) void hello(void);
当您 link libgreeting.dll
.
hello
将 变为 DLL_exported
带有 __declspec(dllexport)
的声明完善了而不是与
那个没有。在 linking libgreeting.dll
中,linker 看到一个非 DLL 导出的引用
hello.obj
中的 hello
和 greeting.obj
中的 DLL 导出引用。它
DLL 导出该符号,因为它至少看到一个 DLL 导出的引用。
毫无疑问,这是一个 hack。