c++ link Qu'est-ce qu'une référence non définie/une erreur de symbole externe non résolue et comment la réparer?




undefined reference to c++> (22)

Le package Visual Studio NuGet doit être mis à jour pour la nouvelle version de l'éditeur d'outils

J'ai juste eu ce problème essayant de lier libpng avec Visual Studio 2013. Le problème est que le dossier de paquet a seulement eu des bibliothèques pour Visual Studio 2010 et 2012.

La bonne solution est d'espérer que le développeur publiera un paquet mis à jour et ensuite mettre à jour, mais cela a fonctionné pour moi en hacking dans un paramètre supplémentaire pour VS2013, pointant vers les fichiers de la bibliothèque VS2012.

J'ai édité le paquet (dans le dossier de packages dans le répertoire de la solution) en trouvant le nom de packagename\build\native\packagename.targets et dans ce fichier, en copiant toutes les sections v110 . J'ai changé la v110 en v120 dans les champs de condition en faisant très attention de laisser les chemins du nom de fichier tout comme v110 . Cela a simplement permis à Visual Studio 2013 de créer un lien vers les bibliothèques pour 2012, et dans ce cas, cela a fonctionné.

Quelles sont les références non définies / les erreurs de symboles externes non résolues? Quelles sont les causes communes et comment les réparer / les prévenir?

N'hésitez pas à modifier / ajouter les vôtres.


Use the linker to help diagnose the error

Most modern linkers include a verbose option that prints out to varying degrees;

  • Link invocation (command line),
  • Data on what libraries are included in the link stage,
  • The location of the libraries,
  • Search paths used.

For gcc and clang; you would typically add -v -Wl,--verbose or -v -Wl,-v to the command line. More details can be found here;

For MSVC, /VERBOSE (in particular /VERBOSE:LIB ) is added to the link command line.


Les implémentations de modèle ne sont pas visibles.

Les modèles non spécialisés doivent avoir leurs définitions visibles pour toutes les unités de traduction qui les utilisent. Cela signifie que vous ne pouvez pas séparer la définition d'un modèle en un fichier d'implémentation. Si vous devez séparer l'implémentation, la solution de contournement habituelle consiste à avoir un fichier impl que vous incluez à la fin de l'en-tête qui déclare le modèle. Une situation commune est:

template<class T>
struct X
{
    void foo();
};

int main()
{
    X<int> x;
    x.foo();
}

//differentImplementationFile.cpp
template<class T>
void X<T>::foo()
{
}

Pour résoudre ce problème, vous devez déplacer la définition de X::foo dans le fichier d'en-tête ou dans un endroit visible par l'unité de traduction qui l'utilise.

Des modèles spécialisés peuvent être implémentés dans un fichier d'implémentation et l'implémentation ne doit pas être visible, mais la spécialisation doit être préalablement déclarée.

Pour plus d'explications et une autre solution possible (instanciation explicite) voir cette question et réponse .


When your include paths are different

Linker errors can happen when a header file and its associated shared library (.lib file) go out of sync. Laisse-moi expliquer.

How do linkers work? The linker matches a function declaration (declared in the header) with its definition (in the shared library) by comparing their signatures. You can get a linker error if the linker doesn't find a function definition that matches perfectly.

Is it possible to still get a linker error even though the declaration and the definition seem to match? Oui! They might look the same in source code, but it really depends on what the compiler sees. Essentially you could end up with a situation like this:

// header1.h
typedef int Number;
void foo(Number);

// header2.h
typedef float Number;
void foo(Number); // this only looks the same lexically

Note how even though both the function declarations look identical in source code, but they are really different according to the compiler.

You might ask how one ends up in a situation like that? Include paths of course! If when compiling the shared library, the include path leads to header1.h and you end up using header2.h in your own program, you'll be left scratching your header wondering what happened (pun intended).

An example of how this can happen in the real world is explained below.

Further elaboration with an example

