Lo que son referencia indefinida/símbolo externo sin resolver errores? ¿Cuáles son las causas comunes y cómo solucionar y prevenir?

Siéntase libre de editar/añadir su propio.

Una cosa a considerar la adición de cómo lidiar con «undefined vtable» y «undefined typeinfo» errores en particular (ya que son menos evidentes que indefinidas de funciones o variables).
He ido marcando esta pregunta para ser una posible víctima de este. Pero después de ir a través de todos los de su (brillante) de las respuestas, yo no puedo ver este caso se tratan aquí. Soy consciente de que es específico acerca de cómo un IDE establece el tipo de proyecto y la vinculación de las dependencias. Pero eso es una pregunta frecuente, creo que valdría la pena cubiertos (tal vez sólo con un enlace a otra dupe) aquí. Si ya está, y yo simplemente no mancha, se olvidan de esta solicitud o comentario.
‘siéntase libre de agregar una respuesta’ he preferido añadir el enlace correspondiente (en mi humilde opinión) su respuesta primaria, si desea permitir.
Bastante error muy común es el que se define una función como un independiente y olvidar el selector de clase (por ejemplo,A::) en su .cpp archivo: hacer esto (mal): void myFunc() { /* do stuff */ } Lugar de este (a la derecha): void A::myFunc() { /* do stuff */ }
Si esto le sucede a usted con un Qt señal, lo más probable es que se olvidó de la Q_OBJECT macro.

OriginalEl autor Luchian Grigore | 2012-09-24

