Error de las herramientas del vinculador LNK2001

símbolo externo "symbol" sin resolver

El código compilado hace una referencia o llama a symbol. El símbolo no está definido en ninguna biblioteca ni archivo de objeto donde busque el enlazador.

A este mensaje de error le sigue el error irrecuperable LNK1120. Para corregir el error LNK1120, primero corrija todos los errores LNK2001 y LNK2019.

Hay muchas maneras de que aparezcan errores LNK2001. Todas ellas implican una referencia a una función o variable que el enlazador no puede resolver o para la que no puede encontrar una definición. El compilador puede identificar si el código no declara un símbolo, pero no si no define uno. Esto se debe a que la definición puede estar en un archivo de origen o una biblioteca diferente. Si el código hace referencia a un símbolo, pero nunca se ha definido, el enlazador genera un error.

¿Qué es un símbolo externo sin resolver?

Un símbolo es el nombre interno de una función o variable global. Es la forma del nombre usado o definido en un archivo de objeto o biblioteca compilados. Una variable global se define en el archivo de objeto, donde se le asigna almacenamiento. Una función se define en el archivo de objeto donde se coloca el código compilado del cuerpo de la función. Un símbolo externo es aquel al que se hace referencia en un archivo de objeto, pero que se define en otra biblioteca o archivo de objeto. Un símbolo exportado es aquel que está disponible públicamente mediante el archivo de objeto o la biblioteca que lo define.

Para crear una aplicación o DLL, todos los símbolos usados deben tener una definición. El enlazador debe resolver cada símbolo externo al que hace referencia cada archivo de objeto, o buscar la definición coincidente de este. El enlazador genera un error si no puede resolver un símbolo externo. Esto significa que el enlazador no ha podido encontrar una definición de símbolo exportado coincidente en ninguno de los archivos vinculados.

Este error puede producirse:

  • Si falta una referencia a una biblioteca (.LIB) o archivo de objeto (.OBJ) en el proyecto. Para corregir este problema, agregue una referencia a la biblioteca o el archivo de objeto necesarios para el proyecto. Para obtener más información, vea Archivos .lib como entrada del enlazador.

  • Si el proyecto tiene una referencia a una biblioteca (.LIB) o un archivo de objeto (.OBJ) que, a su vez, requiere símbolos de otra biblioteca. Puede suceder incluso si no se llama a funciones que causen la dependencia. Para corregir este problema, agregue una referencia a la otra biblioteca al proyecto. Para obtener más información, vea Descripción del modelo clásico para vincular: Uso de símbolos.

  • Si usa las opciones /NODEFAULTLIB o /Zl. Al especificar estas opciones, las bibliotecas que contienen código requerido no se vinculan al proyecto a menos que se incluyan explícitamente. Para corregir este problema, incluya explícitamente todas las bibliotecas que use en la línea de comandos de vinculación. Si ve que faltan muchos nombres de función de CRT o biblioteca estándar al usar estas opciones, incluya explícitamente los DLL de biblioteca estándar y CRT o los archivos de biblioteca en el vínculo.

  • Si compila con la opción /clr. Puede que falte una referencia a .cctor. Para obtener más información sobre cómo corregir este problema, vea Inicialización de ensamblados mixtos.

  • Si vincula a las bibliotecas en modo de versión al compilar una versión de depuración de una aplicación. Del mismo modo, si usa las opciones /MTd o /MDd o define _DEBUG y luego vincula a las bibliotecas de versión, debería esperar muchos posibles símbolos externos sin resolver, entre otros problemas. La vinculación de una compilación en modo de versión con las bibliotecas de depuración también provoca problemas similares. Para corregir este problema, asegúrese de usar las bibliotecas de depuración en las compilaciones de depuración, y las bibliotecas comerciales en las compilaciones comerciales.

  • Si el código hace referencia a un símbolo de una versión de biblioteca, pero se vincula otra versión de la biblioteca. Por lo general, no se pueden mezclar archivos de objeto ni bibliotecas compilados para diferentes versiones del compilador. Las bibliotecas que se incluyen en una versión pueden contener símbolos que no se pueden encontrar en las bibliotecas incluidas en otras versiones. Para corregir este problema, compile todos los archivos de objeto y las bibliotecas con la misma versión del compilador antes de vincularlos entre sí. Para obtener más información, consulte Compatibilidad binaria de C++ entre versiones de Visual Studio.

  • Si las rutas de acceso de biblioteca no están actualizadas. El cuadro de diálogo Herramientas > Opciones > Proyectos > Directorios de VC++, en la selección Archivos de biblioteca, permite cambiar el orden de búsqueda de la biblioteca. La carpeta Enlazador del cuadro de diálogo Páginas de propiedades del proyecto también puede contener rutas de acceso que podrían estar obsoletas.

  • Si se instala un nuevo Windows SDK (quizás en otra ubicación). El orden de búsqueda de la biblioteca debe actualizarse para que apunte a la nueva ubicación. Normalmente, debe colocar la ruta de acceso de los nuevos directorios de inclusión y bibliotecas del SDK delante de la ubicación predeterminada de Visual C++. Además, un proyecto que contiene rutas de acceso insertadas puede seguir apuntando a rutas de acceso antiguas que son válidas, pero que no están actualizadas. Actualice las rutas de acceso de la nueva funcionalidad agregada por la nueva versión instalada en otra ubicación.

  • Si compila en la línea de comandos y ha creado sus propias variables de entorno. Compruebe que las rutas de acceso a herramientas, bibliotecas y archivos de encabezado apuntan a una versión coherente. Para obtener más información, vea Usar el conjunto de herramientas de MSVC desde la línea de comandos.

