Exportieren Sie alle Symbole beim Erstellen einer DLL

71

Mit VS2005 möchte ich eine DLL erstellen und automatisch alle Symbole exportieren, ohne überall __declspec (dllexport) hinzuzufügen und ohne .def-Dateien von Hand zu erstellen. Gibt es eine Möglichkeit, dies zu tun?

Jazz
quelle

Antworten:

45

Es kann getan werden ...

Wir verwenden hier die Option / DEF des Linkers, um eine "Moduldefinitionsdatei" zu übergeben, die eine Liste unserer Exporte enthält. Ich sehe aus Ihrer Frage, dass Sie über diese Dateien Bescheid wissen. Wir machen es jedoch nicht von Hand. Die Liste der Exporte selbst wird mit dem Befehl dumpbin / LINKERMEMBER erstellt und die Ausgabe über ein einfaches Skript im Format einer Moduldefinitionsdatei bearbeitet.

Das Einrichten ist viel Arbeit, aber es ermöglicht uns, Code zu kompilieren, der ohne dllexport-Deklarationen für Unix unter Windows erstellt wurde.

Andrew Stein
quelle
11
In der Regel ist es besser, Exportmakros hinzuzufügen, die __declspec(dllexport)unter Windows, __attribute__ ((dllexport))gcc und auf anderen Compilern leer sind. Dann -fvisibility=hiddengcc weitergeben. Sie erhalten eine kleinere, übersichtlichere Symboltabelle und Fehler, die den Windows-Build beim Testen unter Linux beschädigen würden.
Craig Ringer
17
Das OP wollte nicht __declspec(dllexport)überall schreiben . Ebenso schwierig ist es, überall ein anderes Exportmakro hinzuzufügen.
Andrew Stein
39

Kurze Antwort

Sie können dies mit Hilfe der neuen Version von CMake tun (jede Version cmake-3.3.20150721-g9cd2f-win32-x86.exe oder höher).

Derzeit ist es in der Dev-Branche. Später wird die Funktion in der Release-Version von cmake-3.4 hinzugefügt.

Link zum cmake dev:

cmake_dev

Link zu einem Artikel, der die Technik beschreibt:

Erstellen Sie DLLs unter Windows ohne declspec () mit der neuen Funktion CMake export all

Link zu einem Beispielprojekt:

cmake_windows_export_all_symbols


Lange Antwort

Achtung: Alle folgenden Informationen beziehen sich auf den MSVC-Compiler oder Visual Studio.

Wenn Sie andere Compiler wie gcc unter Linux oder MinGW gcc compiler unter Windows verwenden, treten keine Verknüpfungsfehler aufgrund nicht exportierter Symbole auf, da der gcc-Compiler standardmäßig alle Symbole in einer dynamischen Bibliothek (DLL) anstelle von MSVC- oder Intel Windows-Compilern exportiert .

In Windows müssen Sie das Symbol explizit aus einer DLL exportieren.

Weitere Informationen hierzu finden Sie unter folgenden Links:

Exportieren aus einer DLL

HowTo: Exportieren Sie C ++ - Klassen aus einer DLL

Wenn Sie also alle Symbole mit MSVC (Visual Studio Compiler) aus der DLL exportieren möchten, haben Sie zwei Möglichkeiten:

  • Verwenden Sie das Schlüsselwort __declspec (dllexport) in der Definition der Klasse / Funktion.
  • Erstellen Sie eine Moduldefinitionsdatei (.def) und verwenden Sie die .def-Datei beim Erstellen der DLL.

1. Verwenden Sie das Schlüsselwort __declspec (dllexport) in der Definition der Klasse / Funktion


1.1. Fügen Sie einer Klasse oder Methode, die Sie verwenden möchten, die Makros "__declspec (dllexport) / __declspec (dllimport)" hinzu. Wenn Sie also alle Klassen exportieren möchten, sollten Sie diese Makros allen hinzufügen

Weitere Informationen hierzu finden Sie unter folgendem Link:

Exportieren aus einer DLL mit __declspec (dllexport)

