2009-03-08 6 views
8

Je compile une bibliothèque statique C++ et comme toutes les classes sont modélisées, les définitions de classe et les implémentations sont toutes dans des fichiers d'en-tête. Par conséquent, il semble (sous Visual Studio 2005) que j'ai besoin de créer un fichier .cpp qui inclut tous les autres fichiers d'en-tête afin qu'il puisse être compilé correctement dans la bibliothèque.Compiler un C++ .lib avec uniquement des fichiers d'en-tête?

Pourquoi est-ce?

Répondre

8

Le compilateur ne compile pas les fichiers d'en-tête car ceux-ci doivent être inclus dans les fichiers source. Avant toute compilation, le préprocesseur prend tout le code de tous les fichiers d'en-tête inclus et place ce code dans les fichiers source où ils sont inclus, à l'endroit même où ils sont inclus. Si le compilateur doit également compiler les fichiers d'en-tête, vous aurez par exemple plusieurs définitions sur plusieurs choses.

exemple, voici ce que le préprocesseur voit:

[foo.h] 
void foo(); 

-

[mysource.cpp] 
#include "foo.h" 

int main() 
{ 
    foo(); 
} 

Et voici ce que le compilateur voit:

[mysource.cpp] 
void foo(); 

int main() 
{ 
    foo(); 
} 
0

Pensez Bibliothèque de modèles standard. Vos classes modélisées seront compilées lorsque vous les utiliserez dans un autre projet.

0

Ce que d'autres ont dit est vrai concernant les modèles qui ne sont pas compilés dans la bibliothèque. Cependant, il vaut toujours la peine de les forcer à être vus par le compilateur (en les #incluant dans un fichier .cpp) car ainsi ils seront au moins vérifiés pour la syntaxe.

+0

Il est préférable d'écrire un ensemble de tests unitaires plutôt que de forcer la création d'une bibliothèque statique qui n'a pas besoin d'exister. Après tout, de nombreux compilateurs manqueront des erreurs très basiques sur le code du template si ce code n'est pas appelé. – Tom

2

En C++, les modèles sont juste une méta-définition d'une classe réelle. Lorsque vous compilez une classe basée sur un modèle, le compilateur génère réellement le code de la classe réelle à la volée pour le type particulier de données transmises (le modèle est simplement un "modèle" à copier).

par exemple. Si vous avez le code suivant

 

struct MyTemplate 
{ 
private: 
    float MyValue; 

public: 
    float Get() { return MyValue; } 
    void Set(float value) { MyValue = value; } 
}; 

void main() 
{ 
    MyTemplate v1; 
    MyTemplate v2; 
    v1.Set(5.0f); 
    v2.Set(2); 
    v2.Get(); 
} 
 

Ce que le compilateur voit réellement est

 

struct CompilerGeneratedNameFor_MyTemplate_float 
{ 
private: 
    float MyValue; 

public: 
    float Get() { return MyValue; } 
    void Set(float value) { MyValue = value; } 
}; 

struct CompilerGeneratedNameFor_MyTemplate_int 
{ 
private: 
    int MyValue; 

public: 
    int Get() { return MyValue; } 
    void Set(int value) { MyValue = value; } 
}; 

void main() 
{ 
    CompilerGeneratedNameFor_MyTemplate_float v1; 
    CompilerGeneratedNameFor_MyTemplate_int v2; 
    v1.Set(5.0f); 
    v2.Set(2); 
    v2.Get(); 
} 
 

Comme vous pouvez le voir, le compilateur ne sait pas vraiment ce code pour générer, jusqu'à ce que vous déclarez en fait une instance de votre modèle. Cela signifie que le modèle ne peut pas être compilé dans une bibliothèque, car il ne sait pas quel sera le modèle. La bonne nouvelle à ce sujet est que vous n'avez besoin d'AUCUNE bibliothèque pour être compilée ou incluse si vous distribuez simplement les fichiers d'en-tête qui incluent la définition du modèle. En outre, en remarque, la commande de pré-compilateur '#include' indique simplement au pré-compilateur de remplacer '#include' par tout ce qui se trouve dans ce fichier.

1

Vous essayez de créer quelque chose de superflu. La plupart des bibliothèques C (et toutes les bibliothèques C++) se répartissent comme deux parties:

  • Interface (foo.h)
  • mise en œuvre (foo.lib)

Pour C++ code du modèle, l'ensemble de votre bibliothèque doit être compilée par vos utilisateurs finaux, car c'est ainsi que fonctionnent les modèles. Il n'y a aucune raison de fournir une bibliothèque précompilée. Dans ce cas, votre peut penser à la distribution de votre bibliothèque comme ceci:

  • Interface (foo.h)
  • mise en œuvre (foo-inl.h)

Comme Niel a dit ci-dessus, il est utile d'avoir des implémentations juste pour votre propres tests, et il est probablement utile de les distribuer à la bibliothèque elle-même. Vous devriez donc avoir une suite séparée de tests unitaires qui exercent votre code; mais ces tests ne devraient pas faire partie de la bibliothèque elle-même.

0

Vous n'avez pas besoin de générer un fichier .lib si toutes vos classes sont des modèles, regardez un boost ou le stlport ils n'ont pas de fichier .lib qu'ils distribuent [1].

Les modèles sont compilés lorsqu'ils sont utilisés. Strictement parlant, ils distribuent des bibliothèques pour les fonctionnalités plus avancées comme les expressions régulières, iostream etc., mais les bibliothèques auxiliaires sont utilisées par d'autres modèles, les modèles ne sont pas distribués sous forme de bibliothèque.

2

Si tout votre code est dans des fichiers .h, vous n'avez pas besoin de compiler une bibliothèque statique pour utiliser le code.

Tout le code est disponible pour l'utilisation de la bibliothèque au moment de la compilation, donc rien n'est nécessaire au moment de la liaison.

1

Si votre bibliothèque est entièrement implémentée dans des fichiers d'en-tête, vous n'avez pas besoin de générer de binaire pour l'utiliser. Cela dit. Je crée généralement un fichier .cpp lors de ma phase de développement initiale de la bibliothèque en-tête uniquement. Pourquoi? Les compilateurs n'essaient pas de compiler ou même d'analyser votre modèle tant qu'il n'est pas réellement utilisé. Avoir un fichier .cpp et avoir un code fictif ici pour instancier les modèles m'aident à trouver des erreurs de syntaxe plus tôt pendant le développement. Je peux donc ajouter du code de modèle, frapper la compilation, corriger l'erreur de syntaxe, ajouter plus de code, compiler ... etc. Si vous essayez tous de traquer une erreur de syntaxe stupide après avoir ajouté des centaines de lignes de code, vous saurez ce que je veux dire. Une fois que ma bibliothèque est prête pour le test unitaire, je vais supprimer le fichier .cpp et me fier aux testes unitaires pour piloter mon développement. En outre, si vous ne compilez que votre code en utilisant VC++, une chose que vous devez savoir est que VC++ n'essaie pas de compiler toutes les fonctions membres du template jusqu'à ce qu'il soit réellement utilisé. Par exemple:

template <typename T> 
class MyTemplate 
{ 
public: 
    MyTemplate() {} // default constructor 

    MyTemplate(int) { 
     1 = 2 
     // other syntax error code here 
    } 
}; 

void f() { MyTemplate<int> myt(); } // compile fine in VC 
void g() { MyTemplate<int> myt(1); } // syntax error 

Le f() compilera très bien avec VC++ 2003, g ++ interceptera l'erreur de syntaxe. Je pense que VC8 et VC9 ont aussi le même problème.