LNK2019 Unresolved External Symbol — Find the Missing Definition
LNK2019 is not primarily a header/include error. The caller compiled, but LINK could not resolve the exact requested linker symbol from the object/library inputs and members available to that link. Read the unresolved decorated symbol and referenced in function caller first; then prove which object/library member should emit it, whether that artifact is actually selected by LINK, and whether the emitted symbol identity matches.
error LNK2019: unresolved external symbol ... referenced in function ....A declaration/header may exist, but LINK cannot find a compatible compiled definition.The error may be followed by LNK1120: N unresolved externals; fix the underlying LNK2019/LNK2001 symbols first.Do not start by adding random libraries. Reduce the message to two facts: which symbol LINK needs, and which compiled function references it.
foo.obj : error LNK2019:
unresolved external symbol "void __cdecl run(int)"
referenced in function main
Need: run(int)
Caller: main in foo.obj
Next question: where should run(int) be defined?Verify: Before changing project settings, you can name the missing symbol, caller/object, and intended source/library of the definition.
What LNK2019 actually proves
Microsoft describes LNK2019 as compiled code referencing a function or variable whose definition the linker cannot find in the libraries or object files it searches. A declaration can therefore be perfectly visible to the compiler while the definition is missing at link time.
What exact function/variable is unresolved?
Which source, object, static library or import library should define it?
Was that definition compiled and was its object/library actually passed to LINK?
Does the emitted linker symbol exactly match what the caller requests?
Fix #2 — definition is in your source, but that source is missing from the build
A header declaration is not the implementation. Confirm the function/variable has a definition, then confirm the source file containing it participates in the active build. In Visual Studio, a file can exist in the solution while being excluded or configured with the wrong item type.
// api.h
void run(int);
// api.cpp — this must be compiled
void run(int value) { /* ... */ }Do not “fix” this by #include-ing a normal .cpp into another source file. Make the implementation source a proper compilation unit unless the code is intentionally header-only/template-based.
Verify: Build with normal verbosity and confirm the implementation source produces an .obj in the active configuration; rebuild and confirm this symbol is no longer unresolved.
Fix #3 — the definition is in another object/library, but LINK is not receiving it
Proving that something.lib exists on disk—or even that a similarly named symbol can be found somewhere inside it—is not enough. The active link must receive the correct library and LINK must be able to select the member that provides the exact requested decorated symbol. Check project references/linker inputs, effective library search paths and linker evidence for the configuration you are building. With static libraries, remember that libraries are archives of object members: resolution/extraction depends on unresolved references and the actual link inputs/options, so inspect what LINK selects rather than treating archive presence as proof.
Verify: inspect the effective link command and appropriate /VERBOSE evidence to prove the intended library/member is considered or selected for the exact unresolved symbol. Then rerun the same link and confirm that requested symbol is resolved. If LINK progresses to duplicate-symbol, machine-type, runtime-library or another diagnostic, stop treating it as the original LNK2019.
Fix #4 — a definition exists, but it is not the same linker symbol
C++ name decoration encodes information about a function. A declaration/definition mismatch can therefore compile in separate translation units yet fail to link. Compare the declaration and definition exactly: namespace and class scope, parameter types/order, const/ref qualifiers where applicable, calling convention, and template parameters/instantiations.
// declaration
void run(int);
// wrong definition: different symbol
void run(double) {}Verify: After correcting the mismatch, inspect/rebuild the defining artifact and confirm it now emits the symbol requested by the caller.
Fix #5 — template or static member was declared but never emitted
Templates are a common LNK2019 trap because the compiler generally needs the template definition where it instantiates a specialization. A declaration in a header plus a template definition hidden in an unrelated .cpp may compile callers but leave the required specialization unavailable to the linker. Keep the definition visible to the instantiating translation unit, or explicitly instantiate the specializations you intentionally provide from a source file.
Static data members have a related ownership question: depending on the C++ form and language version, a declaration may not by itself provide the definition/storage your program odr-uses. Check the exact declaration form instead of adding a library blindly.
Verify: Identify the exact template specialization/static member named by LNK2019 and prove that one linked object emits its matching symbol.
Fix #6 — C/C++ linkage, DLL import/export or decorated-name mismatch
If C code is consumed from C++, make the linkage contract explicit where appropriate with extern "C". For a normal MSVC DLL import, the executable links against the DLL's import library (typically a .lib); the DLL itself is needed when the program loads/runs. Keep the two pieces of evidence separate: the DLL must export the intended API, while the import library consumed by this build must provide the matching import symbol/linker contract. Seeing an export in the DLL alone does not prove the correct import library is on the active link.
#ifdef __cplusplus
extern "C" {
#endif
void c_api(void);
#ifdef __cplusplus
}
#endifDo not add extern "C" indiscriminately to C++ APIs. It changes language linkage/name decoration and is appropriate only when the interface contract requires C linkage. Likewise, copying a DLL next to the executable does not resolve a link-time LNK2019 when the required import-library/linker input is absent.
Verify: use DUMPBIN on the relevant object/static library/import library and, separately when applicable, the DLL exports. Compare the exact decorated requested/emitted/import symbols; use UNDNAME only as a readability aid. Then prove the active link consumes the matching import/static-library artifact.
Fix #7 — only one architecture or configuration fails
If Debug works but Release fails—or x86 works but x64 fails—treat that difference as evidence. Libraries and objects must match the target architecture; a machine-type incompatibility may also surface as LNK1112 rather than LNK2019, so preserve companion linker errors instead of forcing every architecture failure into this guide. Visual Studio properties can differ by configuration/platform. Inspect the failing combination's effective Additional Dependencies, library directories, project references, preprocessor/export macros and toolset.
Verify: Clean/rebuild the failing configuration and confirm LINK receives an artifact built for the same target architecture/configuration and resolves the symbol.
When the symbol is opaque: inspect the linker evidence
Microsoft recommends linker diagnostics rather than guessing. /VERBOSE can show linker progress and library/search details; DUMPBIN /SYMBOLS can inspect COFF symbols in objects/libraries, while /EXPORTS shows DLL/executable exports. UNDNAME can translate decorated C++ names into a more readable form.
Important: seeing a readable function name somewhere is not enough. Compare the actual decorated symbol and its ownership. Optimized/LTCG/COMDAT builds can also change what is emitted or retained, so use the artifact from the failing configuration, not a Debug object or stale library from another build. The final proof is that LINK resolves the exact requested symbol in the exact failing link.
dumpbin /symbols your.obj
dumpbin /exports your.dll
undname "?decorated@@..."
rem Add /VERBOSE to the linker when you need search/input evidence.Verify: You can now answer one concrete question: definition absent, artifact not linked, or emitted symbol different from requested symbol.
What not to do
.lib files until the error disappears. Identify which artifact should own the symbol.Do not include ordinary .cpp files as a substitute for configuring compilation units correctly.Do not assume a library that exists on disk is used by the active link.Do not copy Debug linker settings into Release—or x86 into x64—without understanding the difference.Do not chase the final LNK1120 count first; resolve the preceding LNK2019/LNK2001 symbols.Do not move every template implementation into a .cpp and assume callers can instantiate it; make the required definition visible or instantiate deliberately.Do not copy a DLL beside the executable as a link-time fix when the missing dependency is its import library/linker input.Do not treat “DUMPBIN found a similar function name in the .lib” as proof; compare the exact decorated symbol and prove LINK selects the owning member in the failing link.Do not use an artifact from Debug/another architecture/stale build as evidence for a Release or LTCG failure; inspect the artifact produced for the failing configuration.Do not equate a DLL export with the import-library symbol consumed at link time; verify both sides of the DLL contract.Do not keep diagnosing the original LNK2019 after the exact symbol resolves and LINK advances to a different linker diagnostic.Still seeing LNK2019?
Preserve the first unresolved-symbol line and its caller. If many errors share one library/namespace prefix, investigate that common owner before treating each symbol as an unrelated problem.
/VERBOSE evidenceDUMPBIN evidence for the exact requested decorated symbol, its owning object/library member, and separate DLL export/import-library evidence when applicablethe exact decorated requested/emitted names when a signature or linkage mismatch is suspecteddeclaration and definition signatures for your own symbolwhether another configuration/platform succeeds, and whether the inspected artifact was produced by the exact failing configuration/toolset/LTCG modeOfficial references
Still stuck? Ask the community
Share the first full LNK2019 line, active configuration/platform, where the definition should live, and any DUMPBIN or linker-input evidence you already checked.
Loading community discussion…
Comments could not load here. Open ErrorHarbor Discussions on GitHub →