Anwendungsbeispiel ("Projekt" durch echten Projektnamen ersetzen):

// ProjectExport.h

#ifndef __PROJECT_EXPORT_H
#define __PROJECT_EXPORT_H

#ifdef USEPROJECTLIBRARY
#ifdef  PROJECTLIBRARY_EXPORTS 
#define PROJECTAPI __declspec(dllexport)
#else
#define PROJECTAPI __declspec(dllimport)
#endif
#else
#define PROJECTAPI
#endif

#endif

Fügen Sie dann allen Klassen "PROJECTAPI" hinzu. Definieren Sie "USEPROJECTLIBRARY" nur, wenn Sie Symbole aus der DLL exportieren / importieren möchten. Definieren Sie "PROJECTLIBRARY_EXPORTS" für die DLL.

Beispiel für den Klassenexport:

#include "ProjectExport.h"

namespace hello {
    class PROJECTAPI Hello {}   
}

Beispiel für den Funktionsexport:

#include "ProjectExport.h"

PROJECTAPI void HelloWorld();

Achtung: Vergessen Sie nicht, die Datei "ProjectExport.h" einzuschließen.


1.2. Als C-Funktionen exportieren. Wenn Sie den C ++ - Compiler verwenden, um zu kompilieren, dass Code auf C geschrieben ist, können Sie externes "C" vor einer Funktion hinzufügen, um die Namensverfälschung zu beseitigen

Weitere Informationen zum Mangeln von C ++ - Namen finden Sie unter folgendem Link:

Namensdekoration

Anwendungsbeispiel:

extern "C" __declspec(dllexport) void HelloWorld();

Weitere Informationen hierzu finden Sie unter folgendem Link:

Exportieren von C ++ - Funktionen zur Verwendung in ausführbaren Dateien in C-Sprache


2. Erstellen Sie eine .def-Datei (Module Definition) und verwenden Sie beim Erstellen der DLL die .def-Datei

Weitere Informationen hierzu finden Sie unter folgendem Link:

Exportieren aus einer DLL mit DEF-Dateien

Weiter beschreibe ich drei Ansätze zum Erstellen einer .def-Datei.


2.1. C-Funktionen exportieren

In diesem Fall können Sie Funktionsdeklarationen einfach von Hand in die .def-Datei einfügen.

Anwendungsbeispiel:

extern "C" void HelloWorld();

Beispiel für eine .def-Datei (__cdecl-Namenskonvention):

EXPORTS 
_HelloWorld

2.2. Exportieren Sie Symbole aus der statischen Bibliothek

Ich habe den von "user72260" vorgeschlagenen Ansatz ausprobiert.

Er sagte:

  • Erstens könnten Sie eine statische Bibliothek erstellen.
  • Verwenden Sie dann "dumpbin / LINKERMEMBER", um alle Symbole aus der statischen Bibliothek zu exportieren.
  • Analysieren Sie die Ausgabe.
  • Fügen Sie alle Ergebnisse in eine .def-Datei ein.
  • Erstellen Sie eine DLL mit der .def-Datei.

Ich habe diesen Ansatz verwendet, aber es ist nicht sehr praktisch, immer zwei Builds zu erstellen (einen als statische und einen als dynamische Bibliothek). Ich muss jedoch zugeben, dass dieser Ansatz wirklich funktioniert.


2.3. Exportieren Sie Symbole aus OBJ-Dateien oder mithilfe von CMake


2.3.1. Mit CMake-Nutzung

Wichtiger Hinweis: Sie benötigen keine Exportmakros für Klassen oder Funktionen!

