Skip to content
C++ Better Explained
Go back
How to Fix 'collect2: error: ld returned 1 exit status' in C++

How to Fix “collect2: error: ld returned 1 exit status” in C++

Short answer: this line isn’t the real error. It’s g++ telling you that the linker (ld) failed. The reason is always on the lines just above it. Read those and match them below: an undefined reference, a missing main (shown as WinMain on Windows), a multiple definition, or Permission denied because your program is still running.

The line above saysWhat it means
undefined reference to 'add(int, int)'A function was declared, but its body was never compiled into the program
undefined reference to 'main' or 'WinMain'There’s no int main(), or the file with it wasn’t built
multiple definition of 'square(int)'The same function body was compiled twice, often from a header
cannot open output file ... Permission deniedThe program is still running, or you can’t write to that folder

Hit “collect2: error: ld returned 1 exit status”? It's a classic beginner trap, and there are others like it.

Free 1-page checklist: The 10 Mistakes Every C++ Beginner Makes. It shows the exact traps that slow down every C++ beginner, so you can avoid them from day one.

🔒 No spam. Unsubscribe anytime.


What collect2 and ld Are

g++ builds your program in two steps. First it compiles each .cpp file on its own into an object file. Then the linker, ld, joins those object files with the standard library to make the program, and checks that every function you call exists exactly once.

collect2 is the helper g++ uses to run ld. When ld fails, it reports that ld returned 1, the standard way a program says “something went wrong”. So the message tells you which step failed, not why.

Other tools say the same thing in different words:

ToolLast line when the linker fails
g++ on Linuxcollect2: error: ld returned 1 exit status
g++ on Windows (MinGW, Code::Blocks, VS Code)collect2.exe: error: ld returned 1 exit status
Clangclang++: error: linker command failed with exit code 1 (use -v to see invocation)
Visual Studiofatal error LNK1120, LNK1169 or LNK1168

Cause 1: A Function Declared but Never Defined

#include <iostream>

int add(int a, int b);

int main() {
    std::cout << add(2, 3) << '\n';
}
GCC:    /usr/bin/ld: /tmp/ccXXXXXX.o: in function `main':
        main.cpp:(.text+0x13): undefined reference to `add(int, int)'
        collect2: error: ld returned 1 exit status
MinGW:  ...\ld.exe: ...\ccXXXXXX.o: in function `main':
        main.cpp:6:(.text+0x18): undefined reference to `add(int, int)'
        collect2.exe: error: ld returned 1 exit status
MSVC:   error LNK2019: unresolved external symbol "int __cdecl add(int,int)" (?add@@YAHHH@Z) referenced in function main
        fatal error LNK1120: 1 unresolved externals

The line int add(int a, int b); promises that add exists, so the compiler is happy. But there’s no body anywhere, so the linker has nothing to connect the call to.

Fix: write the function’s body:

#include <iostream>

int add(int a, int b);

int main() {
    std::cout << add(2, 3) << '\n';
}

int add(int a, int b) {
    return a + b;
}
5

A spelling difference between the declaration and the body causes the same error, because to the linker they’re two different functions. Undefined reference errors covers more causes, such as missing libraries and templates.

Cause 2: A .cpp File That Wasn’t Compiled

Say your project has three files:

// util.h
#pragma once

int square(int x);
int cube(int x);
// util.cpp
#include "util.h"

int square(int x) {
    return x * x;
}

int cube(int x) {
    return square(x) * x;
}
// main.cpp
#include <iostream>
#include "util.h"

int main() {
    std::cout << square(3) << ' ' << cube(3) << '\n';
}

Build only main.cpp and the bodies in util.cpp never reach the linker:

g++ main.cpp -o app
/usr/bin/ld: /tmp/ccXXXXXX.o: in function `main':
main.cpp:(.text+0x13): undefined reference to `square(int)'
/usr/bin/ld: main.cpp:(.text+0x3e): undefined reference to `cube(int)'
collect2: error: ld returned 1 exit status

Fix: list every .cpp file:

g++ main.cpp util.cpp -o app
9 27

In VS Code this catches a lot of people. The build task it creates compiles only the file you have open (${file} in tasks.json). VS Code’s own guide shows how to replace it with ${workspaceFolder}/*.cpp to build every .cpp file in the folder. See how to run a .cpp file for building from the command line.

Header and linker errors are easier with the big picture. C++ Better Explained explains how C++ code gets compiled, including what header files and the linker each do, in plain English with diagrams.

Get the book — $19

Cause 3: No main Function (or “undefined reference to WinMain”)

#include <iostream>

int Main() {
    std::cout << "Hello\n";
    return 0;
}
GCC:    /usr/bin/ld: .../Scrt1.o: in function `_start':
        (.text+0x1b): undefined reference to `main'
        collect2: error: ld returned 1 exit status
MinGW:  ...\ld.exe: ...\libmingw32.a(lib64_libmingw32_a-crtexewin.o):crtexewin.c:(.text+0x119): undefined reference to `WinMain'
        collect2.exe: error: ld returned 1 exit status
