Exporter tous les symboles lors de la création D'une DLL

Avec VS2005, je veux créer une DLL et exporter automatiquement tous les symboles sans ajouter __declspec(dllexport) partout et sans créer à la main .fichiers def. Threre est-il un moyen de le faire?

57
demandé sur tzot 2008-10-22 15:48:47

5 réponses

Cela peut être fait...

La façon dont nous le faisons ici est d'utiliser l'option /DEF de l'éditeur de liens pour passer un "fichier de définition de module" contenant une liste de nos exportations. Je vois de votre question que vous connaissez ces fichiers. Cependant, nous ne le faisons pas à la main. La liste des exportations elle - même est créée par la commande dumpbin /LINKERMEMBER, et la manipulation de la sortie via un script simple au format d'un fichier de définition de module.

C'est beaucoup de travail à configurer, mais il permet de compiler du code créé sans déclarations dllexport pour Unix sous Windows.

35
répondu Andrew Stein 2016-10-28 17:23:58

Réponse Courte

Vous pouvez le faire avec l'aide de la nouvelle version du CMake (toute version cmake-3.3.20150721-g9cd2f-win32-x86.exe ou plus).

Actuellement, il est dans la branche dev. Plus tard, la fonctionnalité sera ajoutée dans la version de cmake-3.4.

Lien vers le dev cmake:

Cmake_dev

Lien vers un article qui décrit la technique:

Créer des dll sous Windows sans declspec () en utilisant New cmake export all fonction

Lien vers un exemple de projet:

Cmake_windows_export_all_symbols


Réponse Longue

Attention: Toutes les informations ci-dessous sont liées au compilateur MSVC ou Visual Studio.

Si vous utilisez d'autres compilateurs comme gcc sous Linux ou le compilateur gcc MinGW sous Windows, vous n'avez pas d'erreurs de liaison dues à des symboles non exportés, car le compilateur gcc exporte tous les symboles dans une bibliothèque dynamique (dll) par défaut au lieu de MSVC ou Compilateurs Intel windows.

Dans windows, vous devez exporter explicitement le symbole à partir d'une dll.

Plus d'informations à ce sujet sont fournies par links:

L'Exportation à partir d'une DLL

HowTo: exporter des classes C++ à partir d'une DLL

Donc, si vous voulez exporter tous les symboles de dll avec MSVC (Visual Studio compiler), vous avez deux options:

  • utilisez le mot clé _ _ declspec (dllexport) dans la définition de la classe/fonction.
  • créer un définition du module (.Def) fichier et utiliser le .fichier def lors de la construction de la DLL.

1. Utilisez le mot clé _ _ declspec(dllexport) dans la définition de la classe/fonction


1.1. Ajoutez des macros" __declspec(dllexport) / __declspec(dllimport) " à une classe ou à une méthode que vous souhaitez utiliser. Donc, si vous voulez exporter toutes les classes, vous devez ajouter ces macros à toutes

Plus d'informations à ce sujet est fourni par Lien:

Exportation à partir d'une DLL Utiliser _ _ declspec (dllexport)

Exemple d'utilisation (remplacer "projet" par le nom réel du projet):

// 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

Ajoutez ensuite "PROJECTAPI" à toutes les classes. Définissez "USEPROJECTLIBRARY" uniquement si vous souhaitez exporter / importer des symboles de dll. Définissez "PROJECTLIBRARY_EXPORTS" pour la dll.

Exemple d'exportation de classe:

#include "ProjectExport.h"

namespace hello {
    class PROJECTAPI Hello {}   
}

Exemple d'exportation de fonction:

#include "ProjectExport.h"

PROJECTAPI void HelloWorld();

Attention: n'oubliez pas d'inclure "ProjectExport.h" fichier.


1.2. Exportation comme C fonctions. Si vous utilisez le compilateur C++ pour que le code de compilation soit écrit sur C, vous pouvez ajouter extern "C" devant une fonction pour éliminer la modification des noms

Plus d'informations sur C++ nom mangling est fourni par link:

Nom Décoration

Exemple d'utilisation:

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

Plus d'informations à ce sujet est fourni par Lien:

Exportation de fonctions C++ à utiliser dans les exécutables en langage C


2. Créer un module définition (.Def) fichier et utiliser le .fichier def lors de la construction de la DLL

Plus d'informations à ce sujet est fourni par Lien:

Exportation à partir d'une DLL à L'aide de fichiers DEF

En outre, je décris trois approches sur la façon de créer .fichier def.


2.1. Exporter les fonctions C

Dans ce cas, vous pouvez simplement ajouter des déclarations de fonction dans le .fichier def à la main.

Exemple d'utilisation:

extern "C" void HelloWorld();

Exemple de .fichier def (__convention de nommage cdecl):

EXPORTS 
_HelloWorld

2.2. Exporter les symboles de la bibliothèque statique

J'ai essayé l'approche suggérée par "user72260".

Il a dit:

  • tout d'abord, vous pouvez créer une bibliothèque statique.
  • ensuite, utilisez "dumpbin / LINKERMEMBER" pour exporter tous les symboles de la bibliothèque statique.
  • analysez la sortie.
  • mettez tous les résultats dans un.fichier def.
  • créer dll avec le .fichier def.

, j'ai utilisé cette approche, mais ce n'est pas très pratique à toujours créer deux versions (l'une statique et l'autre dynamique de la bibliothèque). Cependant, je dois admettre que cette approche fonctionne vraiment.


2.3. Exporter les symboles de .fichiers obj ou avec L'aide du CMake


2.3.1. Avec CMake utilisation

Avis Important: vous n'avez pas besoin de macros d'exportation vers des classes ou des fonctions a!

