Question
I am trying to compile a C++ program, and the linker returns this error:
/usr/bin/ld: cannot find -l<nameOfTheLibrary>
In my Makefile, I use g++ and link against a library. The library file is a symbolic link to the real library located in another directory.
Is there a compiler or linker option I need to add so the build can find and link the library correctly?
Short Answer
By the end of this page, you will understand what the -l linker option means, how g++ searches for libraries, why this error happens, and how to fix it using options such as -L, correct library naming, and runtime path settings when needed.
Concept
When you build a C++ program, compilation and linking are two separate steps:
- Compilation turns source files like
.cppinto object files like.o - Linking combines object files and libraries into the final executable
The error:
/usr/bin/ld: cannot find -lfoo
means the linker cannot find a library matching foo in its search paths.
What -lfoo actually means
When you write:
g++ main.cpp -lfoo
g++ passes the request to the linker, which searches for files with names like:
libfoo.solibfoo.a
So -lfoo does not mean “find a file named foo”. It means “find a library named libfoo with a supported extension”.
Why this error happens
Common reasons include:
Mental Model
Think of the linker like a librarian.
-lfoomeans: “Please find the book calledlibfoo.”-L/path/to/libsmeans: “Also search this shelf.”- If the shelf is not listed, the librarian only checks the usual shelves.
- If the label is wrong, the book is not found even if it exists.
- If a symbolic link points to nowhere, it is like a catalog card that references a missing book.
So the error means the librarian understood your request, but could not find the library on any known shelf.
Syntax and Examples
The core options for linking libraries with g++ are:
g++ main.cpp -L/path/to/library_directory -lfoo -o my_program
Meaning of each part
-L/path/to/library_directoryadds a directory to the link-time search path-lfoolooks forlibfoo.soorlibfoo.a-o my_programsets the output executable name
Example 1: Linking a custom library
Suppose your library file is:
/opt/mylibs/libmathutils.so
Then use:
g++ main.cpp -L/opt/mylibs -lmathutils -o app
Notice:
- The file is
libmathutils.so - The linker flag is
-lmathutils - You do not write
-llibmathutils.so
Example 2: Static library
If the file is:
Step by Step Execution
Consider this command:
g++ main.cpp -L/home/user/libs -lfoo -o app
Assume /home/user/libs contains libfoo.so.
Step-by-step
1. g++ compiles main.cpp
It first compiles the source code into an object file.
2. g++ invokes the linker
After compilation, g++ calls the linker (ld) behind the scenes.
3. The linker reads -L/home/user/libs
This tells it to also search /home/user/libs for libraries.
4. The linker reads -lfoo
It searches for a matching library file, usually:
libfoo.solibfoo.a
5. If found, it links the library
The executable app is created.
Real World Use Cases
Library linking appears in many real projects.
Using third-party C++ libraries
Examples:
- SQLite wrappers
- OpenSSL
- Boost components
- graphics and game libraries
You often need to add both:
- include paths for headers:
-I... - library paths for linking:
-L...
Building internal shared libraries
A company might have a reusable library like:
/company/libs/libauth.so
Applications link against it with:
-L/company/libs -lauth
Plugin or modular systems
Large applications may separate code into shared libraries so multiple programs can reuse them.
Cross-platform builds
A project might build successfully on one machine because the library is installed system-wide, but fail on another machine where the path must be added manually.
Real Codebase Usage
In real codebases, developers usually organize linking in a structured way instead of placing everything directly in one command.
Common patterns
Use variables in Makefiles
LDFLAGS += -L$(PROJECT_ROOT)/lib
LDLIBS += -lfoo
This keeps build settings reusable.
Separate headers from libraries
Developers often use:
CPPFLAGSfor preprocessor flags like-IincludeLDFLAGSfor linker search paths like-LlibLDLIBSfor actual libraries like-lfoo
Validate library existence
Teams may check whether dependencies are installed before building.
Use pkg-config
For many libraries, developers avoid hardcoding paths and instead use:
g++ main.cpp $(pkg-config --cflags --libs libpng)
This automatically provides the correct include and link flags.
Handle runtime loading too
Even if link time succeeds, a shared library may still fail at runtime unless the system can find it. Common approaches include:
Common Mistakes
1. Using the wrong library name with -l
Broken:
g++ main.cpp -llibfoo.so -o app
Correct:
g++ main.cpp -lfoo -o app
The linker adds lib and .so or .a automatically.
2. Forgetting -L for non-standard directories
Broken:
g++ main.cpp -lfoo -o app
If libfoo.so is in /home/user/libs, this fails.
Correct:
g++ main.cpp -L/home/user/libs -lfoo -o app
3. Confusing include paths and library paths
Broken idea:
g++ main.cpp -I/home/user/libs -lfoo -o app
-I is for header files, not libraries.
Correct:
Comparisons
| Concept | Purpose | Example | Common Confusion |
|---|---|---|---|
-I/path | Add header search path | -Iinclude | Does not help find .so or .a files |
-L/path | Add library search path | -L/usr/local/lib | Does not help find header files |
-lfoo | Link library libfoo.so or libfoo.a | -lssl | Do not include lib prefix or file extension |
Cheat Sheet
# Basic pattern
g++ main.cpp -L/path/to/libs -lfoo -o app
Rules
-lfoosearches forlibfoo.soorlibfoo.a- Use
-L/pathto add non-standard library directories - Use
-I/pathfor headers, not libraries - Do not write
-llibfoo.so - The library directory must be reachable at link time
- Shared libraries may also need runtime search configuration
Useful checks
# Check library files
ls /path/to/libs
# Inspect symbolic link
ls -l /path/to/libs/libfoo.so
# Check architecture
file /path/to/libs/libfoo.so
# Show verbose link command
g++ -v main.cpp -L/path/to/libs -lfoo -o app
Common fixes
# Add library path
g++ main.cpp -L/path/to/libs -lfoo -o app
# Link exact file
g++ main.cpp /path/to/libs/libfoo.so -o app
# Add runtime path too
g++ main.cpp -L/path/to/libs -lfoo -Wl,-rpath,/path/to/libs -o app
Naming reminder
FAQ
Why does -lfoo look for libfoo.so instead of foo.so?
Because that is the standard Unix linker naming convention for libraries.
Do I need -L if the library is a symbolic link?
Yes, if the symlink is in a non-standard directory. The linker still needs to know which directory to search.
Can I link directly to the .so file instead of using -l?
Yes. You can pass the full path to the library file. This is often useful for debugging.
What is the difference between -L and LD_LIBRARY_PATH?
-L is used at build time by the linker. LD_LIBRARY_PATH is used at runtime by the dynamic loader.
Why does the build succeed on one machine and fail on another?
One machine may have the library installed in a standard system path, while the other does not.
Does -I help fix this error?
No. -I only adds header search paths, not library search paths.
How can I check whether the symlink is broken?
Mini Project
Description
Build a small C++ program that uses a custom library stored in a separate directory. This project demonstrates the difference between compilation and linking, how to use -L and -l, and how to organize a simple Makefile correctly.
Goal
Create and link a program against a custom library in a non-standard directory using g++ and a Makefile.
Requirements
- Create a small shared library with one function.
- Place the library in a custom
libdirectory. - Write a program that calls the library function.
- Build the program with
-Land-l. - Ensure the executable can also find the shared library at runtime.
Keep learning
Related questions
Advantages of Brace Initialization in C++
Learn why C++ brace initialization is often clearer and safer than other object initialization styles, with examples and common pitfalls.
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Aggregates, Trivial Types, Trivially Copyable Types, and PODs Explained
Learn what aggregates, trivial types, trivially copyable types, and PODs mean in C++, how they differ, and why they matter.