Skip to content

🔗 Linker Errors - Guía de Diagnóstico

Errores de linking son los más frustrantes. Esta guía los desmitifica.


📊 ANATOMÍA DE UN ERROR DE LINKER

Linking CXX executable AudioLab.exe
main.cpp.obj : error LNK2019: unresolved external symbol
"void __cdecl foo(void)" (?foo@@YAXXZ) referenced in function main
AudioLab.exe : fatal error LNK1120: 1 unresolved externals

Desglose: - LNK2019: Undefined reference (symbol declarado pero no definido) - ?foo@@YAXXZ: Name mangling (decoración de C++) - main.cpp.obj: Dónde se usa el symbol - AudioLab.exe: Target que falla


🔍 TIPOS DE ERRORES DE LINKER

1️⃣ UNDEFINED REFERENCE / UNRESOLVED EXTERNAL

Qué significa

El linker encontró una declaración (en header) pero no la definición (en .cpp).

Ejemplo

// AudioProcessor.h
class AudioProcessor {
    void process();  // Declaración
};

// main.cpp
processor.process();  // Uso

// ❌ FALTA AudioProcessor.cpp con la definición

Soluciones

✅ Asegurar que .cpp está en build

target_sources(mi_plugin PRIVATE
    src/AudioProcessor.cpp  # Agregar
)

✅ Verificar que library está linkeada

target_link_libraries(mi_plugin PRIVATE
    audio_processing_lib
)

✅ Revisar name mangling (C vs C++)

// Si linkeas con C library
extern "C" {
    #include "c_library.h"
}

2️⃣ MULTIPLE DEFINITION / DUPLICATE SYMBOL

Qué significa

El mismo símbolo está definido dos veces.

Ejemplo

// ❌ BAD: En header (.h)
void utility() {  // No inline, no static
    // ...
}

// Cada .cpp que incluye este header genera una definición
// → Duplicate symbols al linkear

Soluciones

✅ Opción 1: Inline

// En header
inline void utility() {
    // ...
}

✅ Opción 2: Static

// En header (una copia por translation unit)
static void utility() {
    // ...
}

✅ Opción 3: Declaración + Definición

// Header
void utility();

// Source (.cpp)
void utility() {
    // ...
}

3️⃣ CANNOT FIND LIBRARY

Síntoma

ld: library not found for -ljuce_core

o

LINK : fatal error LNK1104: cannot open file 'juce_core.lib'

Causas

  • Library no compilada
  • Path incorrecto
  • Architecture mismatch (x86 vs x64)
  • Configuration mismatch (Debug vs Release)

Soluciones

✅ Verificar que library existe

# Buscar archivo
find build -name "*.lib" -o -name "*.a"

✅ Agregar library path

target_link_directories(mi_plugin PRIVATE
    ${CMAKE_BINARY_DIR}/lib
)

✅ Verificar architecture

# Forzar x64
set(CMAKE_GENERATOR_PLATFORM x64)

4️⃣ ABI MISMATCH

Síntoma

Compile exitoso, pero crash inmediato al ejecutar, o comportamiento extraño.

Causas

  • Mezclar Debug y Release binaries
  • Mezclar diferentes CRT en Windows (/MD vs /MT)
  • Mezclar diferentes std::lib (libstdc++ vs libc++)
  • Mezclar diferentes compiler versions

Diagnóstico

# Linux: Ver qué ABI usa un binary
readelf -d libMiLibrary.so | grep NEEDED

# Windows: Ver dependencies
dumpbin /DEPENDENTS MiLibrary.dll

Solución

🔥 REGLA DE ORO: TODO debe compilarse con:

  • Mismo compilador
  • Misma versión de compilador
  • Mismo build type (Debug/Release)
  • Mismo CRT runtime
# Asegurar consistencia
set(CMAKE_MSVC_RUNTIME_LIBRARY
    "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")

🛠️ HERRAMIENTAS DE DIAGNÓSTICO

Windows: dumpbin

# Ver exports de una DLL
dumpbin /EXPORTS MiLibrary.dll

# Ver imports necesarios
dumpbin /IMPORTS MiPlugin.dll

# Ver symbols
dumpbin /SYMBOLS MiObject.obj

Linux: nm, objdump

# Ver symbols definidos
nm -C libMiLibrary.so | grep "T "

# Ver symbols undefined
nm -C libMiLibrary.so | grep "U "

# Ver dependencies
ldd MiPlugin.so

macOS: otool

# Ver dependencies
otool -L MiPlugin.component/Contents/MacOS/MiPlugin

# Ver symbols
nm -gU MiLibrary.dylib

Cross-platform: CMake

# Ver qué libraries linkea un target
cmake --build build --target mi_plugin --verbose 2>&1 | grep "link"

🔧 WORKFLOW DE RESOLUCIÓN

1. Identificar símbolo problemático
   ↓
2. Demangle el nombre (c++filt)
   ↓
3. Buscar declaración (grep en headers)
   ↓
4. Buscar definición (grep en sources)
   ↓
5. Verificar que .cpp está en CMakeLists.txt
   ↓
6. Verificar que library está linkeada
   ↓
7. Verificar orden de linking

Ejemplo Práctico

# Error: undefined reference to `_Z3foov'

# 1. Demangle
c++filt _Z3foov
# Output: foo()

# 2. Buscar declaración
grep -r "void foo()" src/

# 3. Buscar definición
grep -r "void foo() {" src/

# 4. Si existe, verificar CMakeLists.txt
grep -A 10 "target_sources" CMakeLists.txt

💡 TIPS AVANZADOS

# Mostrar link command
set(CMAKE_VERBOSE_MAKEFILE ON)

# O al compilar
cmake --build build --verbose
# Eliminar binario para forzar relink
rm build/mi_plugin.vst3
cmake --build build --target mi_plugin

Static vs Shared

# Forzar static linking
set(BUILD_SHARED_LIBS OFF)

# Forzar shared
set(BUILD_SHARED_LIBS ON)

📚 RECURSOS