Problemas de codificación

Este error puede deberse a:

  • Caso no coincidente en el archivo de código fuente o de definición de módulo (.def). Por ejemplo, si asigna el nombre var1 a una variable en un archivo de código fuente de C++ e intenta acceder a ella como VAR1 en otro, se genera este error. Para corregir este problema, use nombres con una ortografía y con mayúsculas y minúsculas coherentes.

  • Un proyecto que usa inclusión de funciones en línea. Puede producirse cuando las funciones se definen como inline en un archivo de código fuente, en lugar de en un archivo de encabezado. Las funciones insertadas no se pueden ver fuera del archivo de código fuente que las define. Para corregir este problema, defina las funciones insertadas en los encabezados donde se declaran.

  • Una llamada a una función de C desde un programa de C++ sin usar una declaración extern "C" para la función de C. El compilador usa diferentes convenciones de nomenclatura de símbolos internas para el código de C y C++. El nombre del símbolo interno es lo que busca el enlazador al resolver símbolos. Para corregir este problema, use un contenedor de extern "C" en torno a todas las declaraciones de funciones de C usadas en el código de C++, lo que hace que el compilador emplee la convención de nomenclatura interna de C para esos símbolos. Las opciones del compilador /Tp y /Tc hacen que el compilador compile los archivos como C++ o C, respectivamente, independientemente de cuál sea la extensión de nombre de archivo. Estas opciones pueden dar lugar a nombres de función internos diferentes a lo esperado.

  • Un intento de hacer referencia a funciones o datos que no tienen vinculación externa. En C++, las funciones insertadas y los datos const tienen vinculación interna a menos que se especifique explícitamente como extern. Para corregir este problema, use declaraciones extern explícitas en símbolos a los que se haga referencia fuera del archivo de código fuente que define.

  • Una definición de cuerpo de función o variable no encontrados. Este error es común cuando se declaran, pero no se definen, variables, funciones o clases en el código. El compilador solo necesita un prototipo de función o una declaración de variable extern para generar un archivo de objeto sin errores, pero el enlazador no puede resolver una llamada a la función ni una referencia a la variable porque no hay ningún código de función o espacio de variable reservado. Para corregir este problema, asegúrese de definir todas las funciones y variables a las que se hace referencia en un archivo de código fuente o biblioteca que se vincule.

  • Una llamada de función que usa tipos devueltos y de parámetros o convenciones de llamada que no coinciden con los de la definición de función. En los archivos de objeto de C++, la decoración de nombres codifica la convención de llamada, el ámbito de clase o espacio de nombres, y los tipos devueltos y de parámetros de una función. La cadena codificada forma parte del nombre final representativo de la función. El enlazador usa este nombre para resolver, o emparejar, llamadas a la función desde otros archivos de objeto. Para corregir este problema, asegúrese de que la declaración de función, la definición y las llamadas usan los mismos ámbitos, tipos y convenciones de llamada.

  • Código de C++ al que se llama, cuando se incluye un prototipo de función en una definición de clase, pero que no incluye la implementación de la función. Para corregir este problema, asegúrese de proporcionar una definición para todos los miembros de clase a los que se llame.

  • Un intento de llamar a una función virtual pura desde una clase base abstracta. Una función virtual pura no tiene ninguna implementación de clase base. Para corregir este problema, asegúrese de que todas las funciones virtuales llamadas estén implementadas.

  • Intento de usar una variable declarada dentro de una función (una variable local) fuera del ámbito de esa función. Para corregir este problema, quite la referencia a la variable que no está en el ámbito o mueva la variable a un ámbito superior.

  • Al compilar una versión de lanzamiento de un proyecto ATL, se genera un mensaje que indica que se requiere código de inicio de CRT. Para corregir este problema, realice una de las acciones siguientes,

    • Quite _ATL_MIN_CRT de la lista de preprocesadores para permitir que se incluya el código de inicio de CRT. Para obtener más información, vea Página de propiedades General (Proyecto).

    • Si es posible, quite las llamadas a funciones de CRT que requieran código de inicio de CRT. En su lugar, use sus equivalentes de Win32. Por ejemplo, use lstrcmp en lugar de strcmp. Las funciones conocidas que requieren código de inicio de CRT son algunas de las funciones de cadena y punto flotante.