Avis Important: vous ne pouvez pas utiliser /GL (programme entier Optimisation ) lorsque vous utilisez cette approche!

  • créez un projet CMake basé sur les " CMakeLists.txt " fichier.
  • ajoutez la ligne suivante aux " CMakeLists.txt" un fichier: set (CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
  • ensuite, créez un projet Visual Studio à l'aide de "CMake (cmake-gui)".
  • compiler le projet.

Exemple d'utilisation:

dossier Racine

CMakeLists.txt (dossier racine)

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)

Principal.rpc (Racine dossier)

#include "foo.h"

int main() {
    HelloWorld();

    return 0;
}

dossier Foo (dossier racine / dossier Foo)

CMakeLists.txt (dossier Foo)

project(foo)

set(SOURCE_LIB foo.cpp)

add_library(foo SHARED ${SOURCE_LIB})

Foo.h (dossier Foo)

void HelloWorld();

Foo.cpp (dossier Foo)

#include <iostream>

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

Lien vers l'exemple de projet à nouveau:

Cmake_windows_export_all_symbols

CMake utilise le différent de " 2.2. Exporter les symboles de la bibliothèque statique " approche.

Il fait ce qui suit:

1) Créer " Objets.txt" un fichier dans le construire le répertoire avec des informations de .les fichiers obj sont utilisés dans une dll.

2) compiler la dll, c'est-à-dire créer .les fichiers obj.

3) basé sur " objets.les informations du fichier" txt " extraient tous les symboles .fichier obj.

Exemple d'utilisation:

DUMPBIN /SYMBOLS example.obj > log.txt

Plus d'informations à ce sujet est fourni par Lien:

/symboles

4) Analyse extraite de .informations sur le fichier obj.

À mon avis, j'utiliserais la convection d'appel, par exemple "__cdecl / _ _ fastcall"," SECTx/UNDEF " champ de symbole (la troisième colonne)," externe/statique "champ de symbole (la cinquième colonne),"??", "?"informations pour l'analyse d'un .les fichiers obj.

Je ne sais pas exactement comment CMake analyse un .fichier obj. Cependant, CMake est open source, vous pouvez donc savoir si cela vous intéresse.

Lien vers le projet CMake:

CMake_github

5) Mettre tous les symboles exportés dans un .fichier def.

6) lier une dll avec l'utilisation d'un .def fichier créé.

Étapes 4)-5), c'est-à analyser .fichiers obj et créer un .fichier def avant de lier et d'utiliser le .fichier def CMake fait avec l'aide de "événement pré-lien". Alors que" événement pré-lien " se déclenche, vous pouvez appeler n'importe quel programme que vous voulez. Donc, en cas de" utilisation CMake "" événement pré-lien " appelez le CMake avec les informations suivantes sur l'endroit où mettre le .fichier def et où les "objets.txt "fichier et avec argument" - e_ _ create _ Def". Vous pouvez vérifier ces informations en créant CMake Visusal Studio projet avec "set (CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) "puis vérifiez le".VCXPROJ " fichier de projet pour dll.

Si vous essayez de compiler un projet sans " set (CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)" ou avec "set (CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF)" vous obtiendrez des erreurs de liaison, en raison du fait que les symboles ne sont pas exportés à partir d'une dll.

Plus d'informations à ce sujet est fourni par Lien:

Comprendre les étapes de construction personnalisées et construire Les événements


2.3.2. Sans utilisation CMake

Vous pouvez simplement créer un petit programme pour l'analyse.obj fichier par vous-même sans CMake usege. Hovewer, je dois admettre que CMake est un programme très utile en particulier pour le développement multi-plateforme.

25
répondu Maks 2017-11-26 01:00:23

J'ai écrit un petit programme pour analyser la sortie de "dumpbin / linkermember" sur le .fichier lib. J'ai plus de 8 000 références de fonction à exporter à partir d'une DLL.

Le problème avec le faire sur une DLL est que vous devez lier la DLL sans les définitions exportées une fois pour créer le .fichier lib, puis générer le .def ce qui signifie que vous devez maintenant relier à nouveau la DLL avec le .fichier def pour avoir réellement les références exportées.

Travailler avec des bibliothèques statiques est plus facile. Compilez toutes vos sources dans des bibliothèques statiques, exécutez dumbin, générez un .def avec votre petit programme, puis liez les libs ensemble dans une DLL maintenant que les noms d'exportation sont disponibles.

Malheureusement, ma société ne me permettra pas de vous montrer la source. Le travail impliqué est de reconnaître quels "symboles publics" dans la sortie de vidage ne sont pas nécessaires dans votre fichier def. Vous devez jeter beaucoup de ces références, NULL_IMPORT_DESCRIPTOR, NULL_THUNK_DATA, _ _ imp*, etc.

8
répondu user72260 2009-04-08 20:50:16

Merci @Maks pour la réponse détaillée .

Voici un exemple de ce que j'ai utilisé dans l'événement Pre-Link pour générer un fichier DEF à partir d'obj. J'espère que ce sera utile pour quelqu'un.

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

Fondamentalement, je viens de prendre un des objets (mdb.obj) et les fonctions mdb_* gripped. Ensuite, la sortie analysée pour garder seulement les noms en tenant compte de la quantité d'espaces pour l'indentation (un après la division en jetons et un autre en écho. Je ne sais pas si c'est grave).

Script du monde réel probablement sera un peu plus complexe Cependant.

0
répondu Sergey 2018-04-18 05:28:05

Non, vous aurez besoin d'une macro qui se résout à __declspec(dllexport) quand elle est incluse par le .fichier cpp qui implémente les fonctions exportées, et se résout à __declspec(dllimport) sinon.

-3
répondu Adam Mitz 2015-05-15 14:24:36