gpt4 book ai didi

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

转载 作者:可可西里 更新时间:2023-11-01 17:37:46 25 4
gpt4 key购买 nike

在 win32 上,我构建了一个名为 的动态库A.dll 它链接到一个名为 的静态库B.lib ,还构建了一个名为 的可执行文件C.exe 其中只有依赖 A.dll .

但是现在,在 C.exe 如果我想使用函数 foo 仅在 中有定义B.lib ,我要链接 C.exe 反对 B.lib 再次。

问题是我可以导出吗? foo 来自 B.lib 直接进入 A.dll 建时 A.dll , 如何?

我也想知道在处理 GCC 时会发生什么。

最佳答案

一个函数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 没有依赖关系
    在静态库上。如果它需要包中的任何目标文件,它现在已经得到了。它不需要袋子。

    这是使用适用于 Windows 的 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

    你好.cpp
    #include "hello.h"
    #include <iostream>

    void hello()
    {
    std::cout << "Hello world!" << std::endl;
    }

    你好.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

    另一个源文件和标题:

    问候.cpp
    #include "greeting.h"
    #include "hello.h"
    #include "niceday.h"

    void greeting()
    {
    hello();
    niceday();
    }

    问候.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

    最后,我们将通过链接我们的 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 , nicedaygreeting ,
    叫做。要让这一切发生,最重要的是,他们都是
    声明 __declspec(dllexport)并且所有这些都链接到 libgreeting.dll不知何故。碰巧的是,其中两个( helloniceday )是从静态库链接的,另一个( 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

    编译 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

    友情链接 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 链接器在这里创建了一个导入库 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

    链接我们的程序(使用导入库 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头文件中的
    编译其他一些目标文件,那么你很可能在对编译器撒谎
    第二次编译,当您将这些目标文件链接到某个程序或 DLL 时
    可以期待坏事发生。

    但是,在这种情况下,您可以摆脱它。在上面的例子中,你
    可以先编译,比如说, hello.cpp声明在 hello.h :
    extern void hello(void);

    后来编译 greeting.cpp的时候, 其中 #include s hello.h , 你
    可以将声明更改为:
    extern __declspec(dllexport) void hello(void);

    结果是 hello链接时将被 DLL_exported libgreeting.dll .

    __declspec(dllexport)的声明细化而不是反驳
    没有的。在链接中 libgreeting.dll ,链接器看到一个非 DLL 导出的引用
    hellohello.obj以及 greeting.obj 中的 DLL 导出引用.它
    DLL 导出该符号,因为它已经看到至少一个 DLL 导出的引用。

    毫无疑问,这是一个黑客。

    关于c++ - 在构建链接到静态库的动态库时,我可以导出静态库的函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47791319/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com