Wichtiger Hinweis: Sie können / GL ( Whole Program Optimization ) nicht verwenden, wenn Sie diesen Ansatz verwenden!

  • Erstellen Sie ein CMake-Projekt basierend auf der Datei "CMakeLists.txt".
  • Fügen Sie der Datei "CMakeLists.txt" die folgende Zeile hinzu: set (CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
  • Erstellen Sie dann mit Hilfe von "CMake (cmake-gui)" ein Visual Studio-Projekt.
  • Kompilieren Sie das Projekt.

Anwendungsbeispiel:

Root-Verzeichnis

CMakeLists.txt (Stammordner)

cmake_minimum_required(VERSION 2.6)
project(cmake_export_all)

set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

set(dir ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${dir}/bin")

set(SOURCE_EXE main.cpp)

include_directories(foo)

add_executable(main ${SOURCE_EXE})

add_subdirectory(foo)

target_link_libraries(main foo)

main.cpp (Stammordner)

#include "foo.h"

int main() {
    HelloWorld();

    return 0;
}

Foo-Ordner (Stammordner / Foo-Ordner)

CMakeLists.txt (Foo-Ordner)

project(foo)

set(SOURCE_LIB foo.cpp)

add_library(foo SHARED ${SOURCE_LIB})

foo.h (Foo-Ordner)

void HelloWorld();

foo.cpp (Foo-Ordner)

#include <iostream>

void HelloWorld() {
    std::cout << "Hello World!" << std::endl;
}

Nochmals Link zum Beispielprojekt:

cmake_windows_export_all_symbols

CMake verwendet den anderen Ansatz als "2.2. Symbole aus statischer Bibliothek exportieren".

Es macht folgendes:

1) Erstellen Sie die Datei "objects.txt" im Build-Verzeichnis mit Informationen zu OBJ-Dateien, die in einer DLL verwendet werden.

2) Kompilieren Sie die DLL, dh erstellen Sie OBJ-Dateien.

3) Basierend auf den Dateiinformationen "objects.txt" extrahieren Sie alle Symbole aus der OBJ-Datei.

Anwendungsbeispiel:

DUMPBIN /SYMBOLS example.obj > log.txt

Weitere Informationen hierzu finden Sie unter folgendem Link:

/ SYMBOLE

4) Analyse aus .obj-Dateiinformationen.

Meiner Meinung nach würde ich die Aufrufkonvektion verwenden, zum Beispiel "__cdecl / __ fastcall", "SECTx / UNDEF" -Symbolfeld (die dritte Spalte), "External / Static" -Symbolfeld (die fünfte Spalte), "??", "? "" Informationen zum Parsen von OBJ-Dateien.

Ich weiß nicht, wie genau CMake eine OBJ-Datei analysiert. CMake ist jedoch Open Source, sodass Sie herausfinden können, ob es für Sie interessiert ist.

Link zum CMake-Projekt:

CMake_github

5) Fügen Sie alle exportierten Symbole in eine .def-Datei ein.

6) Verknüpfen Sie eine DLL mit der Verwendung einer von .def erstellten Datei.

Schritte 4) -5), dh .obj-Dateien analysieren und eine .def-Datei erstellen, bevor die .def-Datei verknüpft und verwendet wird, die CMake mithilfe des "Pre-Link-Ereignisses" ausführt. Während das "Pre-Link-Ereignis" ausgelöst wird, können Sie jedes gewünschte Programm aufrufen. Bei "CMake-Verwendung" "Pre-Link-Ereignis" rufen Sie das CMake mit den folgenden Informationen darüber auf, wo die .def-Datei und wo die "objects.txt" -Datei abgelegt werden soll, und mit dem Argument "-E __create_def". Sie können diese Informationen überprüfen, indem Sie ein CMake Visusal Studio-Projekt mit "set (CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)" erstellen und dann die Projektdatei ".vcxproj" auf DLL überprüfen.

Wenn Sie versuchen, ein Projekt ohne "set (CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)" oder mit "set (CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF)" zu kompilieren, werden Verknüpfungsfehler angezeigt, da Symbole nicht aus einer DLL exportiert werden.

Weitere Informationen hierzu finden Sie unter folgendem Link:

Grundlegendes zu benutzerdefinierten Erstellungsschritten und Erstellungsereignissen


2.3.2. Ohne CMake-Nutzung

