代码之家  ›  专栏  ›  技术社区  ›  Francis

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

  •  14
  • Francis  · 技术社区  · 7 年前

    在win32上,我构建了一个名为 A、 dll 它与一个名为 B、 lib公司 ,还构建了一个名为 C、 exe文件 哪一个 只有 依赖于 A、 dll .

    但是现在,在 C、 exe文件 如果我想使用函数 其定义仅限于 B、 lib公司 ,我必须链接 C、 exe文件 反对 B、 lib公司 再一次

    问题是我能出口吗 从…起 B、 lib公司 直接进入 A、 dll 建造时 A、 dll ,如何?

    另外,我想知道当处理GCC时会是什么情况。

    1 回复  |  直到 6 年前
        1
  •  15
  •   Mike Kinghan Luchian Grigore    7 年前

    A函数 foo

    • 您声明 __declspec(dllexport) 属性时 将函数编译成一个对象文件,例如 foo.obj

    • 你链接 傅。obj公司 进入DLL。

    不管怎样 傅。obj公司 链接到DLL。

    也许你可以指定 傅。obj公司 显式地在DLL的链接中。

    也许你把 傅。obj公司 在静态库中,比如说 foobar.lib ,以及联动装置 的DLL包含对函数的一些引用 . 然后链接器将 傅。obj公司 福巴。lib公司 并将其链接到DLL中,以解决 参考文献。

    如果 傅。obj公司 通过从静态库中提取链接 完全一样 傅。obj公司 按名称链接。静态库只是 链接器可以从中选择需要携带的对象文件包 在联动装置上。链接完成后,生成的程序或DLL没有依赖关系 在静态库上。如果它需要包中的任何对象文件,它现在已经得到了它们。它不需要袋子。

    下面是一个使用GCC mingw-w64工具链for Windows的示例,说明了 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
    

    你好清洁石油产品

    #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
    

    类似地:

    祝你愉快。清洁石油产品

    #include "niceday.h"
    #include <iostream>
    
    void niceday()
    {
        std::cout << "What a nice day!" << std::endl;
    }
    

    祝你愉快。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
    

    另一个源文件和头:

    招呼清洁石油产品

    #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 还有静电 图书馆 利布雷特。lib公司 :

    C:\develop\so\scrap>g++ -shared -o libgreeting.dll greeting.obj libgreet.lib
    

    这里有一个程序源文件:

    #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 具有 LIB问候语。dll . 只有 具有 LIB问候语。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) 所有这些都与 LIB问候语。dll 以某种方式 . 碰巧有两个( 你好 , 尼斯戴 )从静态库和另一个( 招呼 )直接从对象文件链接:这无关紧要。

    如果你有兴趣。。。

    下面是如何使用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
    

    编写 你好清洁石油产品 :

    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
    

    编写 祝你愉快。清洁石油产品 :

    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
    

    链接 LIB问候语。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 利布雷特。lib公司 )用于 链接 LIB问候语。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
    

    链接我们的程序(使用导入库 LIB问候语。lib公司 代替 LIB问候语。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: \开发\销售订单\报废>掠夺
    你好,世界!
    多好的一天啊!
    我说。。。
    你好,世界!
    多好的一天啊!
    

    后来

    如果 第一次编译时没有 __declspec(dllexport) 有这样的声明 void foo() 当我构建B.lib时。 但是当我构建C.exe时,我将foo的声明更改为 __declspec(dllexport) void foo() . 问题是,我还能做到这一点吗?

    原则上,如果编译具有特定声明的对象文件 在其头文件中 然后 改变 该声明随后 #include 中的头文件 编译其他一些对象文件,那么您很可能在 可以预料坏事会发生。

    然而,在这种情况下,你可以逍遥法外。在上面的示例中,您 可以先编译, 你好清洁石油产品 在声明中 hello.h :

    extern void hello(void);
    

    稍后,当您编译时 招呼清洁石油产品 哪一个 #包括 s 你好h 你 可将声明更改为:

    extern __declspec(dllexport) void hello(void);
    

    你好 链接时导出DLL\U LIB问候语。dll .

    声明与 __declspec(dllexport) 精炼而不是矛盾 没有的那个。在链接中 LIB问候语。dll ,链接器会看到非DLL导出的引用 你好 在里面 hello.obj 以及在中导出的DLL引用 招呼obj公司 . 它 DLL导出符号,因为它至少看到一个DLL导出的引用。

    毫无疑问,这是一个 乱劈 .