I have two projects: graphics.lib and main.exe . Both projects depend on common_math.h . Suppose the library exports the following function:

// graphics.lib    
#include "common_math.h" 

void draw(vec3 p) { ... } // vec3 comes from common_math.h

And then you go ahead and include the library in your own project.

// main.exe
#include "other/common_math.h"
#include "graphics.h"

int main() {
    draw(...);
}

Boom! You get a linker error and you have no idea why it's failing. The reason is that the common library uses different versions of the same include common_math.h (I have made it obvious here in the example by including a different path, but it might not always be so obvious. Maybe the include path is different in the compiler settings).

Note in this example, the linker would tell you it couldn't find draw() , when in reality you know it obviously is being exported by the library. You could spend hours scratching your head wondering what went wrong. The thing is, the linker sees a different signature because the parameter types are slightly different. In the example, vec3 is a different type in both projects as far as the compiler is concerned. This could happen because they come from two slightly different include files (maybe the include files come from two different versions of the library).

Debugging the linker

DUMPBIN is your friend, if you are using Visual Studio. I'm sure other compilers have other similar tools.

The process goes like this:

  1. Note the weird mangled name given in the linker error. (eg. [email protected]@XYZ).
  2. Dump the exported symbols from the library into a text file.
  3. Search for the exported symbol of interest, and notice that the mangled name is different.
  4. Pay attention to why the mangled names ended up different. You would be able to see that the parameter types are different, even though they look the same in the source code.
  5. Reason why they are different. In the example given above, they are different because of different include files.

[1] By project I mean a set of source files that are linked together to produce either a library or an executable.

EDIT 1: Rewrote first section to be easier to understand. Please comment below to let me know if something else needs to be fixed. Merci!


Membres du cours

Un destructeur virtual pur a besoin d'une implémentation.

Déclarer un destructeur pur nécessite toujours de le définir (contrairement à une fonction normale):

struct X
{
    virtual ~X() = 0;
};
struct Y : X
{
    ~Y() {}
};
int main()
{
    Y y;
}
//X::~X(){} //uncomment this line for successful definition

Cela arrive parce que les destructeurs de classe de base sont appelés lorsque l'objet est détruit implicitement, donc une définition est requise.

virtual méthodes virtual doivent être implémentées ou définies comme étant pures.

Ceci est similaire aux méthodes non virtual sans définition, avec le raisonnement supplémentaire que la déclaration pure génère une vtable factice et que vous pourriez obtenir l'erreur de l'éditeur de liens sans utiliser la fonction:

struct X
{
    virtual void foo();
};
struct Y : X
{
   void foo() {}
};
int main()
{
   Y y; //linker error although there was no call to X::foo
}

Pour que cela fonctionne, déclarez X::foo() pur:

struct X
{
    virtual void foo() = 0;
};

Membres de classe non- virtual

Certains membres doivent être définis même s'ils ne sont pas utilisés explicitement:

struct A
{ 
    ~A();
};

Ce qui suit donnerait l'erreur:

A a;      //destructor undefined

L'implémentation peut être en ligne, dans la définition de classe elle-même:

struct A
{ 
    ~A() {}
};

ou à l'extérieur:

A::~A() {}

Si l'implémentation est en dehors de la définition de classe, mais dans un en-tête, les méthodes doivent être marquées comme inline pour empêcher une définition multiple.

Toutes les méthodes de membre utilisées doivent être définies si elles sont utilisées.

Une erreur courante est d'oublier de qualifier le nom:

struct A
{
   void foo();
};

void foo() {}

int main()
{
   A a;
   a.foo();
}

La définition devrait être

void A::foo() {}

Les membres de données static doivent être définis en dehors de la classe dans une seule unité de traduction :

struct X
{
    static int x;
};
int main()
{
    int x = X::x;
}
//int X::x; //uncomment this line to define X::x