30 Comentarios

  1. 739

    La compilación de un programa C++ que se lleva a cabo en varios pasos, como especificado por 2.2 (créditos a Keith Thompson para la referencia):

    La precedencia entre las reglas de sintaxis de la traducción es especificado por las siguientes fases [ver nota].

    1. Física archivo de origen de los caracteres se asignan, en una aplicación de forma definida, a la fuente básica de conjunto de caracteres
      (la introducción de nueva línea de caracteres de fin de línea de indicadores) si
      es necesario. [SNIP]
    2. Cada instancia de un carácter de barra diagonal inversa (\) seguida de inmediato por una nueva línea de personaje es eliminado, el empalme de origen físico de las líneas a
      la forma lógica de las líneas de código fuente. [SNIP]
    3. El archivo de origen se descompone en el preprocesamiento de los tokens (2.5) y las secuencias de caracteres de espacio en blanco (incluyendo comentarios). [SNIP]
    4. Directivas de preprocesamiento son ejecutados, macro invocaciones se expanden, y _Pragma operador unario se ejecutan las expresiones. [SNIP]
    5. Cada fuente de caracteres del conjunto de miembros de un carácter literal o un literal de cadena, así como cada una secuencia de escape y universal-personaje-nombre
      en un carácter literal o no raw literal de cadena, se convierte en
      el miembro correspondiente de la ejecución del conjunto de caracteres; [SNIP]
    6. Adyacentes literal de cadena de tokens se concatenan.
    7. Caracteres de espacio en blanco que separa los tokens no son significativas. Cada preprocesamiento token se convierte en un símbolo. (2.7). El
      resultante de tokens son sintácticamente y semánticamente analizado y
      traducido como una unidad de traducción. [SNIP]
    8. Traducido unidades de traducción y creación de instancias de unidades se combinan de la siguiente manera: [SNIP]
    9. Todas las referencias a entidades externas se resuelven. Los componentes de la biblioteca están vinculados a satisfacer las referencias externas a las entidades no definidas en el
      traducción actual. Todos estos traductor de salida se recoge en el
      imagen del programa que contiene la información necesaria para la ejecución de sus
      el entorno de ejecución.
      (el énfasis es mío)

    [nota de pie de página] Implementaciones deben comportarse como si estas fases distintas, aunque en la práctica las diferentes fases podría ser dobladas juntas.

    Especificado se producen errores durante esta última etapa de compilación, más comúnmente conocida como la vinculación. Esto básicamente significa que usted recopilado un montón de archivos de implementación en objeto de archivos o bibliotecas, y ahora quiere llegar a trabajar juntos.

    Decir que definió símbolo a en a.cpp. Ahora, b.cpp declarado ese símbolo. Antes de la vinculación, simplemente se supone que ese símbolo se define en algún lugar, pero aún no les importa de dónde. La vinculación de fase es la responsable de encontrar el símbolo y correctamente su vinculación a la b.cpp (bueno, en realidad al objeto o a la biblioteca que lo utiliza).

    Si está utilizando Microsoft Visual Studio, usted verá que genera .lib archivos. Estos contienen una tabla de símbolos exportados, y una tabla de símbolos importados. Los símbolos importados se resuelven en contra de las bibliotecas de enlace en contra, y los símbolos exportados son proporcionados por las bibliotecas que utilizan el .lib (si los hubiere).

    Mecanismos similares existen para otros compiladores/plataformas.

    Mensajes de error comunes son error LNK2001, error LNK1120, error LNK2019 para Microsoft Visual Studio y undefined reference to symbolName para GCC.

    El código:

    struct X
    {
       virtual void foo();
    };
    struct Y : X
    {
       void foo() {}
    };
    struct A
    {
       virtual ~A() = 0;
    };
    struct B: A
    {
       virtual ~B(){}
    };
    extern int x;
    void foo();
    int main()
    {
       x = 0;
       foo();
       Y y;
       B b;
    }

    genera los siguientes errores con GCC:

    /home/AbiSfw/ccvvuHoX.o: In function `main':
    prog.cpp:(.text+0x10): undefined reference to `x'
    prog.cpp:(.text+0x19): undefined reference to `foo()'
    prog.cpp:(.text+0x2d): undefined reference to `A::~A()'
    /home/AbiSfw/ccvvuHoX.o: In function `B::~B()':
    prog.cpp:(.text._ZN1BD1Ev[B::~B()]+0xb): undefined reference to `A::~A()'
    /home/AbiSfw/ccvvuHoX.o: In function `B::~B()':
    prog.cpp:(.text._ZN1BD0Ev[B::~B()]+0x12): undefined reference to `A::~A()'
    /home/AbiSfw/ccvvuHoX.o:(.rodata._ZTI1Y[typeinfo for Y]+0x8): undefined reference to `typeinfo for X'
    /home/AbiSfw/ccvvuHoX.o:(.rodata._ZTI1B[typeinfo for B]+0x8): undefined reference to `typeinfo for A'
    collect2: ld returned 1 exit status

    y errores similares con Microsoft Visual Studio:

    1>test2.obj : error LNK2001: unresolved external symbol "void __cdecl foo(void)" (?[email protected]@YAXXZ)
    1>test2.obj : error LNK2001: unresolved external symbol "int x" (?[email protected]@3HA)
    1>test2.obj : error LNK2001: unresolved external symbol "public: virtual __thiscall A::~A(void)" (??1A@@[email protected])
    1>test2.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall X::foo(void)" (?[email protected]@@UAEXXZ)
    1>...\test2.exe : fatal error LNK1120: 4 unresolved externals

    De las causas comunes incluyen:

    es allí una manera de conseguir una mejor VS enlazador errores? Para conseguir que se vea más como gcc, por ejemplo.
    Si sólo. Creo que se puede modificar de salida utilizando este, pero yo no lo he probado.
    Personalmente, creo que el MS enlazador mensajes de error son tan legible como el GCC errores. También tienen la ventaja de que incluye tanto la alterados y unmangled nombres para los externos sin resolver. Tener el trastoca nombre puede ser útil cuando usted necesita para buscar en las bibliotecas o archivos objeto directamente para ver qué podría ser el problema (por ejemplo, una convención de llamada de genes). También, no estoy seguro de qué versión de MSVC producido el error aquí, pero las versiones más recientes incluyen el nombre (tanto alterados y unmangled) de la función de referencia para el símbolo externo sin resolver.
    David Drysdale escribió un gran artículo sobre cómo enlazadores de trabajo: Guía para Principiantes Enlazadores. Dado el tema de esta pregunta, pensé que podría ser útil.
    Y cómo definir donde es mi caso?! stackoverflow.com/questions/32915615/…

    OriginalEl autor Luchian Grigore

  2. 158

    Los miembros de la clase:

    Un puro virtual destructor de las necesidades de una aplicación.

    Declarar un destructor pura todavía requiere que se defina (a diferencia de una función regular):

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

    Esto sucede porque destructores de la clase base se llama cuando el objeto se destruye de forma implícita, por lo que se requiere de una definición.

    virtual métodos deben ser implementadas o definidos como puro.

    Esto es similar a los no-virtual métodos sin definición, con el añadido de razonamiento que
    la pura declaración genera una dummy vtable y usted puede obtener el error del vinculador sin utilizar la función:

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

    Para que esto funcione, declarar X::foo() como puro:

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

    Novirtual los miembros de la clase

    Algunos miembros necesitan ser definidas incluso si no se utilizan de forma explícita:

    struct A
    { 
        ~A();
    };

    La siguiente daría el error:

    A a;      //destructor undefined

    La aplicación puede ser en línea, en la propia definición de clase:

    struct A
    { 
        ~A() {}
    };

    o fuera:

    A::~A() {}

    Si la aplicación está fuera de la definición de la clase, pero en un encabezado, los métodos han de ser marcados como inline para evitar una definición múltiple.

    Todos utilizan métodos de miembro, debe definirse si se utiliza.

    Un error común es olvidar para calificar el nombre de:

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

    La definición debe ser

    void A::foo() {}

    static miembros de datos debe ser definido fuera de la clase en un sola unidad de traducción:

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

    Un inicializador puede ser proporcionada por un static const miembro de datos integral o tipo de enumeración dentro de la definición de la clase; sin embargo, odr-el uso de este miembro se requieren de un espacio de nombres de la definición del alcance, como se describe anteriormente. C++11 permite la inicialización dentro de la clase para todos los static const miembros de datos.

    La última línea de esta respuesta es incorrecta, en la declaración de la clase es nunca una definición. (Definiciones no son necesarios para los miembros estáticos que no son odr-usa, que es común para la integral constantes en tiempo de compilación)
    No está seguro de esta parte – C++11 permite la inicialización dentro de la clase para todos los static const de datos de los miembros de la es correcta. [clase.estática.datos]/3 dice que usted necesita para marcar los miembros de datos estáticos constexpr si no están de integral o tipo de enumeración.
    No hay necesidad de definir cualquier función no virtual nunca se uso. También, no hay necesidad de definir cualquier función virtual, si usted nunca construir un objeto de la clase, ni llamarlo desde una clase derivada de realmente crear una instancia. Además, todas las funciones virtuales puras pueden ser definidos.
    frente a la «debería». Pedantically, no las funciones virtuales puras necesita ser definido (aunque, como se ha mencionado, algunos compiladores no quejarse hasta que se les llame, pero algunos). No creo que me dijo que no se puede definir puro virtuals.
    ver «Una función virtual declarada en una clase deberá ser definido, o declarado puro (10.4) en esa clase, o ambos; pero no de diagnóstico es necesaria» (10.3 funciones Virtuales) – a menos que esto se cambió en C++14

    OriginalEl autor Luchian Grigore

  3. 100

    Incumplimiento de enlace contra adecuado de bibliotecas o archivos objeto o compilar archivos de implementación

    Comúnmente, cada unidad de traducción, se generará un fichero objeto que contiene las definiciones de los símbolos definidos en los que la unidad de traducción.
    El uso de los símbolos, tiene que vincular en contra de los ficheros objeto.

    Bajo gcc tendría que especificar todos los archivos objeto que se unen en la línea de comandos, o compilar la aplicación archivos juntos.

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

    La libraryName aquí es sólo el desnudo nombre de la biblioteca, sin plataforma adiciones específicas. Así por ejemplo, en Linux los archivos de la biblioteca son generalmente llamados libfoo.so pero que solo escribir -lfoo. En Windows el mismo archivo puede ser llamado foo.lib, pero tendría que utilizar el mismo argumento. Usted podría tener que añadir el directorio donde los archivos pueden ser encontrados usando -L‹directory›. Asegúrese de no escribir un espacio después de -l o -L.

    Para XCode: Agregar el Encabezado de Usuario de Búsqueda de Caminos -> agregar la Ruta de Búsqueda de Biblioteca -> arrastrar y soltar la real biblioteca de referencia en la carpeta del proyecto.

    Bajo MSVS, los archivos agregados a un proyecto automáticamente sus archivos de objetos vinculados y un lib archivo se genera (de uso común). El uso de los símbolos en un proyecto independiente, que había
    necesidad de incluir la lib archivos en la configuración del proyecto. Esto se hace en el enlace de la sección de propiedades del proyecto, en Input -> Additional Dependencies. (la ruta de acceso a la lib archivo debe ser
    añadido en Linker -> General -> Additional Library Directories) Cuando se utiliza una librería de terceros que se proporcione con un lib archivo, de no hacerlo, por lo general resulta en el error.

    También puede suceder que usted se olvide de agregar el archivo a la compilación, en cuyo caso el objeto archivo no se crea. En gcc tendrás que añadir los archivos a la línea de comandos. En MSVS de agregar el archivo del proyecto será la que se compile automáticamente (aunque los archivos puede, manualmente, de forma individual excluidos de la acumulación).

    De programación de Windows, la señal reveladora de que no enlace de una biblioteca es necesario es que el nombre del símbolo sin resolver comienza con __imp_. Buscar el nombre de la función en la documentación, y se debe decir que la biblioteca necesita utilizar. Por ejemplo, MSDN coloca la información en un cuadro en la parte inferior de cada función en una sección llamada «Biblioteca».

    OriginalEl autor Luchian Grigore

  4. 93

    Declarado pero no define una variable o función.

    Una típica declaración de variable es

    extern int x;

    Ya que esto es sólo una declaración, un única definición es necesario. Una definición correspondiente sería:

    int x;

    Por ejemplo, lo siguiente generará un error:

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

    Similares observaciones se aplican a funciones. Se declara una función sin definir conduce al error:

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

    Tener cuidado de que la función de implementar coincide exactamente con la que se ha declarado. Por ejemplo, puede que no coinciden cv-clasificados:

    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)

    Otros ejemplos de discrepancias incluyen

    • Función/variable declarada en un espacio de nombres definido en otro.
    • Función/variable declarada como miembro de la clase, que se define como global (o viceversa).
    • Tipo de devolución de función, el parámetro de número y los tipos, y de la convención de llamada no todos exactamente de acuerdo.

    El mensaje de error del compilador suele presentar la declaración completa de la variable o función que se ha declarado pero nunca se define. Comparar de cerca a la definición proporcionada. Asegurarse de que cada detalle de los partidos.

    He omitido el nombre de la función se escribe incorrectamente como es bastante obvio. Como para los nombres de los parámetros – ¿qué?
    Las personas preguntan acerca de externos sin resolver debido a los nombres mal escritos, por lo que no es del todo evidente. (No estoy seguro de lo que se está refiriendo acerca de los nombres de los parámetros. Los nombres de los parámetros no son parte del texto).
    ya cubierto por stackoverflow.com/a/12574420/673730
    En el VS, el cpp archivos que coinciden con aquellos en el encabezado #includes no added del directorio de origen también cae bajo la categoría de falta de definiciones.

    OriginalEl autor Luchian Grigore

  5. 75

    El orden en el que interdependiente vinculados a las bibliotecas se especifica que está mal.

    El orden en el que las bibliotecas están vinculados NO importa si las bibliotecas dependen unos de otros. En general, si la biblioteca A depende de la biblioteca B, entonces libA DEBE aparecen antes de libB en el enlazador.

    Por ejemplo:

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

    Crear las bibliotecas:

    $ 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

    Compilar:

    $ 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

    Para repetir de nuevo, el orden HACE importa!

    Yo lo curioso es que en mi caso tengo un archivo de objeto que depende de una biblioteca compartida. He tenido que modificar el archivo Makefile y poner la biblioteca DESPUÉS de el objeto con gcc 4.8.4 en Debian. En Centos 6.5 con gcc 4.4 el Makefile trabajado con ningún problema.
    -Wl, – inician-grupo …..-Wl,–end-grupo resuelve este problema.

    OriginalEl autor Svalorzen

  6. 65

    ¿qué es una «referencia indefinida/símbolo externo sin resolver»

    Voy a tratar de explicar lo que es un «undefined reference/símbolo externo sin resolver».

    nota: yo uso g++ y Linux, y todos los ejemplos es que

    Por ejemplo tenemos algún código

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

    y

    //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);
    }

    Hacer objeto de archivos

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

    Después de que el ensamblador fase tenemos un objeto de archivo, que contiene todos los símbolos a la exportación.
    Mira los símbolos

    $ 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]

    He rechazado algunas de las líneas de salida, porque no importa

    Así, vemos siga símbolos para la exportación.

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

    src2.cpp las exportaciones de nada y no hemos visto ninguna de sus símbolos

    Link de nuestro objeto de archivos

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

    y ejecutar

    $ ./prog
    123

    Vinculador ve símbolos exportados y enlaces. Ahora tratamos de descomentar las líneas en src2.cpp como aquí

    //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);
    }

    y volver a generar un archivo de objeto

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

    ACEPTAR (sin errores), ya que sólo construir objeto de archivo, el enlace no es de hecho todavía.
    Tratar de vincular

    $ 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

    Que ha sucedido a causa de nuestra local_var_name es estático, es decir, no es visible para otros módulos.
    Ahora más profundamente. Obtener la traducción de la fase de salida

    $ 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

    Así, hemos visto que no hay etiqueta para local_var_name, es por eso que el enlazador no se ha encontrado. Pero somos hackers 🙂 y podemos solucionarlo. Abierto src1.s en tu editor de texto y cambiar

    .local  _ZL14local_var_name
    .comm   _ZL14local_var_name,4,4

    a

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

    es decir, debe tener, como el de abajo

        .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:
    ; ...

    hemos cambiado la visibilidad de local_var_name y establezca su valor a 456789.
    Tratar de construir un objeto de archivo

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

    ok, nos vemos readelf de salida (símbolos)

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

    ahora local_var_name ha Enlazar GLOBAL (LOCAL)

    link

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

    y ejecutar

    $ ./prog 
    123456789

    ok, nos hack 🙂

    Así que, como resultado – un «undefined reference/externos sin resolver símbolo de error» ocurre cuando el enlazador no puede encontrar símbolos globales en los archivos objeto.

    OriginalEl autor

  7. 62

    Símbolos que se definen en un programa en C y se utiliza en el código de C++.

    La función (o variable) void foo() fue definido en un programa en C y que intente utilizarlo en un programa de C++:

    void foo();
    int main()
    {
        foo();
    }

    El C++ linker espera nombres para ser destrozados, así que usted tiene que declarar la función como:

    extern "C" void foo();
    int main()
    {
        foo();
    }

    Equivalentemente, en lugar de ser definido en un programa de C, la función (o variable) void foo() fue definido en C++ pero con C de vinculación:

    extern "C" void foo();

    y que intente utilizarlo en un programa de C++ con C++ vinculación.

    Si toda una biblioteca está incluido en un archivo de encabezado (y fue compilado como C código); el incluir tendrá que ser de la siguiente manera;

    extern "C" {
        #include "cheader.h"
    }
    O, por el contrario, Si el desarrollo de una biblioteca de C, una buena regla es proteger el archivo de encabezado(s) rodeando exportadas todas las declaraciones con #ifdef __cplusplus [\n] extern"C" { [\n] #endif y #ifdef __cplusplus [\n] } [\n] #endif ([\n] ser real, retorno de carro pero no puedo escribir bien en el comentario).
    Como en el comentario de arriba, la ‘Creación de Lenguaje Mixto Encabezados de sección ayudado a: oracle.com/technetwork/articles/servers-storage-dev/…

    OriginalEl autor Luchian Grigore

  8. 59

    Si todo lo demás falla, vuelva a compilar.

    Recientemente fue capaz de deshacerse de un error externo sin resolver en Visual Studio 2012 sólo por volver a compilar el archivo que se ofende. Cuando me re-construido, el error se fue.

    Esto generalmente sucede cuando dos (o más) de las bibliotecas tienen un ciclo de dependencia. La biblioteca de Una intentos para utilizar símbolos en B. lib y biblioteca B intentos de utilizar los símbolos de A. lib. Ni existen para empezar. Cuando intento compilar Una, el vínculo paso fallará porque no puede encontrar B. lib. A. lib será generado, pero no de dll. A continuación, compila B, que va a tener éxito y generar B. lib. Re-compilación de Un ahora funcionará porque B. lib se encuentra ahora.

    Correcto – esto ocurre cuando las bibliotecas tienen un ciclo de dependencia.
    He ampliado en su respuesta, y vinculado en la principal. Gracias.

    OriginalEl autor sgryzko

  9. 51

    Incorrectamente la importación/exportación de métodos y clases a través de módulos/dll (compilador).

    MSVS requiere especificar que los símbolos de la exportación y la importación mediante __declspec(dllexport) y __declspec(dllimport).

    Esta doble funcionalidad se obtiene generalmente mediante el uso de una macro:

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

    La macro THIS_MODULE sólo sería definido en el módulo de exportación de la función. De esa manera, la declaración:

    DLLIMPEXP void foo();

    se expande a

    __declspec(dllexport) void foo();

    y le dice al compilador para exportar la función, como el actual módulo contiene su definición. Siempre y cuando se incluya la declaración en un módulo diferente, se expandiría a

    __declspec(dllimport) void foo();

    y le dice al compilador que la definición se encuentra en una de las librerías con las que se enlaza (ver también 1)).

    Puede similarmente importación/exportación de clases:

    class DLLIMPEXP X
    {
    };
    Para ser completo, esta respuesta debería mencionar GCC visibility y Windows’ .def archivos, ya que estos también influyen en el nombre del símbolo y de su presencia.
    No he utilizado .def archivos en las edades. Siéntase libre de añadir una respuesta o editar este.

    OriginalEl autor Luchian Grigore

  10. 49

    De la plantilla de las implementaciones no visible.

    No especializada plantillas deben tener sus definiciones visible para todas las unidades de traducción que hacen uso de ellos. Eso significa que no se puede separar la definición de una plantilla
    para un archivo de implementación. Si usted debe separar la implementación, la solución habitual es tener un impl archivo que se incluyen al final de la cabecera que
    declara la plantilla. Una situación común es:

    template<class T>
    struct X
    {
        void foo();
    };
    
    int main()
    {
        X<int> x;
        x.foo();
    }
    
    //differentImplementationFile.cpp
    template<class T>
    void X<T>::foo()
    {
    }

    Para solucionar este problema, debe mover la definición de X::foo para el archivo de encabezado o en algún lugar visible de la unidad de traducción en el que se usa.

    Plantillas especializadas puede ser implementado en un archivo de implementación y la aplicación no tiene que ser visible, pero la especialización debe ser declarado previamente.

    Para una explicación más detallada y otra posible solución (la creación de instancias explícita) ver esta pregunta y la respuesta.

    Más información», las plantillas deben ser definidas en el encabezado» se puede encontrar en stackoverflow.com/questions/495021

    OriginalEl autor Luchian Grigore

  11. 48

    Este es uno de los más confusos mensajes de error que cada VC++ programadores han visto una y otra vez. Vamos a hacer las cosas claridad en primer lugar.

    A. ¿Qué es un símbolo?
    En definitiva, un símbolo es un nombre. Puede ser un nombre de variable, una función de nombre, un nombre de clase, un typedef nombre, o nada, a excepción de los nombres y signos que pertenecen al lenguaje C++. Es definido por el usuario o introducida por una dependencia de la biblioteca (otro definido por el usuario).

    B. Lo que es externo?
    En VC++, cada archivo de código fuente (.cpp,.c,etc.) se considera como una unidad de traducción, el compilador compila una unidad a la vez, y generar un archivo objeto(.obj) para la traducción actual de la unidad. (Tenga en cuenta que cada archivo de encabezado que este archivo de origen serán procesados y serán considerados como parte de esta unidad de traducción)Todo dentro de una unidad de traducción es considerada como interno, todo lo demás es considerado como externo. En C++, se puede hacer referencia a un símbolo externo mediante el uso de palabras clave como extern, __declspec (dllimport) y así sucesivamente.

    C. ¿Qué es «resolver»?
    Resolver es un enlace en tiempo de plazo. En la vinculación de tiempo, enlazador intenta encontrar la definición externa para cada símbolo en archivos objeto que no puede encontrar su definición internamente. El alcance de este proceso de búsqueda, incluyendo:

    • Todos los archivos objeto que se generan en la compilación de tiempo
    • Todas las bibliotecas (.lib) que son explícita o implícitamente
      especificado como otras dependencias de este edificio de la aplicación.

    Este proceso de búsqueda es llamado a resolver.

    D. por último, ¿por qué no Resueltos Símbolo Externo?
    Si el enlazador no puede encontrar la definición externa de un símbolo que no tiene definición internamente, informa de un Símbolo Externo sin resolver el error.

    E. Posibles causas de LNK2019: Unresolved External Símbolo de error.
    Ya sabemos que este error es debido a que el enlazador no se pudo encontrar la definición de símbolos externos, las posibles causas pueden ser clasificados como:

    1. Existe una definición

    Por ejemplo, si tenemos una función llamada foo definido en a.cpp:

    int foo()
    {
        return 0;
    }

    En b.cpp queremos llamar a la función foo, por lo tanto, añadir

    void foo();

    para declarar la función foo(), y se llama en otro cuerpo de la función, decir bar():

    void bar()
    {
        foo();
    }

    Ahora cuando la generación de este código recibirás un LNK2019 error quejándose de que foo es un símbolo sin resolver. En este caso, sabemos que foo() tiene su definición en a.cpp pero diferente de la que estamos llamando(diferente valor de retorno). Este es el caso que existe una definición.

    1. Definición no existe

    Si queremos llamar a algunas de las funciones en una biblioteca, pero la importación de la biblioteca, no se agrega a la dependencia adicional de la lista (conjunto de: Project | Properties | Configuration Properties | Linker | Input | Additional Dependency) de la configuración del proyecto. Ahora el vinculador informe de un LNK2019 ya que la definición no existe en la actual búsqueda de alcance.

    Compatriota su respuesta fue agradable

    OriginalEl autor Nima Soroush

  12. 34

    indefinido referencia a [email protected] o similar ‘inusual’ main() punto de entrada de referencia (especialmente para ).

    Es posible que haya perdido el derecho de elegir el tipo de proyecto con su IDE. El IDE puede que desee enlazar por ejemplo, proyectos de Aplicación de Windows a tal punto de entrada de la función (como se especifica en la falta de referencia más arriba), en lugar de los comúnmente utilizados int main(int argc, char** argv); firma.

    Si su IDE soporta Llanura de la Consola de Proyectos es posible que desee elegir este tipo de proyecto, en lugar de un proyecto de aplicación para windows.


    Aquí se case1 y case2 manejado en más detalle a partir de un mundo real problema.

    No puede dejar de señalar esta pregunta y el hecho de que esto es más a menudo causada por no tener ninguna función principal en todos los que no teniendo WinMain. Válido en C++ los programas necesitan un main.

    OriginalEl autor πάντα ῥεῖ

  13. 32

    Además, si estás utilizando la 3ª parte de las bibliotecas de asegurarse de que tiene la correcta 32/64 bits binarios

    OriginalEl autor Dula

  14. 32

    Microsoft ofrece una #pragma para hacer referencia a la biblioteca correcta en el momento de enlazar;

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

    Además de la ruta de la biblioteca, incluyendo el directorio de la biblioteca, este debe ser el nombre completo de la biblioteca.

    OriginalEl autor Niall

  15. 31

    Visual Studio paquete de NuGet necesita ser actualizado para el nuevo conjunto de herramientas de la versión

    Yo sólo tenía este problema, tratando de vincular libpng con Visual Studio 2013. El problema es que el archivo de paquete sólo tenían bibliotecas de Visual Studio 2010 y 2012.

    La solución correcta es la esperanza de que el desarrollador libera una actualización del paquete y, a continuación, actualizar, pero a mí me funcionó por hacking en una configuración extra para VS2013, apuntando a la VS2012 los archivos de la biblioteca.

    He editado el paquete (en el packages carpeta dentro de la solución del directorio) por la búsqueda de packagename\build\native\packagename.targets y dentro de ese archivo, copiar todos los v110 secciones. He cambiado el v110 a v120 en la condición de los campos sólo de ser muy cuidadosos para dejar el nombre de archivo de todas las rutas de acceso como v110. Esta permitido simplemente Visual Studio 2013 para vincular a las bibliotecas para el año 2012, y en este caso, se trabajó.

    Esto parece demasiado específico – tal vez un nuevo hilo sería un lugar mejor para esta respuesta.
    Quería post aquí como que la pregunta era exactamente este problema, pero fue marcado como un duplicado de esta pregunta, así que no podía responder. Así que he publicado mi respuesta aquí en su lugar.
    Esa pregunta ya ha aceptado la respuesta. Es marcado como duplicados porque la causa general se muestra más arriba. ¿Qué pasaría si tuviéramos aquí una respuesta para cada proble con una biblioteca que no está incluido?
    Este problema no es específico para una biblioteca, que afecta a todas las bibliotecas de uso de Visual Studio gestión de paquetes del sistema. Me acaba de pasar para encontrar la otra pregunta, ya que ambos tuvieron problemas con libpng. Yo también tenía el mismo problema (con la misma solución) para libxml2, libiconv y glew. Esa pregunta es acerca de un problema con Visual Studio sistema de gestión de paquetes, y mi respuesta explica la razón y proporciona una solución. Alguien vio «unresolved external» y supuse que era una norma enlazador problema cuando en realidad es un paquete de gestión de problema.

    OriginalEl autor Malvineous

  16. 30

    Suponga que tiene un gran proyecto por escrito en c++, que cuenta con un millar de .archivos cpp y un mil .h archivos.Y vamos, dice el proyecto también depende de diez bibliotecas estáticas. Vamos dice que estamos en Windows y vamos a construir nuestro proyecto en Visual Studio 20xx. Cuando usted presione Ctrl + F7 Visual Studio para empezar a recopilar toda la solución ( supongamos que sólo tenemos un proyecto en la solución )

    ¿Cuál es el significado de compilación ?

    • Visual Studio de búsqueda en el archivo .vcxproj y empezar a recopilar cada archivo que tiene la extensión .cpp. Orden de compilación es de carácter indefinido.Así que usted no debe suponer que el archivo main.cpp se compila primera
    • Si .archivos cpp depende adicionales .h archivos con el fin de encontrar símbolos
      que puede o no puede ser definido en el archivo .cpp
    • Si existe uno .archivo cpp en el que el compilador no pudo encontrar un símbolo, un compilador error de tiempo de plantea el mensaje Símbolo x no se pudo encontrar
    • Para cada archivo con la extensión .cpp se genera un archivo objeto .oh, y también de Visual Studio escribe el resultado en un archivo denominado ProjectName.Cpp.Clean.txt que contiene todos los archivos objeto que debe ser procesada por el enlazador.

    El Segundo paso de la compilación se realiza por el Enlazador.Enlazador debe combinar todos los objetos de archivo y construir finalmente la salida ( que puede ser un ejecutable o una biblioteca)

    Pasos En la Vinculación de un proyecto

    • Analizar todos los archivos objeto y encontrar la definición que sólo se había declarado en los encabezados ( por ejemplo: El código de un método de una clase de como se menciona en las respuestas anteriores, o en caso de que la inicialización de una variable estática que es miembro dentro de una clase)
    • Si un símbolo no se encuentra en los archivos de objeto también es buscado en Bibliotecas Adicionales.Para añadir una biblioteca a un proyecto propiedades de Configuración de -> Directorios de VC++ – > Biblioteca Directorios y aquí especificado carpeta adicional para la búsqueda de bibliotecas y propiedades de Configuración de -> Enlazador -> de Entrada para especificar el nombre de la biblioteca.
      -Si el Vinculador no se pudo encontrar el símbolo con el que se puede escribir en uno .cpp se plantea una linker error de tiempo de que puede sonar como
      error LNK2001: unresolved external symbol "void __cdecl foo(void)" ([email protected]@YAXXZ)

    Observación

    1. Una vez que el Enlazador encontrar un símbolo que no buscar en otras bibliotecas para que
    2. El orden de la vinculación de las bibliotecas importa.
    3. Si encuentra Vinculador un símbolo externo en una biblioteca estática se incluye el símbolo en el producto del proyecto.Sin embargo, si la biblioteca es compartida( dinámico ) no incluir el código ( símbolos ) en la salida, pero Tiempo de Ejecución los accidentes pueden ocurrir

    Cómo Solucionar este tipo de error

    Compilador De Error De Tiempo :

    • Asegúrese de escribir su proyecto de c++ sintáctica correcta.

    Linker Error De Tiempo De

    • Definir todos los símbolos que se declara en los archivos de encabezado
    • Uso #pragma once para permitir que el compilador no incluir un encabezado si ya estaba incluido en el actual .cpp el cual se compilan
    • Asegúrese de que el exterior de la biblioteca no contiene símbolos que pueden entrar en conflicto con otros símbolos que se definen en los archivos de encabezado
    • Cuando se utiliza la plantilla para asegurarse de incluir la definición de cada función de la plantilla en el archivo de encabezado para permitir que el compilador genere código apropiado para cualquiera de las instancias.
    No es que su respuesta es específica para visual studio? La pregunta no especifica ningún IDE/compilador de herramientas de modo que hace que su respuesta inútil para los no-visual-studio parte.
    Estás en lo correcto . Pero cada en cada IDE proceso de compilación y vinculación que se hace de forma ligeramente diferente.Pero los archivos se procesan exactamente de la misma ( incluso g++ hacer lo mismo cuando se analiza las banderas.. )
    El problema no es realmente acerca de la IDE pero se trata de una respuesta para la vinculación de los problemas. La vinculación de los problemas no están relacionados con el IDE, pero para el compilador y proceso de construcción.
    Sí.Pero la build/proceso de vinculación que se hace en g++/Visual Studio(compilador proporcionada por Microsoft para VS )/Eclipse/Net Beans de la misma manera

    OriginalEl autor

  17. 26

    Un error en el compilador/IDE

    Recientemente he tenido este problema, y resultó fue un error de Visual Studio Express 2013. Tuve que eliminar un archivo de código fuente del proyecto y volver a añadirlo a superar el error.

    Pasos para probar si usted cree que puede ser un error en el compilador/IDE:

    • Limpie el proyecto (algunos IDEs tiene una opción para hacer esto, usted también puede
      hacer manualmente eliminando los archivos de objeto)
    • Intentar iniciar un nuevo proyecto,
      copia todo el código fuente de la original.
    La creencia de que sus herramientas están rotos es más probable que va a mantenerse alejado de la verdadera causa. Es mucho más probable que usted cometió un error que un compilador causado el problema. La limpieza de su solución o volver a crear la configuración de generación, se puede solucionar errores de compilación, pero eso no significa que hay un error en el compilador. Los enlaces de «resultó que era un error» no se ha confirmado por parte de Microsoft y no es reproducible.
    Hay 21 respuestas en esta pregunta y, por tanto, una cantidad significativa de respuestas no van a ser una «probable» de la solución. Si usted rechaza todas las respuestas que están por debajo de su umbral de probabilidad, a continuación, en esta página de manera efectiva se vuelve inútil, ya que la mayoría de los casos son fáciles de ver de todos modos.

    OriginalEl autor developerbmw

  18. 23

    Vinculados .archivo lib está asociado a una .dll

    He tenido el mismo problema. Decir que tengo proyectos Miproyecto y TestProject. Efectivamente había vinculado el archivo lib para Miproyecto a la TestProject. Sin embargo, este archivo lib producido como DLL para el Miproyecto fue construido. Además, yo no contienen el código fuente para todos los métodos en la MyProject, pero sólo el acceso a la DLL punto de entrada.

    Para resolver el problema, he construido el Miproyecto como LIB, y vinculado TestProject a este .archivo lib (i copiar y pegar el generado .archivo lib en el TestProject carpeta). Luego se pueden construir de nuevo Miproyecto como un archivo DLL. Es una compilación, ya que la lib para que TestProject está vinculado contiene código para todos los métodos en las clases en Miproyecto.

    OriginalEl autor octoback

  19. 23

    Utilizar el enlazador para ayudar a diagnosticar el error

    Más modernos enlazadores de incluir una opción verbose que imprime en diferentes grados;

    • Enlace invocación (línea de comandos),
    • Datos sobre lo que las bibliotecas se incluyen en el enlace de la etapa,
    • La ubicación de las bibliotecas,
    • Rutas de búsqueda utilizado.

    Para gcc y clang; normalmente, se agregaría -v -Wl,--verbose o -v -Wl,-v a la línea de comandos. Más detalles se pueden encontrar aquí;

    Para MSVC, /VERBOSE (en particular /VERBOSE:LIB) se agrega a la línea de comandos link.

    OriginalEl autor Niall

  20. 18

    Ya que la gente parece estar dirigido a esta pregunta cuando se trata de errores del vinculador voy a añadir esta aquí.

    Una posible razón para errores del vinculador con GCC 5.2.0 es que una nueva libstdc++ biblioteca de ABI ahora es elegido por defecto.

    Si obtiene errores del vinculador sobre indefinido referencias a símbolos que implican los tipos en el std::__cxx11 espacio de nombres o de la etiqueta de [abi:cxx11] entonces, esto indica que probablemente usted está tratando de unir los archivos de objetos que fueron compilados con diferentes valores para el _GLIBCXX_USE_CXX11_ABI macro. Esto sucede comúnmente cuando se une a una tercera parte de la biblioteca que fue compilado con una versión de GCC. Si la tercera parte de la biblioteca no se puede generar con la nueva ABI entonces usted tendrá que volver a compilar el código con el viejo ABI.

    Así que si de pronto te encuentras enlazador errores al cambiar a una GCC después de 5.1.0 esto va a ser cosa de la salida.

    OriginalEl autor Plankalkül

  21. 17

    Una envoltura alrededor de GNU ld que no admite enlazador de secuencias de comandos

    Algunos .por lo que los archivos son en realidad GNU enlazador ld secuencias de comandos, por ejemplo, libtbb.así archivo es un archivo de texto ASCII con este contenido:

    INPUT (libtbb.so.2)

    Algunas más complejas construye pueden no ser compatibles con esta. Por ejemplo, si incluye -v en las opciones del compilador, se puede ver que el mainwin gcc contenedor mwdip descartes linker script de comandos de archivos en la salida detallada lista de las bibliotecas de enlace. Un simple trabajo de todo es reemplazar el linker script de entrada de comando archivo con una copia del archivo en lugar de (o un enlace), por ejemplo,

    cp libtbb.so.2 libtbb.so

    O usted podría reemplazar el argumento-l con la ruta de acceso completa de la .así, por ejemplo, en lugar de -ltbb hacer /home/foo/tbb-4.3/linux/lib/intel64/gcc4.4/libtbb.so.2

    OriginalEl autor JDiMatteo

  22. 16

    Amistad con plantillas…

    Dado que el fragmento de código de un tipo de plantilla con un amigo operador (o función);

    template <typename T>
    class Foo {
        friend std::ostream& operator<< (std::ostream& os, const Foo<T>& a);
    };

    La operator<< se declara como un no-función de la plantilla. Para cada tipo de T utilizado con Foo, tiene que ser un no-con plantilla operator<<. Por ejemplo, si hay un tipo de Foo<int> declarado, entonces no debe ser un operador de la aplicación de la siguiente manera;

    std::ostream& operator<< (std::ostream& os, const Foo<int>& a) {/*...*/}

    Ya que no está implementado, el enlazador no puede encontrar y resultados en el error.

    Para corregir esto, usted puede declarar una plantilla de operador antes de la Foo tipo y, a continuación, declarar como a un amigo, el de la creación de instancias. La sintaxis es un poco torpe, pero se ve de la siguiente manera;

    //forward declare the Foo
    template <typename>
    class Foo;
    
    //forward declare the operator <<
    template <typename T>
    std::ostream& operator<<(std::ostream&, const Foo<T>&);
    
    template <typename T>
    class Foo {
        friend std::ostream& operator<< <>(std::ostream& os, const Foo<T>& a);
        //note the required <>        ^^^^
        //...
    };
    
    template <typename T>
    std::ostream& operator<<(std::ostream&, const Foo<T>&)
    {
      //... implement the operator
    }

    El código de arriba de los límites de la amistad de el operador a la correspondiente creación de instancias de Foo, es decir, el operator<< <int> la creación de instancias es limitado acceso a los miembros privados de la creación de instancias de Foo<int>.

    Alternativas incluyen;

    • Permitiendo la amistad para extender a todas las instancias de las plantillas, de la siguiente manera;

      template <typename T>
      class Foo {
          template <typename T1>
          friend std::ostream& operator<<(std::ostream& os, const Foo<T1>& a);
          //...
      };
    • O, la aplicación de la operator<< se puede hacer en línea dentro de la definición de clase;

      template <typename T>
      class Foo {
          friend std::ostream& operator<<(std::ostream& os, const Foo& a)
          { /*...*/ }
          //...
      };

    Nota, cuando la declaración del operador (o función) sólo aparece en la clase, el nombre no está disponible para los «normales» de la búsqueda, sólo para el argumento de la búsqueda dependiente, de cppreference;

    Un nombre de la primera vez que se declaró en un amigo de la declaración dentro de la clase o de la plantilla de clase X se convierte en un miembro de la recóndita, adjuntando el espacio de nombres de X, pero no es accesible para la búsqueda (excepto la búsqueda dependiente de argumentos que considera X), a menos que la coincidencia de la declaración en el ámbito de espacio de nombres es siempre…

    Hay más información sobre la plantilla de amigos en cppreference y la C++ FAQ.

    Listado de código muestra las técnicas de más arriba.


    Como una nota de lado a la falta de ejemplo de código; g++ advierte acerca de esto de la siguiente manera

    warning: friend declaration 'std::ostream& operator<<(...)' declares a non-template function [-Wnon-template-friend]

    note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)

    OriginalEl autor Niall

  23. 13

    Inconsistente UNICODE definiciones

    Un Windows UNICODE está construido con TCHAR etc. se define como wchar_t etc. Cuando no edificio con UNICODE define como construir con TCHAR define como char etc. Estos UNICODE y _UNICODE define afectan a todos los «T» tipos de cadena; LPTSTR, LPCTSTR y sus elk.

    La construcción de una biblioteca con UNICODE definido y tratando de enlace en un proyecto donde UNICODE no está definido resultará en errores del vinculador ya que habrá una falta de coincidencia en la definición de TCHAR; char vs wchar_t.

    El error por lo general incluye una función de un valor con un char o wchar_t tipo derivado, estos podrían incluir std::basic_string<> etc. así. Cuando la navegación a través de la función afectada en el código, con frecuencia, habrá una referencia a TCHAR o std::basic_string<TCHAR> etc. Esto es un indicio claro de que el código fue originalmente destinado tanto para UNICODE y una de Caracteres Multi-Byte (o «estrecho») de la compilación.

    Para corregir esto, la construcción de todas las bibliotecas necesarias y proyectos con una definición coherente de UNICODE (y _UNICODE).

    1. Esto se puede hacer con cualquiera;

      #define UNICODE
      #define _UNICODE
    2. O en la configuración del proyecto;

      Propiedades del proyecto > General > los valores Predeterminados del Proyecto > Conjunto de Caracteres

    3. O en la línea de comandos;

      /DUNICODE /D_UNICODE

    La alternativa es aplicable, así que, si UNICODE no es la intención de ser usado, asegúrese de que la define no están establecidos, y/o el multi-ajuste de caracteres usados en los proyectos y consistentemente aplicados.

    No te olvides de ser coherente entre la «Liberación» y «Depuración» construye así.

    OriginalEl autor Niall

  24. 12

    Limpiar y reconstruir

    Una «limpia» de la generación puede quitar la «madera muerta» que puede ser de la izquierda se extiende alrededor de las generaciones anteriores, el error se basa, incompleta construye y otro sistema de construcción relacionados con los problemas de generación.

    En general, el IDE o construir incluirá alguna forma de «limpiar» la función, pero esto puede no ser correctamente configurado (por ejemplo, en un manual de makefile) o no (por ejemplo, el intermedio o el resultante binarios son de sólo lectura).

    Una vez que la «limpia» se ha completado, compruebe que la «limpia» ha logrado y todos los generados archivo intermedio (por ejemplo, un fichero automatizado de makefile) se han eliminado con éxito.

    Este proceso puede ser visto como un último recurso, pero a menudo es un buen primer paso; especialmente si el código relacionado con el error ha sido añadido recientemente (ya sea localmente o desde el repositorio de código fuente).

    OriginalEl autor Niall

  25. 12

    Cuando tu incluyen rutas de acceso son diferentes

    Enlazador errores pueden ocurrir cuando un encabezado de archivo y su biblioteca compartida asociada (.archivo lib) ir fuera de sincronización. Me explico.

    ¿Cómo enlazadores de trabajo? El vinculador coincide con una declaración de función (declarada en la cabecera) con su definición (en la biblioteca compartida) mediante la comparación de sus firmas. Usted puede obtener un error del vinculador si el vinculador no encontrar la definición de una función que coincida a la perfección.

    Es posible aún obtener un error del vinculador aunque la declaración y la definición parecen coincidir? Sí! Se podría ver de la misma en el código fuente, pero realmente depende de lo que el compilador ve. Esencialmente, usted podría terminar con una situación como esta:

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

    Nota cómo a pesar de que tanto las declaraciones de función de un aspecto idéntico en el código fuente, pero en realidad son diferentes según el compilador.

    Usted podría preguntar cómo termina en una situación como esa? Incluir rutas de curso! Si durante la compilación de la biblioteca compartida, la ruta conduce a header1.h y terminas usando header2.h en su propio programa, te quedará rascarse la cabecera preguntándose qué pasó (juego de palabras).

    Un ejemplo de cómo esto puede suceder en el mundo real se explica a continuación.

    Mayor elaboración con un ejemplo

    Tengo dos proyectos: graphics.lib y main.exe. Ambos proyectos dependen de common_math.h. Supongamos que la biblioteca de las exportaciones de la siguiente función:

    //graphics.lib    
    #include "common_math.h" 
    
    void draw(vec3 p) { ... } //vec3 comes from common_math.h

    Y, a continuación, seguir adelante y la biblioteca se incluirá en su propio proyecto.

    //main.exe
    #include "other/common_math.h"
    #include "graphics.h"
    
    int main() {
        draw(...);
    }

    Boom! Usted obtiene un error del vinculador y usted no tiene idea de por qué se está fallando. La razón es que el común de la biblioteca utiliza diferentes versiones de la misma incluyen common_math.h (he hecho evidente en el ejemplo mediante la inclusión de un camino diferente, pero es posible que no siempre es tan obvio. Tal vez la ruta es diferente en la configuración de compilador).

    Nota en este ejemplo, el vinculador iba a decirle que no podía encontrar draw(), cuando en realidad sabes que es evidente que está siendo exportado por la biblioteca. Usted podría pasar horas rascándose la cabeza preguntándose qué salió mal. La cosa es que el vinculador ve una firma diferente debido a los tipos de parámetros son ligeramente diferentes. En el ejemplo, vec3 es un tipo diferente en ambos proyectos tan lejos como el compilador de que se trate. Esto podría suceder porque vienen de dos ligeramente diferentes archivos de inclusión (tal vez el de incluir archivos vienen en dos diferentes versiones de la biblioteca).

    La depuración de la enlazador

    DUMPBIN es tu amigo, si usted está utilizando Visual Studio. Estoy seguro de que otros compiladores tienen otras herramientas similares.

    El proceso funciona así:

    1. Nota el extraño trastoca nombre dado en el error del vinculador. (por ejemplo. sorteo [email protected]áficos [email protected]).
    2. El volcado de los símbolos exportados de la biblioteca en un archivo de texto.
    3. Buscar el símbolo exportado de interés, y el aviso de que la trastoca nombre es diferente.
    4. Prestar atención a por qué los nombres alterados terminó diferentes. Usted sería capaz de ver que los tipos de parámetros son diferentes, aunque tienen el mismo aspecto en el código fuente.
    5. Razón por qué son diferentes. En el ejemplo dado anteriormente, son diferentes debido a los diferentes archivos de inclusión.

    [1] Por el proyecto, me refiero a un conjunto de archivos de código fuente que se unen para producir una biblioteca o un archivo ejecutable.

    EDIT 1: reescritura de la primera sección de ser más fácil de entender. Por favor comente abajo para hágamelo saber si hay algo más que necesita ser arreglado. Gracias!

    OriginalEl autor fafaro

  26. 11

    Su vinculación consume bibliotecas antes de que el objeto de los archivos que se refieren a ellos

    • Usted está tratando de compilar y enlazar el programa con el GCC toolchain.
    • Su vinculación especifica todos los recursos de las bibliotecas y de las rutas de búsqueda
    • Si libfoo depende de libbar, entonces su vinculación correctamente pone libfoo antes de libbar.
    • Su vinculación falla con undefined reference to algo errores.
    • Pero todas las indefinido algos se declaran en la cabecera de los archivos que ha
      #included y son, de hecho, define en las bibliotecas que se vincula.

    Ejemplos son en C. Que igual podría ser C++

    Un ejemplo mínimo que implican una biblioteca estática se construye a sí mismo

    my_lib.c

    #include "my_lib.h"
    #include <stdio.h>
    
    void hw(void)
    {
        puts("Hello World");
    }

    my_lib.h

    #ifndef MY_LIB_H
    #define MT_LIB_H
    
    extern void hw(void);
    
    #endif

    eg1.c

    #include <my_lib.h>
    
    int main()
    {
        hw();
        return 0;
    }

    A construir su biblioteca estática:

    $ gcc -c -o my_lib.o my_lib.c
    $ ar rcs libmy_lib.a my_lib.o

    De compilar el programa:

    $ gcc -I. -c -o eg1.o eg1.c

    Intenta vincular con libmy_lib.a y fallar:

    $ gcc -o eg1 -L. -lmy_lib eg1.o 
    eg1.o: In function `main':
    eg1.c:(.text+0x5): undefined reference to `hw'
    collect2: error: ld returned 1 exit status

    El mismo resultado si compilar y vincular en un solo paso, como:

    $ gcc -o eg1 -I. -L. -lmy_lib eg1.c
    /tmp/ccQk1tvs.o: In function `main':
    eg1.c:(.text+0x5): undefined reference to `hw'
    collect2: error: ld returned 1 exit status

    Un ejemplo mínimo que implican un sistema compartido de biblioteca, la biblioteca de compresión libz

    eg2.c

    #include <zlib.h>
    #include <stdio.h>
    
    int main()
    {
        printf("%s\n",zlibVersion());
        return 0;
    }

    Compilar su programa:

    $ gcc -c -o eg2.o eg2.c

    Intenta vincular el programa con libz y fallar:

    $ gcc -o eg2 -lz eg2.o 
    eg2.o: In function `main':
    eg2.c:(.text+0x5): undefined reference to `zlibVersion'
    collect2: error: ld returned 1 exit status

    Mismo si compilar y vincular en uno:

    $ gcc -o eg2 -I. -lz eg2.c
    /tmp/ccxCiGn7.o: In function `main':
    eg2.c:(.text+0x5): undefined reference to `zlibVersion'
    collect2: error: ld returned 1 exit status

    Y una variación en el ejemplo 2, relativas a pkg-config:

    $ gcc -o eg2 $(pkg-config --libs zlib) eg2.o 
    eg2.o: In function `main':
    eg2.c:(.text+0x5): undefined reference to `zlibVersion'

    ¿Qué estás haciendo mal?

    En la secuencia de objeto de archivos y bibliotecas desea vincular a hacer su
    programa, la colocación de las bibliotecas antes de que el objeto de los archivos que se refieren a
    ellos. Es necesario colocar las bibliotecas después de los archivos objeto que se refieren
    para ellos.

    Link del ejemplo 1 correctamente:

    $ gcc -o eg1 eg1.o -L. -lmy_lib

    Éxito:

    $ ./eg1 
    Hello World

    Link ejemplo 2 correctamente:

    $ gcc -o eg2 eg2.o -lz

    Éxito:

    $ ./eg2 
    1.2.8

    Link en el ejemplo 2 pkg-config variación correctamente:

    $ gcc -o eg2 eg2.o $(pkg-config --libs zlib) 
    $ ./eg2
    1.2.8

    La explicación

    La lectura es opcional a partir de aquí en.

    Por defecto, una vinculación comando generado por GCC, en su distribución,
    consume los archivos en la vinculación de izquierda a derecha en
    línea de comandos de la secuencia. Cuando se encuentra que un archivo se refiere a algo
    y no contiene una definición del mismo, se busca una definición
    en los archivos de más a la derecha. Si finalmente se encuentra una definición, la
    de referencia se ha resuelto. Si las referencias no resueltas al final,
    la vinculación de falla: el vinculador no buscar hacia atrás.

    Primero, ejemplo 1, con biblioteca estática my_lib.a

    Una biblioteca estática es un archivo indexado de archivos de objeto. Cuando el enlazador
    encuentra -lmy_lib en la vinculación de la secuencia y las cifras que se refiere este
    a la biblioteca estática ./libmy_lib.a, que quiere saber si su programa
    las necesidades de cualquiera de los archivos objeto en libmy_lib.a.

    No es sólo objeto de archivo en libmy_lib.a, es decir,my_lib.o, y sólo hay una cosa que define
    en my_lib.o, a saber, la función hw.

    El vinculador se decide que el programa de necesidades my_lib.o si y sólo si ya se sabe que
    el programa se refiere a hw, en uno o más de los archivos objeto que ya ha
    añadido al programa, y que ninguno de los archivos objeto que ya ha añadido
    contiene una definición para hw.

    Si que es cierto, es que el conector que va a extraer una copia de my_lib.o de la biblioteca y
    añadir a su programa. A continuación, el programa contiene una definición para hw, por lo que
    sus referencias a hw son resuelto.

    Cuando se intenta vincular el programa como:

    $ gcc -o eg1 -L. -lmy_lib eg1.o

    el vinculador no ha añadido eg1.o para el programa cuando ve
    -lmy_lib. Porque en ese momento, no ha visto eg1.o.
    El programa no hace ninguna referencia a hw:
    aún no hacen ninguna referencia en todos los, porque todas las referencias que hace
    en eg1.o.

    Para que el enlazador no agrega my_lib.o para el programa y no tiene más
    el uso de libmy_lib.a.

    Siguiente, se encuentra con que eg1.o, y se agrega a ser el programa. Un archivo de objeto de la
    la vinculación de la secuencia siempre es añadido al programa. Ahora, el programa hace
    una referencia a hw, y no contiene una definición de hw; pero
    no hay nada a la izquierda en la vinculación de la secuencia que podría proporcionar la falta
    definición. La referencia a hw termina sin resolver, y la vinculación que se produce un error.

    Segundo, ejemplo 2, con biblioteca compartida libz

    Una biblioteca compartida no es un archivo de archivos de objeto o algo parecido. Es
    mucho más parecido a un programa que no tiene un main función y
    en su lugar expone varios otros símbolos que se define, de manera que los otros
    los programas pueden utilizar en tiempo de ejecución.

    Muchas distribuciones de Linux hoy en día de configurar su GCC toolchain para que sus controladores de lenguaje (gcc,g++,gfortran etc)
    indicar al sistema enlazador (ld) para vincular las bibliotecas compartidas en un como sea necesario base.
    Tienes una de esas distros.

    Esto significa que cuando el enlazador busca -lz en la vinculación de la secuencia, y las cifras que se refiere este
    a la biblioteca compartida (decir) /usr/lib/x86_64-linux-gnu/libz.so, se quiere saber si alguna de las referencias que ha añadido a su programa que no se ha definido todavía tienen las definiciones que se exportan por libz

    Si esto es cierto, entonces el vinculador no copiar los trozos de libz y
    agregar a su programa; en lugar de eso, se acaba de médico el código de tu programa
    de manera que:-

    • En tiempo de ejecución, el sistema de cargador de programa se carga una copia de libz en el
      mismo proceso que el programa cada vez que se carga una copia de su programa, ejecutarlo.

    • En tiempo de ejecución, siempre que el programa se refiere a algo que se define en
      libz, que hacen referencia a los usos de la definición exportados por la copia de libz en
      el mismo proceso.

    Su programa quiere referirse a una cosa que tiene una definición exportados por libz,
    es decir, la función zlibVersion, que se conoce sólo una vez, en eg2.c.
    Si el enlazador agrega que la referencia a su programa y, a continuación, se encuentra la definición de
    exportados por libz, la referencia es resuelto

    Pero cuando se intenta vincular el programa como:

    gcc -o eg2 -lz eg2.o

    el orden de los acontecimientos que está mal en la misma forma como con el ejemplo 1.
    En el punto cuando el enlazador busca -lz, hay no referencias a nada
    en el programa: todos ellos están en eg2.o, que aún no ha sido visto. Por lo que el
    enlazador decide que no tiene ningún uso para libz. Cuando llega eg2.o, añade al programa,
    y, a continuación, ha indefinido referencia a zlibVersion, la vinculación de la secuencia está terminado;
    que referencia es sin resolverse, y la vinculación que se produce un error.

    Por último, el pkg-config variación del ejemplo 2 tiene una evidente explicación.
    Después de concha de expansión:

    gcc -o eg2 $(pkg-config --libs zlib) eg2.o

    se convierte en:

    gcc -o eg2 -lz eg2.o

    que es sólo el ejemplo 2 de nuevo.

    Puedo reproducir el problema en el ejemplo 1, pero no en el ejemplo 2

    La vinculación:

    gcc -o eg2 -lz eg2.o

    funciona bien para usted!

    (O: Que la vinculación funcionado bien para usted, por ejemplo, Fedora 23, pero no en Ubuntu 16.04)

    Que es porque la distro en la que la vinculación de las obras es uno de los que
    no configurar su GCC toolchain para vincular las bibliotecas compartidas como sea necesario.

    De vuelta en el día, era normal para unix-como sistemas de enlace estático y compartido
    las bibliotecas por reglas diferentes. Las bibliotecas estáticas en una relación de secuencia estaban vinculados
    en el como sea necesario base explicado en el ejemplo 1, pero las bibliotecas compartidas estaban vinculados de manera incondicional.

    Este comportamiento es económico en linktime porque el vinculador no tienen que reflexionar
    si una biblioteca compartida se necesita el programa: si es una biblioteca compartida,
    enlace. Y la mayoría de las bibliotecas en la mayoría de los nexos son las bibliotecas compartidas. Pero también existen desventajas:-

    • Es antieconómico en tiempo de ejecución, porque puede provocar que las bibliotecas compartidas para ser
      carga junto con un programa, incluso si no los necesita.

    • Los diferentes vinculación de las reglas para la estática y las bibliotecas compartidas puede ser confuso
      para programadores inexpertos, que no puede saber si -lfoo en su vinculación
      se va a resolver a /some/where/libfoo.a o a /some/where/libfoo.so,
      y puede que no entienda la diferencia entre compartido y bibliotecas estáticas
      de todos modos.

    Este trade-off que ha llevado a la situación cismática de hoy. Algunas distribuciones tienen
    cambió su GCC vinculación de las reglas de las bibliotecas compartidas para que el como sea necesario
    principio se aplica para todas las bibliotecas. Algunas distribuciones he quedado con el viejo
    manera.

    ¿Por qué todavía tengo este problema, incluso si puedo compilar y vincular al mismo tiempo?

    Si acabo de hacer:

    $ gcc -o eg1 -I. -L. -lmy_lib eg1.c

    seguramente gcc tiene que compilar eg1.c en primer lugar, y, a continuación, vincular el resultado
    archivo objeto con libmy_lib.a. Así que ¿cómo puede no saber que archivo objeto
    es necesaria cuando se está haciendo el enlace?

    Debido a compilar y vincular con un solo comando no cambia la
    el fin de la vinculación de la secuencia.

    Al ejecutar el comando anterior, gcc figuras que desea compilación +
    la vinculación. Así que detrás de las escenas, se genera un comando de compilación, y se ejecuta
    que, a continuación, genera un vínculo de comandos, y la ejecuta, como si que había corrido la
    dos comandos:

    $ gcc -I. -c -o eg1.o eg1.c
    $ gcc -o eg1 -L. -lmy_lib eg1.o

    Por lo que la vinculación falla como si hacer ejecutar estos dos comandos. El
    la única diferencia se observa en el fallo es que gcc ha generado un
    objeto temporal en el archivo de compilación + link caso, porque no estás diciendo que
    el uso de eg1.o. Vemos:

    /tmp/ccQk1tvs.o: In function `main'

    lugar de:

    eg1.o: In function `main':

    Véase también

    El orden en el que interdependiente vinculados a las bibliotecas se especifica que está mal

    Poner interdependiente de las bibliotecas en el orden equivocado es sólo una manera de
    en el que usted puede conseguir los archivos que necesidad definiciones de las cosas
    más tarde en la vinculación de los archivos que proporcionar las definiciones. Poniendo las bibliotecas antes de la
    los archivos objeto que se refieren a ellos es otra manera de hacer el mismo error.

    OriginalEl autor Mike Kinghan

  27. 7

    Falta «extern» en const declaraciones de variables/definiciones (C++ sólo)

    Para personas que vienen de C podría ser una sorpresa que en C++ global constvariables internas (o estática), la vinculación. En C esto no fue el caso, ya que todas las variables globales son implícitamente extern (es decir, cuando el static palabra clave que falta).

    Ejemplo:

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

    correcto sería utilizar un archivo de encabezado que la incluyen en file2.cpp y file1.cpp

    extern const int test;
    extern int test2;

    Alternativamente, se podría declarar la const variable en file1.cpp con explícita extern

    OriginalEl autor Andreas H.

  28. 2

    Aunque este es un poco más viejas preguntas con múltiples respuestas aceptadas, me gustaría compartir cómo resolver un oscuro «undefined referencia a error».

    Diferentes versiones de las bibliotecas

    Yo estaba usando un alias para referirse a std::filesystem::path: sistema de archivos en la biblioteca estándar, ya que C++17 pero mi programa necesario para también compilar en C++14 así que me decidí a utilizar una variable alias:

    #if (defined _GLIBCXX_EXPERIMENTAL_FILESYSTEM) //is the included filesystem library experimental? (C++14 and newer: <experimental/filesystem>)
    using path_t = std::experimental::filesystem::path;
    #elif (defined _GLIBCXX_FILESYSTEM) //not experimental (C++17 and newer: <filesystem>)
    using path_t = std::filesystem::path;
    #endif

    Digamos que tengo tres archivos: main.cpp, archivo.h, file.cpp:

    • archivo.h #include <experimental::filestystem> y contiene el código de arriba
    • file.cpp, la aplicación de archivo.h #include «archivo.h»
    • main.cpp #include <filestystem> y «archivo.h«

    Nota la diferentes bibliotecas utilizado en main.cpp y archivo.h. Desde main.cpp #include d «archivo.h» después de <filestystem>, la versión de sistema de archivos se utiliza el C++17 uno. He utilizado para compilar el programa con los siguientes comandos:

    $ g++ -g -std=c++17 -c main.cpp -> compila main.cpp a la principal.o

    $ g++ -g -std=c++17 -c file.cpp -> compila file.cpp y archivo.h a archivo.o

    $ g++ -g -std=c++17 -o executable main.o file.o -lstdc++fs -> los enlaces principales.o y archivo.o

    De esta manera cualquier función contenida en el archivo.o y principal.o que requiere path_t dio «undefined reference» errores porque principal.o que se refiere std::filesystem::path pero archivo.o a std::experimental::filesystem::path.

    Resolución

    Para solucionar esto sólo necesitaba cambio <experimental::filestystem> en el archivo.h <filestystem>.

    OriginalEl autor Stypox

  29. 1

    Cuando la vinculación con las bibliotecas compartidas, asegúrese de que los símbolos utilizados no están ocultos.

    El comportamiento predeterminado de gcc es que todos los símbolos son visibles. Sin embargo, cuando la traducción de las unidades se construyen con opción -fvisibility=hidden, sólo las funciones/símbolos marcados con __attribute__ ((visibility ("default"))) son externos en los que resultan objeto compartido.

    Usted puede comprobar si los símbolos de su busca son externos invocando:

    # -D shows (global) dynamic symbols that can be used from the outside of XXX.so
    nm -D XXX.so | grep MY_SYMBOL 

    la escondida/local símbolos se muestran por nm con minúscula tipo de símbolo, por ejemplo t en lugar de `T para el código de la sección:

    nm XXX.so
    00000000000005a7 t HIDDEN_SYMBOL
    00000000000005f8 T VISIBLE_SYMBOL

    También puede utilizar nm con la opción -C a demangle los nombres (si C++).

    Similar a la de Windows dll, sería de marca de las funciones públicas con una definición, por ejemplo DLL_PUBLIC define como:

    #define DLL_PUBLIC __attribute__ ((visibility ("default")))
    
    DLL_PUBLIC int my_public_function(){
      ...
    }

    Lo cual corresponde aproximadamente a Windows’/MSVC-versión:

    #ifdef BUILDING_DLL
        #define DLL_PUBLIC __declspec(dllexport) 
    #else
        #define DLL_PUBLIC __declspec(dllimport) 
    #endif

    Más información acerca de la visibilidad se puede encontrar en el gcc wiki.


    Cuando una unidad de traducción es compilado con -fvisibility=hidden el resultado símbolos tienen todavía la vinculación externa (con mayúsculas tipo de símbolo por nm) y puede ser utilizado para la vinculación externa sin problema si el objeto de que los ficheros sean parte de un librerías estáticas. La vinculación se convierte en local sólo cuando el objeto se vinculan archivos en una biblioteca compartida.

    Para encontrar que los símbolos en un archivo de objeto se oculta ejecutar:

    >>> objdump -t XXXX.o | grep hidden
    0000000000000000 g     F .text  000000000000000b .hidden HIDDEN_SYMBOL1
    000000000000000b g     F .text  000000000000000b .hidden HIDDEN_SYMBOL2
    Usted debe utilizar nm -CD o nm -gCD para ver los símbolos externos. Véase también Visibilidad en el GCC wiki.

    OriginalEl autor ead

  30. 0

    Diferentes arquitecturas

    Usted puede ver un mensaje como:

    library machine type 'x64' conflicts with target machine type 'X86'

    En ese caso, significa que los símbolos disponibles son para una arquitectura diferente de la que usted está compilando.

    En Visual Studio, esto es debido al mal «Plataforma», y que usted necesita para seleccionar el apropiado o instalar la versión correcta de la biblioteca.

    En Linux, puede ser debido a una carpeta de la biblioteca (utilizando lib en lugar de lib64 por ejemplo).

    En MacOS, existe la opción de envío de ambas arquitecturas en el mismo archivo. Puede ser que el enlace espera que ambas versiones para estar allí, pero sólo uno es. También puede ser un problema con el mal lib/lib64 carpeta donde la biblioteca es recogido.

    OriginalEl autor Matthieu Brucher

Dejar respuesta

Please enter your comment!
Please enter your name here