Réponse courte
Vous pouvez le faire à l'aide de la nouvelle version de CMake (toute version cmake-3.3.20150721-g9cd2f-win32-x86.exe ou supérieure).
Actuellement, elle se trouve dans la branche dev. Plus tard, la fonctionnalité sera ajoutée dans la version release de cmake-3.4.
Lien vers le dev. cmake :
cmake_dev
Lien vers un article qui décrit la technique :
Créer des dlls sous Windows sans declspec() en utilisant la nouvelle fonctionnalité CMake export all
Lien vers un exemple de projet :
cmake_windows_export_all_symbols
Réponse longue
Attention : Toutes les informations ci-dessous concernent le compilateur MSVC ou Visual Studio.
Si vous utilisez d'autres compilateurs comme gcc sous Linux ou le compilateur MinGW gcc sous Windows, vous n'aurez 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 à la place des compilateurs MSVC ou Intel Windows.
Sous Windows, vous devez exporter explicitement le symbole d'une dll.
De plus amples informations à ce sujet sont fournies par des liens :
Exportation à partir d'une DLL
Comment faire : Exporter les classes C++ d'une DLL
Ainsi, si vous souhaitez exporter tous les symboles d'une dll avec MSVC (compilateur Visual Studio), vous avez deux possibilités :
- Utilisez le mot-clé __declspec(dllexport) dans la définition de la classe/fonction.
- Créez un fichier de définition de module (.def) et utilisez 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 les macros "__declspec(dllexport) / __declspec(dllimport)" à une classe ou une méthode que vous voulez utiliser. Ainsi, si vous voulez exporter toutes les classes, vous devez ajouter les macros suivantes à chacune d'entre elles
Plus d'informations à ce sujet sont fournies par le lien :
Exportation à partir d'une DLL en utilisant __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
Ensuite, ajoutez "PROJECTAPI" à toutes les classes. Définir "USEPROJECTLIBRARY" seulement si vous voulez exporter/importer des symboles de la dll. Définir "PROJECTLIBRARY_EXPORTS" pour la dll.
Exemple d'exportation de classe :
#include "ProjectExport.h"
namespace hello {
class PROJECTAPI Hello {}
}
Exemple d'exportation de fonctions :
#include "ProjectExport.h"
PROJECTAPI void HelloWorld();
Attention : n'oubliez pas d'inclure le fichier "ProjectExport.h".
1.2. Exportation en tant que fonctions C. Si vous utilisez le compilateur C++ pour compiler du code écrit en C, vous pouvez ajouter extern "C" devant une fonction pour éliminer la confusion des noms.
Plus d'informations sur la manipulation des noms C++ sont fournies par le lien :
Décoration du nom
Exemple d'utilisation :
extern "C" __declspec(dllexport) void HelloWorld();
Plus d'informations à ce sujet sont fournies par le lien :
Exportation de fonctions C++ pour utilisation dans des exécutables en langage C
2. Créez un fichier de définition de module (.def) et utilisez le fichier .def lors de la construction de la DLL.
Plus d'informations à ce sujet sont fournies par le lien :
Exportation à partir d'une DLL en utilisant les fichiers DEF
Je décris ensuite trois approches pour créer un fichier .def.
2.1. Fonctions d'exportation C
Dans ce cas, vous pouvez simplement ajouter des déclarations de fonctions dans le fichier .def à la main.
Exemple d'utilisation :
extern "C" void HelloWorld();
Exemple de fichier .def (convention de dénomination __cdecl) :
EXPORTS
_HelloWorld
2.2. Exportation des 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.
- Utilisez ensuite "dumpbin /LINKERMEMBER" pour exporter tous les symboles de la bibliothèque statique.
- Analyse la sortie.
- Mettez tous les résultats dans un fichier .def.
- Créer une dll avec le fichier .def.
J'ai utilisé cette approche, mais ce n'est pas très pratique de toujours créer deux builds (un en tant que bibliothèque statique et l'autre en tant que bibliothèque dynamique). Cependant, je dois admettre que cette approche fonctionne vraiment.
2.3. Exporter les symboles à partir de fichiers .obj ou avec l'aide de CMake.
2.3.1. Avec l'utilisation de CMake
Avis important : Vous n'avez pas besoin d'exporter des macros vers des classes ou des fonctions !
Avis important : Vous ne pouvez pas utiliser /GL ( Optimisation de l'ensemble du programme ) lorsqu'on utilise cette approche !
- Créer un projet CMake basé sur le fichier "CMakeLists.txt".
- Ajoutez la ligne suivante au fichier "CMakeLists.txt" : set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
- Ensuite, créez un projet Visual Studio avec l'aide de "CMake (cmake-gui)".
- Compilez 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)
main.cpp (Dossier racine)
#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;
}
Reliez à nouveau le projet d'exemple :
cmake_windows_export_all_symbols
CMake utilise une approche différente de celle de "2.2. Exporter les symboles de la bibliothèque statique".
Il fait ce qui suit :
1) Créer un fichier "objects.txt" dans le répertoire de construction avec des informations sur les fichiers .obj utilisés dans une dll.
2) Compiler la dll, c'est-à-dire créer des fichiers .obj.
3) Sur la base des informations du fichier "objects.txt", extraire tous les symboles du fichier .obj.
Exemple d'utilisation :
DUMPBIN /SYMBOLS example.obj > log.txt
Plus d'informations à ce sujet sont fournies par le lien :
/SYMBOLS
4) Analyse des informations extraites du fichier .obj.
A mon avis, j'utiliserais la convection d'appel, par exemple "__cdecl/__fastcall", le champ de symbole "SECTx/UNDEF" (la troisième colonne), le champ de symbole "External/Static" (la cinquième colonne), les informations " ??", " ?" pour le parsing d'un fichier .obj.
Je ne sais pas exactement comment CMake analyse un fichier .obj. Cependant, CMake est open source, donc vous pourriez trouver si cela vous intéresse.
Lien vers le projet CMake :
CMake_github
5) Mettez tous les symboles exportés dans un fichier .def.
6) Lier une dll avec l'utilisation d'un fichier .def créé.
Les étapes 4)-5), c'est-à-dire analyser les fichiers .obj et créer un fichier .def avant de lier et d'utiliser le fichier .def, CMake le fait avec l'aide de "Pre-Link event". Pendant que "Pre-Link event" se déclenche, vous pouvez appeler n'importe quel programme que vous voulez. Ainsi, dans le cas de l'utilisation de CMake, l'événement "Pre-Link" appelle CMake avec les informations suivantes : où placer le fichier .def et où placer le fichier "objects.txt" et avec l'argument "-E __create_def". Vous pouvez vérifier cette information en créant un projet CMake Visusal Studio avec "set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)" et ensuite vérifier le fichier ".vcxproj" pour la 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, dues au fait que les symboles ne sont pas exportés depuis une dll.
Plus d'informations à ce sujet sont fournies par le lien :
Comprendre les étapes de construction personnalisées et les événements de construction
2.3.2. Sans utilisation de CMake
Vous pourriez simplement créer un petit programme pour analyser les fichiers .obj par vous-même sans utiliser CMake. Cependant, je dois admettre que CMake est un programme très utile, surtout pour le développement multiplateforme.