Un initialiseur peut être fourni pour un membre de données const static de type intégrale ou d'énumération dans la définition de classe; cependant, l'utilisation de ce membre nécessitera toujours une définition d'étendue d'espace de nommage comme décrit ci-dessus. C ++ 11 permet l'initialisation à l'intérieur de la classe pour tous static const membres de données static const .


Échec de la liaison avec les bibliothèques / fichiers objets appropriés ou compilation des fichiers d'implémentation

Généralement, chaque unité de traduction génère un fichier objet qui contient les définitions des symboles définis dans cette unité de traduction. Pour utiliser ces symboles, vous devez faire un lien avec ces fichiers objets.

Sous gcc, vous devez spécifier tous les fichiers objet à lier ensemble dans la ligne de commande, ou compiler les fichiers d'implémentation ensemble.

g++ -o test objectFile1.o objectFile2.o -lLibraryName

Le nom de bibliothèque ici est juste le nom nu de la bibliothèque, sans ajouts spécifiques à la plate-forme. Par exemple, sur les fichiers de la bibliothèque Linux, on appelle généralement libfoo.so mais vous écrivez seulement -lfoo . Sous Windows, ce même fichier peut s'appeler foo.lib , mais vous utiliseriez le même argument. Vous devrez peut-être ajouter le répertoire où ces fichiers peuvent être trouvés en utilisant -L‹directory› . Assurez-vous de ne pas écrire un espace après -l ou -L .

Pour XCode : Ajouter les chemins de recherche de l'en-tête utilisateur -> ajouter le chemin de recherche de la bibliothèque -> faire glisser et déposer la référence de la bibliothèque dans le dossier du projet.

Sous MSVS , les fichiers ajoutés à un projet ont automatiquement leurs fichiers objet liés et un fichier lib est généré (dans l'usage courant). Pour utiliser les symboles dans un projet distinct, vous devez inclure les fichiers lib dans les paramètres du projet. Ceci est fait dans la section Linker des propriétés du projet, dans Input -> Additional Dependencies . (le chemin vers le fichier lib doit être ajouté dans Linker -> General -> Additional Library Directories ) Lorsque vous utilisez une bibliothèque tierce fournie avec un fichier lib , l'échec entraîne généralement l'erreur.

Il peut également arriver que vous oubliez d'ajouter le fichier à la compilation, auquel cas le fichier objet ne sera pas généré. Dans gcc vous ajouteriez les fichiers à la ligne de commande. Dans MSVS, ajouter le fichier au projet le fera le compiler automatiquement (bien que les fichiers puissent, manuellement, être exclus individuellement de la construction).

Dans la programmation Windows, le signe indiquant que vous n'avez pas lié une bibliothèque nécessaire est que le nom du symbole non résolu commence par __imp_ . Recherchez le nom de la fonction dans la documentation, et il devrait indiquer quelle bibliothèque vous devez utiliser. Par exemple, MSDN place l'information dans une zone au bas de chaque fonction dans une section appelée "Bibliothèque".


Aussi, si vous utilisez des bibliothèques tierces, assurez-vous d'avoir les bons binaires 32/64 bits


Since people seem to be directed to this question when it comes to linker errors I am going to add this here.

One possible reason for linker errors with GCC 5.2.0 is that a new libstdc++ library ABI is now chosen by default.

If you get linker errors about undefined references to symbols that involve types in the std::__cxx11 namespace or the tag [abi:cxx11] then it probably indicates that you are trying to link together object files that were compiled with different values for the _GLIBCXX_USE_CXX11_ABI macro. This commonly happens when linking to a third-party library that was compiled with an older version of GCC. If the third-party library cannot be rebuilt with the new ABI then you will need to recompile your code with the old ABI.

So if you suddenly get linker errors when switching to a GCC after 5.1.0 this would be a thing to check out.


Missing "extern" in const variable declarations/definitions (C++ only)

For people coming from C it might be a surprise that in C++ global const variables have internal (or static) linkage. In C this was not the case, as all global variables are implicitly extern (ie when the static keyword is missing).

Exemple:

// file1.cpp
const int test = 5;    // in C++ same as "static const int test = 5"
int test2 = 5;

// file2.cpp
extern const int test;
extern int test2;

void foo()
{
 int x = test;   // linker error in C++ , no error in C
 int y = test2;  // no problem
}

correct would be to use a header file and include it in file2.cpp and file1.cpp

extern const int test;
extern int test2;

Alternatively one could declare the const variable in file1.cpp with explicit extern


Si tout le reste échoue, recompilez.

J'ai récemment pu me débarrasser d'une erreur externe non résolue dans Visual Studio 2012 juste en recompilant le fichier incriminé. Quand j'ai reconstruit, l'erreur est partie.

Cela se produit généralement lorsque deux bibliothèques (ou plus) ont une dépendance cyclique. Bibliothèque A tente d'utiliser des symboles dans B.lib et la bibliothèque B tente d'utiliser des symboles de A.lib. Aucun n'existe pour commencer avec. Lorsque vous tentez de compiler A, l'étape de lien échouera car il ne peut pas trouver B.lib. A.lib sera généré, mais pas dll. Vous compilez ensuite B, qui va réussir et générer B.lib. Recompiler A fonctionnera maintenant parce que B.lib est maintenant trouvé.


C'est l'un des messages d'erreur les plus confus que tous les programmeurs VC ++ ont vu à maintes reprises. Faisons les choses claires d'abord.

A. Qu'est-ce qu'un symbole? En bref, un symbole est un nom. Il peut s'agir d'un nom de variable, d'un nom de fonction, d'un nom de classe, d'un nom de typedef ou de tout autre élément, à l'exception des noms et des signes appartenant au langage C ++. Il est défini par l'utilisateur ou introduit par une bibliothèque de dépendances (définie par l'utilisateur).

