web-dev-qa-db-fra.com

Comment créer une bibliothèque?

Disons que j'ai 10 fichiers * .hpp et * .cpp dont j'ai besoin pour compiler un code. Je sais que j'aurai besoin de ces mêmes fichiers pour de nombreux codes différents. Puis-je créer un "package" avec ces fichiers qui me permettrait d'écrire simplement

#include<mypackage>

au lieu de

#include"file1.hpp"
#include"file2.hpp"
...
#include"file10.hpp"

Je n'aurais alors pas besoin d'écrire un makefile chaque fois que j'ai besoin de ce "paquet".

Pour être plus précis, j'utilise linux.

17
PinkFloyd

Une collection de sources CPP (fichiers H et fichiers CPP) peut être compilée dans une "bibliothèque", qui peut ensuite être utilisée dans d'autres programmes et bibliothèques. Les détails de la procédure à suivre sont spécifiques à la plate-forme et à la chaîne d'outils. Je vous laisse donc le soin de découvrir les détails. Cependant, je vais vous fournir quelques liens que vous pouvez lire:

Création d'une bibliothèque partagée et statique avec le compilateur gnu [gcc]

Procédure pas à pas: création et utilisation d'une bibliothèque de liens dynamiques (C++)

Les bibliothèques peuvent être séparées en deux types: les bibliothèques de code source et les bibliothèques binaires. Il peut également y avoir des hybrides de ces deux types - une bibliothèque peut être à la fois une bibliothèque source et une bibliothèque binaire. Les bibliothèques de code source sont simplement les suivantes: une collection de code distribuée sous forme de code source uniquement; typiquement les fichiers d'en-tête. La plupart des bibliothèques Boost sont de ce type. Les bibliothèques binaires sont compilées dans un paquet qui peut être chargé à l'exécution par un programme client.

Même dans le cas de bibliothèques binaires (et évidemment dans le cas de bibliothèques sources), un fichier d’en-tête (ou plusieurs fichiers d’en-tête) doit être fourni à l’utilisateur de la bibliothèque. Cela indique au compilateur du programme client quelles fonctions, etc., rechercher dans la bibliothèque. Ce qui est souvent fait par les rédacteurs de bibliothèque, c’est un fichier d’en-tête unique composé de déclarations de tout ce qui est exporté par la bibliothèque, et le client #include cet en-tête. Plus tard, dans le cas de bibliothèques binaires, le programme client "se liera" à la bibliothèque, ce qui résoudra tous les noms mentionnés dans l'en-tête en adresses exécutables.

Lorsque vous composez le fichier d'en-tête côté client, gardez à l'esprit la complexité. Il peut arriver que certains de vos clients ne souhaitent utiliser que quelques parties de votre bibliothèque. Si vous composez un fichier d’en-tête principal contenant tout ce qui se trouve dans votre bibliothèque, le temps de compilation de vos clients sera augmenté inutilement. 

Une façon courante de traiter ce problème consiste à fournir des fichiers d’en-tête individuels pour les parties corrélées de votre bibliothèque. Si vous pensez à Boost dans une seule bibliothèque, Boost en est un exemple. Boost est une énorme bibliothèque, mais si tout ce que vous voulez, c'est la fonctionnalité regex, vous ne pouvez que #include l'en-tête ou les en-têtes associés à regex pour obtenir cette fonctionnalité. Vous n'avez pas à inclure all of Boost si vous ne voulez que les regex.

