LNK2019 Unresolved External Symbol in C++: Five Causes and Fixes (Visual Studio & CMake)

LNK2019 Unresolved External Symbol in C++: Five Causes and Fixes (Visual Studio & CMake)

이 글의 핵심

Linker LNK2019 means the linker cannot find a symbol’s definition. This guide walks compile vs link, five root causes, and how to verify fixes in Visual Studio and CMake.

Modern CMake: targets & link libraries · generic CMake failures: common CMake errors.

Introduction: the linker error every C++ developer hits

LNK2019: unresolved external symbol is a linker failure: the compiler accepted your translation units, but when linking object files and libraries into an executable or DLL, the linker could not find a definition for a referenced symbol.

Roughly: “there is a declaration, but no matching definition reached the link step.”

This article covers:

  • Compile vs link (why the error appears at link time)
  • Five major causes and fixes
  • Visual Studio and CMake checks

Environments: Examples use Visual Studio on Windows and GCC/Clang + CMake on Linux/macOS. The ideas transfer to any toolchain once you map them to your IDE.


Table of contents

  1. What is LNK2019? (compile vs link)
  2. Cause 1: declaration without definition
  3. Cause 2: .cpp not in the build
  4. Cause 3: library not linked
  5. Cause 4: namespace / name mismatch
  6. Cause 5: template definition not in header
  7. Checking in Visual Studio
  8. Checking in CMake

1. What is LNK2019?

1. Compile turns each .cpp into an object file (.obj / .o). The compiler only needs declarations to type-check calls—e.g. void foo(); is enough to compile a call site.

2. Link merges objects and libraries into the final binary. The linker needs a unique definition for every referenced symbol. If none is found → LNK2019.

Sample message

error LNK2019: unresolved external symbol "void __cdecl foo(void)" (?foo@@YAXXZ)
referenced in function _main

Meaning: foo is used from main, but no object pulled into the link defines foo.

Why two phases?

Incremental builds: change one .cpp, recompile it, relink—faster than compiling everything every time.

flowchart LR
  subgraph compile["Step 1: compile"]
    A[.cpp + headers] --> B[Compiler]
    B --> C[.obj / .o]
    C --> D["Declaration-only can compile"]
  end
  subgraph link["Step 2: link"]
    C --> E[Linker]
    E --> F[.exe]
    E -.->|"no definition"| G[LNK2019]
  end

2. Cause 1: declaration but no definition

utils.h

#ifndef UTILS_H
#define UTILS_H

void printMessage();  // declaration only

#endif

main.cpp

#include "utils.h"

int main() {
    printMessage();  // LNK2019 if no TU defines printMessage
    return 0;
}

Fix: add utils.cpp (or define in a TU that is linked):

#include "utils.h"
#include <iostream>

void printMessage() {
    std::cout << "Hello from utils!\n";
}

Build: ensure utils.obj participates in the link (VS: add file to project; CMake: list in add_executable or link a static lib).

Direct build:

g++ main.cpp utils.cpp -o myapp

3. Cause 2: .cpp omitted from the build

add_executable(myapp
    main.cpp
    # forgot utils.cpp
)

Symptom: build log never compiles utils.cpp.

Fix:

add_executable(myapp
    main.cpp
    utils.cpp
)

4. Cause 3: not linking the library

You included headers and compiled, but the .lib / .a (implementation) is not on the link line.

Visual Studio: Linker → Input → Additional Dependencies (ws2_32.lib, mylib.lib, …) and Additional Library Directories.

CMake:

target_link_libraries(myapp PRIVATE mylib)

CLI:

g++ main.cpp -o myapp -L/path/to/lib -lmylib

5. Cause 4: namespace / name mismatch

Declaration:

namespace util {
    void printMessage();
}

Wrong definition (global):

void printMessage() { }  // different symbol from util::printMessage

Fix: define inside namespace util or as void util::printMessage().

Also watch case and extern "C" for C APIs.


6. Cause 5: templates defined only in .cpp

Templates are usually instantiated where used. If the definition is hidden in a .cpp that does not see the use sites, the linker misses symbols.

Typical fix: put definitions in the header (or explicit instantiations in .cpp for known types).

// math.h
template <typename T>
T add(T a, T b) { return a + b; }

Explicit instantiation (narrow use):

template int add<int>(int, int);
template double add<double>(double, double);

7. Visual Studio checklist

  • Linker → Input → Additional Dependencies
  • Linker → General → Additional Library Directories
  • C/C++ → General → Additional Include Directories (compile-time paths)

8. CMake checklist

add_executable(myapp main.cpp utils.cpp)
target_link_libraries(myapp PRIVATE mylib)

Debug finding:

cmake --build . --verbose

Resolution checklist

CauseCheckFix
No definitionNo TU defines the symbolAdd .cpp / library
Missing TU.cpp not listedAdd to CMake/VS project
Missing libHeaders onlytarget_link_libraries / VS libs
Name mismatchNamespace / spellingAlign declaration & definition
TemplatesDefinition only in .cppHeader definition or explicit inst.

Practical debugging

  1. Read the demangled name in the error (VS shows both).
  2. Follow “referenced in function …” to the call site.
  3. Fix first LNK2019—later errors may be follow-ons.
  4. Match x64/x86 and Debug/Release runtimes with your .lib files.
  5. For C APIs from C++, wrap includes in extern "C" when required.

FAQ (short)

LNK2019 vs LNK1120 — per-symbol vs summary.
main unresolved — entry point / subsystem / target type.
Header-only — no .lib needed if truly header-only.


  • CMake intro
  • Segfault debugging
  • Compile speed (VS)

Keywords

LNK2019, unresolved external symbol, C++ linker error, target_link_libraries, Visual Studio link error


Practical tips

  • Treat the first linker error as primary.
  • Verify every .cpp that defines symbols you call is compiled and linked.
  • For third-party SDKs, copy exact pragma comment(lib, …) / CMake targets from their docs.

Closing: LNK2019 means missing definition at link time. Walk definitions → object files → libraries → names → templates, and the fix is usually one configuration step away.

Search: LNK2019, unresolved external symbol, CMake link, MSVC linker