Problemas de coherencia

Actualmente, no hay un estándar para la decoración de nombres de C++ entre proveedores de compiladores, ni incluso entre versiones diferentes del mismo compilador. Es posible que los archivos de objeto compilados con distintos compiladores no usen el mismo esquema de nomenclatura. Su vinculación puede ocasionar el error LNK2001.

La mezcla de opciones de compilación insertadas y no insertadas en distintos módulos puede provocar el error LNK2001. Si se crea una biblioteca de C++ con la inserción de funciones activada (/Ob1 u /Ob2), pero el archivo de encabezado correspondiente que describe las funciones tiene desactivada la inserción (sin palabra clave inline), se produce este error. Para corregir este problema, defina las funciones inline en el archivo de encabezado que incluya en otros archivos de código fuente.

Si usa la directiva del compilador #pragma inline_depth, asegúrese de que ha establecido un valor de 2 o superior y de que también usa la opción del compilador /Ob1 u /Ob2.

Este error puede producirse si se omite la opción de LINK /NOENTRY al crear un archivo DLL de solo recursos. Para corregir este problema, agregue la opción /NOENTRY al comando LINK.

Este error puede producirse si se usa el valor incorrecto /SUBSYSTEM o /ENTRY en el proyecto. Por ejemplo, si escribe una aplicación de consola y especifica /SUBSYSTEM:WINDOWS, se genera un error externo sin resolver para WinMain. Para corregir este problema, asegúrese de emparejar las opciones con el tipo de proyecto. Para obtener más información sobre estas opciones y puntos de entrada, vea las opciones del enlazador /SUBSYSTEM y /ENTRY.

Problemas de símbolos de archivos .def exportados

Este error se produce cuando no se encuentra una exportación enumerada en un archivo .def. Podría deberse a que la exportación no existe, se ha escrito incorrectamente o usa nombres representativos de C++. Un archivo .def no toma nombres representativos. Para corregir este problema, quite las exportaciones innecesarias y use declaraciones extern "C" para símbolos exportados.

Uso del nombre representativo para encontrar el error

El compilador de C++ y el enlazador usan la decoración de nombres, también conocida como name-mangling. La decoración de nombres codifica información adicional sobre el tipo de una variable en su nombre de símbolo. El nombre de símbolo de una función codifica su tipo de valor devuelto, tipos de parámetros, ámbito y convención de llamada. El nombre representativo es el nombre de símbolo que el enlazador busca para resolver los símbolos externos.

SE puede producir un error de vínculo si la declaración de una función o variable no coincide exactamente con la definición de la función o variable. Esto se debe a que cualquier diferencia se convierte en parte del nombre de símbolo que se va a emparejar. El error puede producirse aunque se use el mismo archivo de encabezado tanto en el código de llamada como en el código de definición. Una manera en que puede producirse es si se compilan los archivos de código fuente mediante diferentes marcas del compilador. Por ejemplo, si el código se compila para usar la convención de llamada __vectorcall, pero se vincula a una biblioteca que espera que los clientes lo llamen mediante la convención de llamada predeterminada __cdecl o __fastcall. En este caso, los símbolos no coinciden porque las convenciones de llamada son diferentes.

Para ayudar a encontrar la causa, el mensaje de error muestra dos versiones del nombre. Muestra el "nombre descriptivo", el nombre usado en el código fuente, y el nombre representativo (entre paréntesis). No es necesario saber cómo interpretar el nombre representativo. Puede seguir buscándolo y comparándolo con otros nombres representativos. Las herramientas de línea de comandos pueden ayudar a buscar y comparar el nombre de símbolo esperado y el nombre del símbolo real:

  • Las opciones /EXPORTS y /SYMBOLS de la herramienta de línea de comandos DUMPBIN son útiles en este caso. Pueden ayudar a averiguar qué símbolos están definidos en el archivo .dll y en los archivos de objeto o biblioteca. Puede usar la lista de símbolos para comprobar que los nombres representativos exportados coinciden con los nombres representativos que busca el enlazador.

  • En algunos casos, el enlazador solo puede notificar el nombre representativo de un símbolo. Puede usar la herramienta de línea de comandos UNDNAME para obtener la forma no representativa de un nombre representativo.

Recursos adicionales

Para obtener más información, vea la pregunta de Stack Overflow ¿Qué es un error de referencia no definida o símbolo externo sin resolver y cómo se corrige?.