Sie können einfach ein kleines Programm zum Parsen der OBJ-Datei selbst ohne CMake-Verwendung erstellen. Hovewer, ich muss zugeben, dass CMake ein sehr nützliches Programm ist, insbesondere für die plattformübergreifende Entwicklung.

Maks
quelle
Das ist der wahre Deal! Vielen Dank.
fotinsky
Das sind großartige Informationen. Ich möchte nur hinzufügen, dass Option 1 genau das ist, was das OP nicht wollte. Option 2 beantwortet seine Frage. Insbesondere 2.3 sind die neuen Informationen über die akzeptierte Antwort und die von @ user72260.
Andrew Stein
Unter Windows verfügt der Linker ab Visual Studio 2015 Update 2 über die Option / WHOLEARCHIVE. Siehe docs.microsoft.com/en-us/cpp/build/reference/…
Bleater
Ich habe gerade versucht, mit dem Pre-Link-Event zu spielen. Scheint gut zu funktionieren. Vielen Dank! Unten ist ein Ergebnis meiner Experimente mit liblmdb. `dumpbin / SYMBOLS $ (Plattform) \ $ (Konfiguration) \ mdb.obj | findstr / R "(). * Extern. * mdb _. *"> $ (Plattform) \ $ (Konfiguration) \ mdb_symbols & (echo EXPORTS & for / F "usebackq tokens = 2 delims == |" %% E in ( type $(Platform)\$(Configuration)\mdb_symbols) do @echo %% E)> $ (Plattform) \ $ (Konfiguration) \ lmdb.def
Sergey
Für MingW-Benutzer gilt die Variable CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS in mehrdeutigen Namen nur für msvc.
Javs
8

Ich habe ein kleines Programm geschrieben, um die Ausgabe von "dumpbin / linkermember" in der .lib-Datei zu analysieren. Ich habe mehr als 8.000 Funktionsreferenzen zum Exportieren aus einer DLL.

Das Problem bei einer DLL besteht darin, dass Sie die DLL ohne die exportierten Definitionen einmal verknüpfen müssen, um die .lib-Datei zu erstellen, und dann die .def generieren müssen. Dies bedeutet, dass Sie die DLL jetzt erneut mit der .def-Datei verknüpfen müssen, um sie tatsächlich zu erstellen Lassen Sie die Referenzen exportieren.

Das Arbeiten mit statischen Bibliotheken ist einfacher. Kompilieren Sie alle Ihre Quellen in statische Bibliotheken, führen Sie dummin aus, generieren Sie mit Ihrem kleinen Programm eine .def und verknüpfen Sie die Bibliotheken zu einer DLL, sobald die Exportnamen verfügbar sind.

Leider erlaubt mir meine Firma nicht, Ihnen die Quelle zu zeigen. Die damit verbundene Arbeit besteht darin, zu erkennen, welche "öffentlichen Symbole" in der Dump-Ausgabe in Ihrer Def-Datei nicht benötigt werden. Sie müssen viele dieser Referenzen, NULL_IMPORT_DESCRIPTOR, NULL_THUNK_DATA, __imp * usw., wegwerfen.

user72260
quelle
Wie gehen Sie mit Vorlagen um, die Mitglieder in CPP-Dateien haben?
Rxantos
@rxantos - Verwenden Sie explizite Instanziierungen, um die Instanziierung vorab zu erzwingen. Oder stellen Sie sicher, dass es sich um eine reine Header-Implementierung handelt (die Sie anscheinend nicht haben).
JWW
@ user72260 - Erstellen Sie eine statische Bibliothek anstelle einer DLL mit denselben Objekten. Führen Sie dumpbin.exedie statische Bibliothek aus. Sie werden nicht haben NULL_IMPORT_DESCRIPTOR, NULL_THUNK_DATA, __imp*etc. Erstellen Sie dann die DLL mit den gleichen Objekten und die neuen DEF - Datei.
JWW
7

Ich möchte eine DLL erstellen und automatisch alle Symbole exportieren, ohne überall __declspec (dllexport) hinzuzufügen und ohne .def-Dateien von Hand zu erstellen. Gibt es eine Möglichkeit, dies zu tun?

Dies ist eine späte Antwort, enthält jedoch die Details für Maks 'Antwort in Abschnitt (2). Es vermeidet auch Skripte und verwendet ein C ++ - Programm namens dump2def. Der Quellcode für dump2defist unten.

Bei den folgenden Schritten wird davon ausgegangen, dass Sie über eine Visual Studio Developer-Eingabeaufforderung arbeiten , bei der es sich um ein Windows-Terminal handelt, auf dem vcvarsall.batausgeführt wurde. Sie müssen die Build - Tools wie um sicherzustellen cl.exe, lib.exe, link.exeund nmake.exesind auf dem Weg.

Weitere Informationen hierzu finden Sie unter folgendem Link:

Exportieren aus einer DLL mit DEF-Dateien
...

Die folgenden Anweisungen verwenden:

  • static.lib - statisches Bibliotheksarchiv (* .a Datei unter Linux)
  • dynamic.dll - dynamische Bibliothek (* .so-Datei unter Linux)
  • import.lib - Dynamische Bibliothek (Importbibliothek unter Windows)

Beachten Sie auch, dass Clients, obwohl Sie alles aus der DLL exportieren, immer noch declspec(dllimport)alle Symbole (Klassen, Funktionen und Daten) verwenden müssen, die sie verwenden. Siehe auch auf MSDN.

Nehmen Sie zuerst Ihre Objekte und erstellen Sie ein statisches Archiv:

AR = lib.exe
ARFLAGS = /nologo

CXX_SRCS = a.cpp b.cpp c.cpp ...
LIB_OBJS = a.obj b.obj c.obj ...

static.lib: $(LIB_OBJS)
    $(AR) $(ARFLAGS) $(LIB_OBJS) /out:$@

Führen Sie dumpbin.exe /LINKERMEMEBERzweitens das Archiv aus, um eine *.dumpDatei zu erstellen :

dynamic.dump:
    dumpbin /LINKERMEMBER static.lib > dynamic.dump

Drittens führen Sie dump2def.exedie *.dumpDatei aus, um die *.defDatei zu erstellen . Der Quellcode für dump2def.exeist unten.

dynamic.def: static.lib dynamic.dump
    dump2def.exe dynamic.dump dynamic.def

Viertens erstellen Sie die DLL:

LD = link.exe
LDFLAGS = /OPT:REF /MACHINE:X64
LDLIBS = kernel32.lib

dynamic.dll: $(LIB_OBJS) dynamic.def
    $(LD) $(LDFLAGS) /DLL /DEF:dynamic.def /IGNORE:4102 $(LIB_OBJS) $(LDLIBS) /out:$@

/IGNORE:4102wird verwendet, um diese Warnung zu vermeiden. Es wird in diesem Fall erwartet:

dynamic.def : warning LNK4102: export of deleting destructor 'public: virtual v
oid * __ptr64 __cdecl std::exception::`scalar deleting destructor'(unsigned int)
 __ptr64'; image may not run correctly