MSVC:   MSVCRT.lib(exe_main.obj) : error LNK2019: unresolved external symbol main referenced in function "int __cdecl __scrt_common_main_seh(void)" (?__scrt_common_main_seh@@YAHXZ)
        fatal error LNK1120: 1 unresolved externals

Every program starts at a function called exactly main, all lowercase. Main is a different name, so the linker can’t find a starting point. On Windows, MinGW names WinMain in the message instead, but the cause is the same: it couldn’t find your main.

Fix: spell it int main(). If the spelling is already right, check two more things:

Cause 4: A Function Body in a Header

Now suppose util.h contains a function’s body instead of just its declaration:

// util.h
#pragma once

int square(int x) {
    return x * x;
}

int cube(int x);
// util.cpp
#include "util.h"

int cube(int x) {
    return square(x) * x;
}

main.cpp is the same as in Cause 2. Building both files fails:

g++ main.cpp util.cpp -o app
/usr/bin/ld: /tmp/ccXXXXXX.o: in function `square(int)':
util.cpp:(.text+0x0): multiple definition of `square(int)'; /tmp/ccXXXXXX.o:main.cpp:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status

#include pastes the header into each .cpp file that includes it. Both main.cpp and util.cpp include util.h, so square gets compiled twice, and the linker finds two bodies with the same name. #pragma once doesn’t help here: it only stops a header from being pasted twice into the same .cpp file.

Fix: either keep only the declaration in the header and put the body in util.cpp (the project from Cause 2), or mark the function inline:

// util.h
#pragma once

inline int square(int x) {
    return x * x;
}

int cube(int x);
9 27

inline tells the linker that identical copies of this function are allowed. More in inline functions and header files.

Visual Studio reports this as LNK2005 (already defined in an object file), followed by LNK1169.

The same error from #include “util.cpp”

Including a .cpp file instead of the header does the same thing to every function in it:

#include <iostream>
#include "util.cpp"

int main() {
    std::cout << square(3) << ' ' << cube(3) << '\n';
}
/usr/bin/ld: /tmp/ccXXXXXX.o: in function `square(int)':
util.cpp:(.text+0x0): multiple definition of `square(int)'; /tmp/ccXXXXXX.o:main.cpp:(.text+0x0): first defined here
/usr/bin/ld: /tmp/ccXXXXXX.o: in function `cube(int)':
util.cpp:(.text+0x13): multiple definition of `cube(int)'; /tmp/ccXXXXXX.o:main.cpp:(.text+0x13): first defined here
collect2: error: ld returned 1 exit status

Fix: include the header (#include "util.h") and compile util.cpp separately.

Cause 5: “Permission denied” Because the Program Is Still Running

...\ld.exe: cannot open output file app.exe: Permission denied
collect2.exe: error: ld returned 1 exit status

The linker needs to write a new app.exe. On Windows, a program that’s running locks its .exe file, so if the console window from your last run is still open, the linker can’t replace it.

Fix: close the program’s window, or stop it from your IDE, then build again.

If nothing is running, something else may be holding the file. Microsoft’s notes for Visual Studio’s version of this error, LNK1168 (cannot open ... for writing), list antivirus scanners and search indexing as common causes. On Linux and macOS, Permission denied usually means you can’t write to that folder, so build somewhere you own.

Quick Reference

The line above collect2Fix
undefined reference to 'yourFunction(...)'Write the function’s body, or add its .cpp file to the build
undefined reference to 'main'Spell it int main(), save the file, build the right file
undefined reference to 'WinMain'Same as main: MinGW couldn’t find your main
multiple definition of '...'Move the body out of the header, or make it inline; never #include a .cpp file
cannot open output file ...: Permission deniedClose the running program, then build again

For other common messages, see C++ error messages explained.


Take Your C++ Further

C++ Better Explained ebook cover

Header-file and linker errors stop being mysterious once you know how your .cpp files become a program. C++ Better Explained explains how C++ code gets compiled, step by step, in plain English with diagrams.

Get the book — $19

87 pages · plain English · 30-day money-back guarantee


Next common error C++ Segmentation Fault: What It Is and How to Fix It
📋

Free Download: The 10 Mistakes Every C++ Beginner Makes

A free 1-page checklist that shows the exact traps that slow down every C++ beginner — so you can avoid them from day one.

🔒 No spam. Unsubscribe anytime.


Share this post on:

Written by

Sahil Bora

Software Engineer. Author and creator of C++ Better Explained.


Previous Post
How to Fix 'invalid conversion from const char* to char' in C++
Next Post
How to Fix 'terminate called after throwing an instance of' in C++

Keep Learning