web-dev-qa-db-ja.com

静的ライブラリにリンクする動的ライブラリを構築するときに、静的ライブラリの関数をエクスポートできますか?

Win32では、 A.dll と呼ばれる動的ライブラリを構築し、 B.lib と呼ばれる静的ライブラリにリンクし、実行可能ファイルも構築しましたC.exeと呼ばれ、 only A.dllに依存します。

しかし今、 C.exe foo を使用する場合は、 B.libでのみ定義されています。 C.exeB.libに対して再度リンクする必要があります。

問題は、 foo B.libからA.dllに直接エクスポートできるかどうかです。 A.dllをビルドして、どうやって?

また、私はGCCを扱うときにそれがどうなるか知りたいです。

10
Francis

関数fooは、DLL=

  • 関数をオブジェクトファイルにコンパイルするときに、foo__declspec(dllexport)属性で宣言します。たとえば、_foo.obj_と宣言します。

  • _foo.obj_をDLLにリンクします。

_foo.obj_がDLLにリンクされる方法は問題ではありません。

DLLのリンケージで_foo.obj_を明示的に指定する可能性があります。

多分あなたは_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
_

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
_

次に、これら2つのオブジェクトファイルを静的ライブラリに配置します。 _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
_

次に、_libgreeting.dll_と静的ライブラリ_greeting.obj_を使用して、DLL _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でエクスポートされた3つの関数hellonicedayおよびgreetingが呼び出されます。 重要なことこれが発生するためには、それらすべてが__declspec(dllexport)として宣言され、それらすべてが_libgreeting.dll_にリンクされたということですsomehow 。たまたま、そのうちの2つ(helloniceday)は静的ライブラリからリンクされ、もう1つ(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!
_

後で

fooが最初に__declspec(dllexport)なしでコンパイルされ、B.libをビルドしたときにこのvoid foo()のような宣言がある場合しかし、C.exeをビルドしたとき、fooの宣言を__declspec(dllexport) void foo()に変更しました。問題は、私がまだ上記を実現できるかどうかです

原則として、ヘッダーファイルでfooの特定の宣言を使用してオブジェクトファイルをコンパイルし、次にchange _#include_に続いてその宣言をコンパイルした場合、他のオブジェクトファイルの場合、2回目のコンパイルでコンパイラに嘘をついている可能性が高く、これらのオブジェクトファイルをいくつかのプログラムまたはDLLにリンクすると、悪いことが発生する可能性があります。

ただし、この場合は、問題を回避できます。上記の例では、まず_hello.cpp_の宣言を使用して_hello.h_をコンパイルできます。

_extern void hello(void);
_

後で_greeting.cpp_をコンパイルするとき、その_#include_ s _hello.h_を宣言するときに、宣言を次のように変更できます。

_extern __declspec(dllexport) void hello(void);
_

_libgreeting.dll_をリンクすると、hellowillがDLL_exportされるという結果になります。

__declspec(dllexport)を使用した宣言は、使用しないものと矛盾するのではなく、改良されます。 _libgreeting.dll_をリンクすると、リンカーは_hello.obj_のhelloへの非DLLエクスポート参照と_greeting.obj_のDLLエクスポート参照を参照します。少なくとも1つのDLLでエクスポートされた参照を確認したため、シンボルをDLLでエクスポートします。

これがhackであることは間違いありません。

13
Mike Kinghan