Wenn das dynamic.dllRezept aufgerufen wird, werden auch eine dynamic.libImportdatei und eine dynamic.expDatei erstellt:

> cls && nmake /f test.nmake dynamic.dll
...
Creating library dynamic.lib and object dynamic.exp

Und:

 C:\Users\Test\testdll>dir *.lib *.dll *.def *.exp
 Volume in drive C is Windows
 Volume Serial Number is CC36-23BE

 Directory of C:\Users\Test\testdll

01/06/2019  08:33 PM        71,501,578 static.lib
01/06/2019  08:33 PM        11,532,052 dynamic.lib

 Directory of C:\Users\Test\testdll

01/06/2019  08:35 PM         5,143,552 dynamic.dll

 Directory of C:\Users\Test\testdll

01/06/2019  08:33 PM         1,923,070 dynamic.def

 Directory of C:\Users\Test\testdll

01/06/2019  08:35 PM         6,937,789 dynamic.exp
               5 File(s)     97,038,041 bytes
               0 Dir(s)  139,871,186,944 bytes free

Wenn Sie es hier zusammenkleben, sieht das Nmake-Makefile so aus. Es ist Teil einer echten Nmake-Datei :

all: test.exe

test.exe: pch.pch static.lib $(TEST_OBJS)
    $(LD) $(LDFLAGS) $(TEST_OBJS) static.lib $(LDLIBS) /out:$@

