Question

Fixing 'usr/bin/ld: cannot find -l...' in C++: Understanding Library Linking

cpplinuxg++

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 .cpp into 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.so
  • libfoo.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:

  • The library directory is not in the linker's search path
  • The library file name does not follow the expected pattern
  • A symbolic link points to a missing target
  • You used -l<fullfilename> instead of the short library name
  • The library exists only at runtime, not at link time
  • You are linking 32-bit code with 64-bit libraries, or vice versa

Why it matters

Understanding library linking is important because real C++ projects often depend on:

  • third-party libraries
  • custom shared libraries
  • system libraries
  • build tools such as Make and CMake

If you know how -l, -L, and library naming work, you can diagnose many build problems quickly.

Mental Model

Think of the linker like a librarian.

  • -lfoo means: “Please find the book called libfoo.”
  • -L/path/to/libs means: “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.

Take Quiz

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_directory adds a directory to the link-time search path
  • -lfoo looks for libfoo.so or libfoo.a
  • -o my_program sets 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:

/home/user/lib/libparser.a

Then use:

g++ main.cpp -L/home/user/lib -lparser -o app

Example 3: Linking directly to a file

If needed, you can link by exact file path instead of using -l:

g++ main.cpp /opt/mylibs/libmathutils.so -o app

This can help when debugging search path issues.

Example 4: In a Makefile

CXX = g++
CXXFLAGS = -Wall -Wextra -std=c++17
LDFLAGS = -L/opt/mylibs
LDLIBS = -lmathutils

app: main.cpp
	$(CXX) $(CXXFLAGS) main.cpp $(LDFLAGS) $(LDLIBS) -o app

This separates:

  • compiler options in CXXFLAGS
  • linker search paths in LDFLAGS
  • libraries in LDLIBS

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.so
  • libfoo.a

5. If found, it links the library

The executable app is created.

6. If not found, you get the error

/usr/bin/ld: cannot find -lfoo

Trace example with an error

Command:

g++ main.cpp -lfoo -o app

Library location:

/home/user/libs/libfoo.so

What happens:

  • The linker checks standard system paths
  • It does not check /home/user/libs
  • It fails with cannot find -lfoo

Fixed version

g++ main.cpp -L/home/user/libs -lfoo -o app

Now the library directory is included in the search.

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.

Take Quiz

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:

  • CPPFLAGS for preprocessor flags like -Iinclude
  • LDFLAGS for linker search paths like -Llib
  • LDLIBS for 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:

  • installing the library in a standard location
  • setting LD_LIBRARY_PATH
  • embedding an rpath

Example:

g++ main.cpp -L/opt/mylibs -lfoo -Wl,-rpath,/opt/mylibs -o app

That helps the executable find the shared library later when it runs.

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:

g++ main.cpp -L/home/user/libs -lfoo -o app

4. Broken symbolic link

A symlink may exist, but point to a file that does not exist.

Check with:

ls -l /path/to/libfoo.so

If the target is missing, fix the symlink or point to the real file.

5. Library file has the wrong name

If the file is named:

foo.so

then -lfoo may not find it, because the expected name is usually:

libfoo.so

6. Wrong architecture

A 64-bit program cannot link against a 32-bit library without matching build settings.

Check file type with:

file /path/to/libfoo.so

7. Link order problems

Some libraries depend on others. In many cases, libraries should appear after the object files that use them.

Better:

g++ main.cpp -lfoo -o app

Not usually:

g++ -lfoo main.cpp -o app

For more complex builds, order can matter a lot.

Comparisons

ConceptPurposeExampleCommon Confusion
-I/pathAdd header search path-IincludeDoes not help find .so or .a files
-L/pathAdd library search path-L/usr/local/libDoes not help find header files
-lfooLink library libfoo.so or libfoo.a-lsslDo not include lib prefix or file extension
Direct file pathLink exact library file/opt/lib/libfoo.soUseful for debugging, but less flexible
LD_LIBRARY_PATHRuntime shared library search pathexport LD_LIBRARY_PATH=/opt/libDoes not usually fix link-time cannot find -l...
rpathEmbed runtime library path into executable-Wl,-rpath,/opt/libHelps at runtime, not as a replacement for -L

-L vs LD_LIBRARY_PATH

  • -L helps the linker during build
  • LD_LIBRARY_PATH helps the loader during execution

Symlink vs real file

  • A symlink is fine if it points to a valid library file
  • A symlink alone is not enough if its directory is not in the search path
Take Quiz

Cheat Sheet

# Basic pattern
g++ main.cpp -L/path/to/libs -lfoo -o app

Rules

  • -lfoo searches for libfoo.so or libfoo.a
  • Use -L/path to add non-standard library directories
  • Use -I/path for 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

  • File: libmylib.so
  • Flag: -lmylib

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?

Use:

ls -l /path/to/libfoo.so

Then verify that the target file actually exists.

What if my library file is named incorrectly?

Rename it to the standard form like libfoo.so or link it directly by full path.

Take Quiz

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 lib directory.
  • Write a program that calls the library function.
  • Build the program with -L and -l.
  • Ensure the executable can also find the shared library at runtime.
Take Quiz

Keep learning

Related questions

View more