Sous Windows et Linux, les bibliothèques binaires peuvent être subdivisées en deux types: dynamique et statique. Dans le cas de bibliothèques statiques, le code de la bibliothèque est en fait "importé" (faute d'un meilleur terme) dans l'exécutable du programme client. Une bibliothèque statique est distribuée par vous, mais cela n’est nécessaire que par le client lors de la compilation. Ceci est pratique lorsque vous ne voulez pas forcer votre client à distribuer des fichiers supplémentaires avec son programme. Cela permet également d’éviter L’enfer de dépendance . En revanche, une bibliothèque dynamique n’est pas "importée" dans le programme client, mais achetée dynamiquement chargée par le programme client lors de son exécution. Cela réduit à la fois la taille du programme client et potentiellement l'encombrement du disque dans les cas où plusieurs programmes utilisent la même bibliothèque dynamique, mais que le fichier binaire de la bibliothèque doit être distribué et installé avec le programme client.

33
John Dibling

En supposant que vos "fichier1.hpp" et "fichier2.hpp" sont étroitement liés et (presque) toujours utilisés ensemble, il est alors utile de créer un "mypacakge.h" contenant les éléments includes des autres composants. en soi, en faire une bibliothèque - c'est un processus complètement différent). 

S'ils ne sont PAS étroitement liés et/ou utilisés ensemble, vous ne devriez pas avoir un tel "méga include", car cela traîne dans un tas de choses inutiles. 

Pour créer une bibliothèque, vous devez créer votre code une fois, puis générer un fichier .lib ou une bibliothèque partagée (fichier .dll ou .so). La procédure exacte à suivre dépend du système que vous utilisez et c’est un peu trop compliqué à expliquer ici. 

Edit: Pour expliquer davantage: toute la bibliothèque C++ est en fait un fichier de bibliothèque ou un fichier de bibliothèque partagée [avec un certain nombre de fichiers d'en-tête contenant une partie du code et les déclarations nécessaires pour utiliser le code dans la bibliothèque]. Mais vous incluez <iostream> et <vector> séparément - il serait vraiment horrible d'inclure TOUT dans tous les en-têtes de bibliothèque C++ différents dans un <allcpplibrary>, même si la saisie était beaucoup moins complexe. Il est divisé en sections qui font une chose par fichier d’en-tête. Vous obtenez donc un ensemble "complet" à partir d'un fichier d'en-tête, mais pas trop d'autres choses dont vous n'avez pas réellement besoin. 

1
Mats Petersson

Sous Linux:

g ++ FLAGS -shared -Wl, -soname, libLIBNAME.so.1 -o libLIBNAME.VERSION OBJECT_FILES

FLAGS: drapeaux typiques (par exemple, -g, -Wall, -Wextra, etc.)

LIBNAME: nom de votre bibliothèque

OBJECT_FILES: fichiers objets résultant de la compilation de fichiers cpp

VERSION: version de votre bibliothèque

0
Claudio

Si un client a besoin des dix en-têtes pour utiliser votre "package" (bibliothèque), la conception de l'interface est plutôt mauvaise.

Si un client n'a besoin que de certains en-têtes, en fonction des parties de votre bibliothèque utilisées, laissez-le inclure les en-têtes appropriés. Ainsi, seul un ensemble minimal d'identificateurs est introduit. Cela aide les temps de portée, de modularisation et de compilation.

Si tout le reste échoue, vous pouvez créer un "en-tête d'interface" à usage externe, différent de ceux utilisés en interne pour la compilation de votre bibliothèque. Il s’agit de celui qui s’installe et qui contient le contenu nécessaire des autres en-têtes. (Je ne pense toujours pas que vous auriez besoin de tout de tous les en-tête de votre lib.)

Je découragerais la solution de Salgar. Vous soit avez des en-têtes individuels, ou un/monolithique. Fournir des en-têtes individuels plus un élément central qui inclut simplement les autres me semble assez mal structuré.

Ce que je fais pas comprends, c'est inhowfar Les Makefiles jouent là-dedans. Les dépendances d’en-têtes doivent être résolues automatiquement par votre système Makefile/build, c’est-à-dire que la manière dont vos fichiers d’en-tête sont disposés n’a aucune importance.

0
DevSolar

Oui et non. 

Vous pouvez écrire un en-tête include-all pour que #include "myLib.h" soit suffisant, car vous incluez tous ces en-têtes dans l'en-tête unique. Toutefois, cela ne signifie pas que l'inclusion simple est suffisante pour que le contenu des 10 fichiers '.cpp' liés à votre projet soit lié automatiquement à votre projet. Vous devrez les compiler dans une bibliothèque et lier cette bibliothèque unique (au lieu de tous les fichiers objet) aux projets qui utilisent "myLib.h". Les fichiers binaires des bibliothèques se présentent sous forme de bibliothèques statiques et dynamiques. Les fichiers sont généralement nommés .lib et .dll (windows) et .a et .so (linux) pour les bibliothèques statiques et dynamiques, respectivement. 

La manière de construire et de lier de telles bibliothèques dépend de votre système de compilation. Vous voudrez peut-être utiliser ces termes sur le net.

Une solution consiste à supprimer les fichiers .cpp en définissant toutes les fonctions des en-têtes. Ainsi, vous n'aurez pas à lier la bibliothèque supplémentaire, mais cela se traduira par un temps de construction plus long, car le compilateur devra traiter toutes ces fonctions chaque fois que vous incluez l'en-tête directement ou indirectement dans l'une de vos unités de traduction.

0
Arne Mertz