static.lib: $(LIB_OBJS)
    $(AR) $(ARFLAGS) $(LIB_OBJS) /out:$@

dynamic.map:
    $(LD) $(LDFLAGS) /DLL /MAP /MAPINFO:EXPORTS $(LIB_OBJS) $(LDLIBS) /out:dynamic.dll

dynamic.dump:
    dumpbin.exe /LINKERMEMBER static.lib /OUT:dynamic.dump

dynamic.def: static.lib dynamic.dump
    dump2def.exe dynamic.dump

dynamic.dll: $(LIB_OBJS) dynamic.def
    $(LD) $(LDFLAGS) /DLL /DEF:dynamic.def /IGNORE:4102 $(LIB_OBJS) $(LDLIBS) /out:$@

clean:
    $(RM) /F /Q pch.pch $(LIB_OBJS) pch.obj static.lib $(TEST_OBJS) test.exe *.pdb

Und hier ist der Quellcode für dump2def.exe:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <set>

typedef std::set<std::string> SymbolMap;

void PrintHelpAndExit(int code)
{
    std::cout << "dump2def - create a module definitions file from a dumpbin file" << std::endl;
    std::cout << "           Written and placed in public domain by Jeffrey Walton" << std::endl;
    std::cout << std::endl;

    std::cout << "Usage: " << std::endl;

    std::cout << "  dump2def <infile>" << std::endl;
    std::cout << "    - Create a def file from <infile> and write it to a file with" << std::endl;
    std::cout << "      the same name as <infile> but using the .def extension" << std::endl;

    std::cout << "  dump2def <infile> <outfile>" << std::endl;
    std::cout << "    - Create a def file from <infile> and write it to <outfile>" << std::endl;

    std::exit(code);
}

int main(int argc, char* argv[])
{
    // ******************** Handle Options ******************** //

    // Convenience item
    std::vector<std::string> opts;
    for (size_t i=0; i<argc; ++i)
        opts.push_back(argv[i]);

    // Look for help
    std::string opt = opts.size() < 3 ? "" : opts[1].substr(0,2);
    if (opt == "/h" || opt == "-h" || opt == "/?" || opt == "-?")
        PrintHelpAndExit(0);

    // Add <outfile> as needed
    if (opts.size() == 2)
    {
        std::string outfile = opts[1];
        std::string::size_type pos = outfile.length() < 5 ? std::string::npos : outfile.length() - 5;
        if (pos == std::string::npos || outfile.substr(pos) != ".dump")
            PrintHelpAndExit(1);

        outfile.replace(pos, 5, ".def");
        opts.push_back(outfile);
    }

    // Check or exit
    if (opts.size() != 3)
        PrintHelpAndExit(1);

    // ******************** Read MAP file ******************** //

    SymbolMap symbols;

    try
    {
        std::ifstream infile(opts[1].c_str());
        std::string::size_type pos;
        std::string line;

        // Find start of the symbol table
        while (std::getline(infile, line))
        {
            pos = line.find("public symbols");
            if (pos == std::string::npos) { continue; }        

            // Eat the whitespace after the table heading
            infile >> std::ws;
            break;
        }

        while (std::getline(infile, line))
        {
            // End of table
            if (line.empty()) { break; }

            std::istringstream iss(line);
            std::string address, symbol;
            iss >> address >> symbol;

            symbols.insert(symbol);
        }
    }
    catch (const std::exception& ex)
    {
        std::cerr << "Unexpected exception:" << std::endl;
        std::cerr << ex.what() << std::endl;
        std::cerr << std::endl;

        PrintHelpAndExit(1);
    }

    // ******************** Write DEF file ******************** //

    try
    {
        std::ofstream outfile(opts[2].c_str());

        // Library name, cryptopp.dll
        std::string name = opts[2];
        std::string::size_type pos = name.find_last_of(".");

        if (pos != std::string::npos)
            name.erase(pos);

        outfile << "LIBRARY " << name << std::endl;
        outfile << "DESCRIPTION \"Crypto++ Library\"" << std::endl;        
        outfile << "EXPORTS" << std::endl;
        outfile << std::endl;

        outfile << "\t;; " << symbols.size() << " symbols" << std::endl;

        // Symbols from our object files
        SymbolMap::const_iterator it = symbols.begin();
        for ( ; it != symbols.end(); ++it)
            outfile << "\t" << *it << std::endl;
    }
    catch (const std::exception& ex)
    {
        std::cerr << "Unexpected exception:" << std::endl;
        std::cerr << ex.what() << std::endl;
        std::cerr << std::endl;

        PrintHelpAndExit(1);
    }   

    return 0;
}
jww
quelle
3