B. Qu'est-ce qui est externe? Dans VC ++, chaque fichier source (.cpp, .c, etc.) est considéré comme une unité de traduction, le compilateur compile une unité à la fois et génère un fichier objet (.obj) pour l'unité de traduction en cours. (Notez que chaque fichier d'en-tête inclus dans ce fichier source sera prétraité et sera considéré comme faisant partie de cette unité de traduction) Tout dans une unité de traduction est considéré comme interne, tout le reste est considéré comme externe. En C ++, vous pouvez référencer un symbole externe en utilisant des mots-clés comme extern , __declspec (dllimport) et ainsi de suite.

C. Qu'est-ce que "résoudre"? Resolve est un terme de liaison. Dans linking time, l'éditeur de liens tente de trouver la définition externe pour chaque symbole dans les fichiers objet qui ne peuvent pas trouver sa définition en interne. La portée de ce processus de recherche incluant:

  • Tous les fichiers objets générés lors de la compilation
  • Toutes les bibliothèques (.lib) explicitement ou implicitement spécifiées en tant que dépendances supplémentaires de cette application de construction.

Ce processus de recherche est appelé résoudre.

D. Enfin, pourquoi le symbole externe non résolu? Si l'éditeur de liens ne trouve pas la définition externe d'un symbole qui n'a aucune définition interne, il signale une erreur de symbole externe non résolue.

E. Causes possibles de LNK2019 : Erreur de symbole externe non résolue . Nous savons déjà que cette erreur est due à l'éditeur de liens n'a pas réussi à trouver la définition des symboles externes, les causes possibles peuvent être triées comme:

  1. La définition existe

Par exemple, si nous avons une fonction appelée foo définie dans a.cpp:

int foo()
{
    return 0;
}

Dans b.cpp, nous voulons appeler la fonction foo, donc nous ajoutons

void foo();

pour déclarer la fonction foo (), et l'appeler dans un autre corps de fonction, disons bar() :

void bar()
{
    foo();
}

Maintenant, lorsque vous construisez ce code, vous obtiendrez une erreur LNK2019 se plaignant que foo est un symbole non résolu. Dans ce cas, nous savons que foo () a sa définition dans a.cpp, mais différente de celle que nous appelons (valeur de retour différente). C'est le cas cette définition existe.

  1. La définition n'existe pas

Si nous voulons appeler certaines fonctions dans une bibliothèque, mais que la bibliothèque d'importation n'est pas ajoutée dans la liste des dépendances supplémentaires (définie dans: Project | Properties | Configuration Properties | Linker | Input | Additional Dependency ) de votre paramètre de projet. Maintenant, l'éditeur de liens rapportera un LNK2019 puisque la définition n'existe pas dans la portée de recherche actuelle.


Microsoft propose un #pragma pour référencer la bibliothèque correcte au moment de la liaison.

#pragma comment(lib, "libname.lib")

En plus du chemin de la bibliothèque incluant le répertoire de la bibliothèque, il doit s'agir du nom complet de la bibliothèque.


A bug in the compiler/IDE

I recently had this problem, and it turned out it was a bug in Visual Studio Express 2013 . I had to remove a source file from the project and re-add it to overcome the bug.

Steps to try if you believe it could be a bug in compiler/IDE:

  • Clean the project (some IDEs have an option to do this, you can also manually do it by deleting the object files)
  • Try start a new project, copying all source code from the original one.

Inconsistent UNICODE definitions

A Windows UNICODE build is built with TCHAR etc. being defined as wchar_t etc. When not building with UNICODE defined as build with TCHAR defined as char etc. These UNICODE and _UNICODE defines affect all the " T " string types ; LPTSTR , LPCTSTR and their elk.

Building one library with UNICODE defined and attempting to link it in a project where UNICODE is not defined will result in linker errors since there will be a mismatch in the definition of TCHAR ; char vs. wchar_t .

The error usually includes a function a value with a char or wchar_t derived type, these could include std::basic_string<> etc. as well. When browsing through the affected function in the code, there will often be a reference to TCHAR or std::basic_string<TCHAR> etc. This is a tell-tale sign that the code was originally intended for both a UNICODE and a Multi-Byte Character (or "narrow") build.

To correct this, build all the required libraries and projects with a consistent definition of UNICODE (and _UNICODE ).

  1. This can be done with either;

    #define UNICODE
    #define _UNICODE
    
  2. Or in the project settings;

    Project Properties > General > Project Defaults > Character Set

  3. Or on the command line;

    /DUNICODE /D_UNICODE
    

The alternative is applicable as well, if UNICODE is not intended to be used, make sure the defines are not set, and/or the multi-character setting is used in the projects and consistently applied.

Do not forget to be consistent between the "Release" and "Debug" builds as well.


Linked .lib file is associated to a .dll

J'ai eu le même problème. Say i have projects MyProject and TestProject. I had effectively linked the lib file for MyProject to the TestProject. However, this lib file was produced as the DLL for the MyProject was built. Also, I did not contain source code for all methods in the MyProject, but only access to the DLL's entry points.

To solve the issue, i built the MyProject as a LIB, and linked TestProject to this .lib file (i copy paste the generated .lib file into the TestProject folder). I can then build again MyProject as a DLL. It is compiling since the lib to which TestProject is linked does contain code for all methods in classes in MyProject.


qu'est-ce qu'une "référence non définie / symbole externe non résolu"

Je vais essayer d'expliquer ce qu'est une «référence non définie / symbole externe non résolu».

note: j'utilise g ++ et Linux et tous les exemples sont pour ça

Par exemple, nous avons du code

// src1.cpp
void print();

static int local_var_name; // 'static' makes variable not visible for other modules
int global_var_name = 123;

int main()
{
    print();
    return 0;
}

et

// src2.cpp
extern "C" int printf (const char*, ...);

extern int global_var_name;
//extern int local_var_name;

void print ()
{
    // printf("%d%d\n", global_var_name, local_var_name);
    printf("%d\n", global_var_name);
}

Créer des fichiers objet

$ g++ -c src1.cpp -o src1.o
$ g++ -c src2.cpp -o src2.o

Après la phase assembleur, nous avons un fichier objet, qui contient tous les symboles à exporter. Regardez les symboles

$ readelf --symbols src1.o
  Num:    Value          Size Type    Bind   Vis      Ndx Name
     5: 0000000000000000     4 OBJECT  LOCAL  DEFAULT    4 _ZL14local_var_name # [1]
     9: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 global_var_name     # [2]

J'ai rejeté certaines lignes de la sortie, parce qu'elles n'ont pas d'importance

Donc, nous voyons suivre les symboles à exporter.

[1] - this is our static (local) variable (important - Bind has a type "LOCAL")
[2] - this is our global variable

src2.cpp exporte rien et nous n'avons pas vu ses symboles

Lier nos fichiers objets

$ g++ src1.o src2.o -o prog

et lancez-le

$ ./prog
123

Linker voit les symboles exportés et les lie. Maintenant, nous essayons de décommenter les lignes dans src2.cpp comme ici

// src2.cpp
extern "C" int printf (const char*, ...);

extern int global_var_name;
extern int local_var_name;

void print ()
{
    printf("%d%d\n", global_var_name, local_var_name);
}

et reconstruire un fichier objet

$ g++ -c src2.cpp -o src2.o

OK (pas d'erreurs), parce que nous ne construisons que le fichier objet, la liaison n'est pas encore terminée. Essayez de lier

$ g++ src1.o src2.o -o prog
src2.o: In function `print()':
src2.cpp:(.text+0x6): undefined reference to `local_var_name'
collect2: error: ld returned 1 exit status

Cela est dû au fait que notre nom_var_local est statique, c'est-à-dire qu'il n'est pas visible pour les autres modules. Maintenant plus profondément. Obtenir la sortie de la phase de traduction

$ g++ -S src1.cpp -o src1.s

// src1.s
look src1.s

    .file   "src1.cpp"
    .local  _ZL14local_var_name
    .comm   _ZL14local_var_name,4,4
    .globl  global_var_name
    .data
    .align 4
    .type   global_var_name, @object
    .size   global_var_name, 4
global_var_name:
    .long   123
    .text
    .globl  main
    .type   main, @function
main:
; assembler code, not interesting for us
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
    .section    .note.GNU-stack,"",@progbits

Donc, nous avons vu qu'il n'y a pas d'étiquette pour local_var_name, c'est pourquoi linker ne l'a pas trouvé. Mais nous sommes des hackers :) et nous pouvons le réparer. Ouvrez src1.s dans votre éditeur de texte et modifiez

.local  _ZL14local_var_name
.comm   _ZL14local_var_name,4,4

à

    .globl  local_var_name
    .data
    .align 4
    .type   local_var_name, @object
    .size   local_var_name, 4
local_var_name:
    .long   456789

c'est à dire que vous devriez avoir comme ci-dessous

    .file   "src1.cpp"
    .globl  local_var_name
    .data
    .align 4
    .type   local_var_name, @object
    .size   local_var_name, 4
local_var_name:
    .long   456789
    .globl  global_var_name
    .align 4
    .type   global_var_name, @object
    .size   global_var_name, 4
global_var_name:
    .long   123
    .text
    .globl  main
    .type   main, @function
main:
; ...

nous avons modifié la visibilité de local_var_name et défini sa valeur sur 456789. Essayez de créer un fichier objet à partir de celui-ci

$ g++ -c src1.s -o src2.o

ok, voir lire sortie (symboles)

$ readelf --symbols src1.o
8: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 local_var_name

maintenant local_var_name a Bind GLOBAL (était LOCAL)

lien

$ g++ src1.o src2.o -o prog

et lancez-le

$ ./prog 
123456789

D'accord, nous le piratons :)

Par conséquent, une "référence non définie / erreur de symbole externe non résolue" se produit lorsque l'éditeur de liens ne trouve pas de symboles globaux dans les fichiers objets.


L'ordre dans lequel les bibliothèques liées interdépendantes sont spécifiées est incorrect.

L'ordre dans lequel les bibliothèques sont liées est important si les bibliothèques dépendent les unes des autres. En général, si la bibliothèque A dépend de la bibliothèque B , libA DOIT apparaître avant la libB dans les indicateurs de l'éditeur de liens.

Par exemple:

// B.h
#ifndef B_H
#define B_H

struct B {
    B(int);
    int x;
};

#endif

// B.cpp
#include "B.h"
B::B(int xx) : x(xx) {}

// A.h
#include "B.h"

struct A {
    A(int x);
    B b;
};

// A.cpp
#include "A.h"

A::A(int x) : b(x) {}

// main.cpp
#include "A.h"

int main() {
    A a(5);
    return 0;
};

Créez les bibliothèques:

$ g++ -c A.cpp
$ g++ -c B.cpp
$ ar rvs libA.a A.o 
ar: creating libA.a
a - A.o
$ ar rvs libB.a B.o 
ar: creating libB.a
a - B.o

Compiler:

$ g++ main.cpp -L. -lB -lA
./libA.a(A.o): In function `A::A(int)':
A.cpp:(.text+0x1c): undefined reference to `B::B(int)'
collect2: error: ld returned 1 exit status
$ g++ main.cpp -L. -lA -lB
$ ./a.out

Donc pour répéter encore, l'ordre a de l'importance!


Supposons que vous ayez un gros projet écrit en c ++ qui contient un millier de fichiers .cpp et un millier de fichiers .h. Et supposons que le projet dépend également de dix bibliothèques statiques. Disons que nous sommes sur Windows et que nous construisons notre projet dans Visual Studio 20xx. When you press Ctrl + F7 Visual Studio to start compiling the whole solution ( suppose we have just one project in the solution )

What's the meaning of compilation ?

  • Visual Studio search into file .vcxproj and start compiling each file which has the extension .cpp. Order of compilation is undefined.So you must not assume that the file main.cpp is compiled first
  • If .cpp files depends on additional .h files in order to find symbols that may or may not be defined in the file .cpp
  • If exists one .cpp file in which the compiler could not find one symbol, a compiler time error raises the message Symbol x could not be found
  • For each file with extension .cpp is generated an object file .o and also Visual Studio writes the output in a file named ProjectName.Cpp.Clean.txt which contains all object files that must be processed by the linker.

The Second step of compilation is done by Linker.Linker should merge all the object file and build finally the output ( which may be an executable or a library)

Steps In Linking a project

  • Parse all the object files and find the definition which was only declared in headers ( eg: The code of one method of a class as is mentioned in previous answers, or event the initialization of a static variable which is member inside a class)
  • If one symbol could not be found in object files he also is searched in Additional Libraries.For adding a new library to a project Configuration properties -> VC++ Directories -> Library Directories and here you specified additional folder for searching libraries and Configuration properties -> Linker -> Input for specifying the name of the library. -If the Linker could not find the symbol which you write in one .cpp he raises a linker time error which may sound like error LNK2001: unresolved external symbol "void __cdecl foo(void)" ([email protected]@YAXXZ)

Observation

  1. Once the Linker find one symbol he doesn't search in other libraries for it
  2. The order of linking libraries does matter .
  3. If Linker finds an external symbol in one static library he includes the symbol in the output of the project.However, if the library is shared( dynamic ) he doesn't include the code ( symbols ) in output, but Run-Time crashes may occur

How To Solve this kind of error

Compiler Time Error :

  • Make sure you write your c++ project syntactical correct.

Linker Time Error

  • Define all your symbol which you declare in your header files
  • Use #pragma once for allowing compiler not to include one header if it was already included in the current .cpp which are compiled
  • Make sure that your external library doesn't contain symbols that may enter into conflict with other symbols you defined in your header files
  • When you use the template to make sure you include the definition of each template function in the header file for allowing the compiler to generate appropriate code for any instantiations.

Importation / exportation incorrecte de méthodes / classes sur modules / dll (spécifique au compilateur).

MSVS vous oblige à spécifier les symboles à exporter et à importer en utilisant __declspec(dllexport) et __declspec(dllimport) .

Cette double fonctionnalité est généralement obtenue par l'utilisation d'une macro:

#ifdef THIS_MODULE
#define DLLIMPEXP __declspec(dllexport)
#else
#define DLLIMPEXP __declspec(dllimport)
#endif

La macro THIS_MODULE ne sera définie que dans le module qui exporte la fonction. De cette façon, la déclaration:

DLLIMPEXP void foo();

se développe pour

__declspec(dllexport) void foo();

et dit au compilateur d'exporter la fonction, car le module courant contient sa définition. Lorsque vous incluez la déclaration dans un module différent, elle s'étendra jusqu'à

__declspec(dllimport) void foo();

et indique au compilateur que la définition est dans l'une des bibliothèques avec lesquelles vous avez lié (voir aussi 1) ).

Vous pouvez importer des classes d'import / export similaires:

class DLLIMPEXP X
{
};

Déclaré mais n'a pas défini de variable ou de fonction.

Une déclaration de variable typique est

extern int x;

Comme il ne s'agit que d'une déclaration, une seule définition est nécessaire. Une définition correspondante serait:

int x;

Par exemple, ce qui suit générerait une erreur:

extern int x;
int main()
{
    x = 0;
}
//int x; // uncomment this line for successful definition

Des remarques similaires s'appliquent aux fonctions. Déclarer une fonction sans la définir conduit à l'erreur:

void foo(); // declaration only
int main()
{
   foo();
}
//void foo() {} //uncomment this line for successful definition

Veillez à ce que la fonction que vous implémentez corresponde exactement à celle que vous avez déclarée. Par exemple, vous pouvez avoir des qualificatifs cv incompatibles:

void foo(int& x);
int main()
{
   int x;
   foo(x);
}
void foo(const int& x) {} //different function, doesn't provide a definition
                          //for void foo(int& x)

D'autres exemples de discordances comprennent

  • Fonction / variable déclarée dans un espace de nom, définie dans un autre.
  • Fonction / variable déclarée en tant que membre de classe, définie comme globale (ou vice versa).
  • Le type de retour de fonction, le nombre et les types de paramètre, et la convention d'appel ne sont pas tous exactement d'accord.

Le message d'erreur du compilateur vous donnera souvent la déclaration complète de la variable ou de la fonction déclarée mais jamais définie. Comparez-le étroitement à la définition que vous avez fournie. Assurez-vous que chaque détail correspond.


Clean and rebuild

A "clean" of the build can remove the "dead wood" that may be left lying around from previous builds, failed builds, incomplete builds and other build system related build issues.

In general the IDE or build will include some form of "clean" function, but this may not be correctly configured (eg in a manual makefile) or may fail (eg the intermediate or resultant binaries are read-only).

Once the "clean" has completed, verify that the "clean" has succeeded and all the generated intermediate file (eg an automated makefile) have been successfully removed.

This process can be seen as a final resort, but is often a good first step ; especially if the code related to the error has recently been added (either locally or from the source repository).


référence indéfinie à [email protected] ou référence de point d'entrée main() inhabituelle similaire (en particulier pour visual-studio ).

Vous avez peut-être manqué de choisir le bon type de projet avec votre IDE réel. L'EDI peut vouloir lier, par exemple, des projets d'application Windows à une telle fonction de point d'entrée (comme spécifié dans la référence manquante ci-dessus), au lieu de int main(int argc, char** argv); couramment utilisé int main(int argc, char** argv); Signature.

Si votre IDE prend en charge les projets de console standard, vous pouvez choisir ce type de projet, plutôt qu'un projet d'application Windows.





unresolved-external