在构建链接静态库的动态库时,我可以导出静态库的函数吗?

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 再次.

问题是我可以将 fooB.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.objlibgreeting.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 导出的函数,hellonicedaygreeting, 被称为。 要做到这一点,重要的是 声明为 __declspec(dllexport) 并且所有这些都被 link 编辑为 libgreeting.dll 不知何故。碰巧的是,其中两个 (helloniceday) 是从静态库 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,其中#includes hello.h,你 可以将声明更改为:

extern __declspec(dllexport) void hello(void);

当您 link libgreeting.dll.

时,hello 变为 DLL_exported

带有 __declspec(dllexport) 的声明完善了而不是与 那个没有。在 linking libgreeting.dll 中,linker 看到一个非 DLL 导出的引用 hello.obj 中的 hellogreeting.obj 中的 DLL 导出引用。它 DLL 导出该符号,因为它至少看到一个 DLL 导出的引用。

毫无疑问,这是一个 hack