Danke @Maks für die ausführliche Antwort .

Unten ist ein Beispiel dafür, was ich im Pre-Link-Ereignis verwendet habe, um eine def-Datei aus obj zu generieren. Ich hoffe es wird für jemanden hilfreich sein.

dumpbin /SYMBOLS $(Platform)\$(Configuration)\mdb.obj | findstr /R "().*External.*mdb_.*" > $(Platform)\$(Configuration)\mdb_symbols
(echo EXPORTS & for /F "usebackq tokens=2 delims==|" %%E in (`type $(Platform)\$(Configuration)\mdb_symbols`) do @echo  %%E) > $(Platform)\$(Configuration)\lmdb.def

Grundsätzlich habe ich nur eines der Objekte (mdb.obj) genommen und mdb_ * -Funktionen erfasst. Dann analysierte Ausgabe, um nur Namen unter Berücksichtigung der Anzahl der Leerzeichen für Einrückungen beizubehalten (eines nach dem Aufteilen in Token und eines im Echo. Ich weiß jedoch nicht, ob es wichtig ist).

Das Skript der realen Welt wird jedoch wahrscheinlich etwas komplexer.

Sergey
quelle
0

Vielleicht findet jemand mein Python-Skript nützlich, um .dump in .def zu konvertieren.

import sys, os
functions = []
startPoint = False
# Exclude standard API like sprintf to avoid multiple definition link error
excluded_functions = [ 'sprintf', 'snprintf', 'sscanf', 'fprintf' ]

if len(sys.argv) < 2:
    print('Usage: %s <Input .dump file> <Output .def file>.' % sys.argv[0])
    print('Example: %s myStaticLib.dump exports.def' % sys.argv[0])
    sys.exit(1)
print('%s: Processing %s to %s' % (sys.argv[0], sys.argv[1], sys.argv[2]))

fin = open(sys.argv[1], 'r')
lines = fin.readlines()
fin.close()

# Reading
for l in lines:
    l_str = l.strip()
    if (startPoint == True) and (l_str == 'Summary'): # end point
        break
    if (startPoint == False) and ("public symbols" in l_str):
        startPoint = True
        continue
    if (startPoint == True) and l_str is not '':
        funcName = l_str.split(' ')[-1]
        if funcName not in excluded_functions:
            functions.append("    " + funcName)
# Writing
fout = open(sys.argv[2], 'w')
fout.write('EXPORTS\n')
for f in functions:
    fout.write('%s\n' % f)
fout.close()

Mit diesem Skript können Sie die .def-Datei für Ihre .lib in zwei Schritten abrufen:

dumpbin /LINKERMEMBER:1 myStaticLib.lib > myExports.dump
python dump2def.py myExports.dump myExports.def
Alexander Samoylov
quelle
-3

Nein, Sie benötigen ein Makro, das aufgelöst wird, __declspec(dllexport)wenn es in der CPP-Datei enthalten ist, die die exportierten Funktionen implementiert, und __declspec(dllimport)andernfalls aufgelöst wird.

Adam Mitz
quelle