Libraries
By the end of this lesson you'll know the difference between the standard library and third-party code, when to reach for static vs dynamic vs header-only libraries, what the -I / -L / -l flags actually do, and how a package manager like vcpkg or Conan saves you from wiring all of it up by hand.
Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.
Part of the free C++ course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Think of building a program like assembling flat-pack furniture. The header is the instruction sheet — it promises "a function called area() exists and takes a radius". The library is the box of actual parts — the compiled code that does the work. The compiler reads the instructions; the linker bolts in the parts. A static library is parts you glue permanently inside the finished piece (heavier, but nothing can fall off). A dynamic library is parts you keep in a shared drawer that several pieces of furniture borrow at use-time (lighter, but the drawer had better still be there). When you " #include the header but forget to link the library", you've read the instructions but never opened the box — hence the famous undefined reference error.
A library is just reusable compiled code plus a header that describes it. The header tells the compiler what exists; the library provides the actual instructions the linker bolts in.
1. Standard Library vs Third-Party
Every header you've used so far — , , , — is part of the standard library . It ships with the compiler, so you only it and it just works. A third-party library is code someone else wrote and published; you have to obtain it, tell the compiler where its headers are, and (usually) link its compiled code. Read this worked example, run it, and notice that everything here is "free" — no extra build flags needed.
2. Header-Only Libraries
The simplest kind of third-party library is header-only : all of its code lives in the header file, so there is nothing to compile or link separately — you it and build. This is why templates and inline functions live in headers, and why libraries like nlohmann/json , Catch2 , and fmt are so easy to adopt. The one rule: mark non-template functions inline so including the header in several .cpp files doesn't cause "multiple definition" errors.
Your turn. The namespace below is pretending to be a header-only file. Fill in the two blanks marked ___ using the hints in the comments, then run it.
3. Static Libraries (.a / .lib)
A static library is an archive of pre-compiled object files — .a on Linux/macOS, .lib on Windows. At link time the linker copies the bits you actually use straight into your executable. The upside: the program is self-contained , with no runtime dependency to ship. The downside: a bigger binary, and you must rebuild to pick up a library update. The worked example below runs real geometry code and shows, in comments, the exact g++ and CMake commands you'd use to build and link it.
4. Dynamic Libraries & the Linking Flags
A dynamic (or shared ) library — .so on Linux, .dll on Windows, .dylib on macOS — stays a separate file that is loaded when your program runs. Your executable stays small and many programs can share one copy, but that file must be found at run time or the program won't start. Linking any non-header library comes down to three flags: -I<dir> says where the headers are, -L<dir> says where the library files are, and -l<name> says which library to link ( -lcurl links libcurl.so — drop the lib prefix and the extension).
Now you try. The blanks below aren't C++ — they're the build flags . Fill in the right flag for the library folder and the library name so the recipe would actually find and link libcurl :
5. Package Managers & Consuming a Library
Hand-writing -I / -L / -l for one library is fine; doing it for a dozen libraries that each have their own dependencies is miserable. A package manager — vcpkg (Microsoft) or Conan — downloads a library, builds it for your platform, and wires it into your build (typically via CMake's find_package ). Whatever the tooling, consuming a library is always the same two steps: include its header , then link its compiled code . The example shows the vcpkg and Conan recipes in comments around runnable code.
Reach for static when you want a single self-contained binary you can copy anywhere — command-line tools and containers love this. Reach for dynamic when several programs share one library, when the library is large, or when you want to patch the library (a security fix) without rebuilding every program that uses it.
Header-only wins when the library is small or template-heavy and you value "just drop it in". The trade-off is slower compiles, because the code is recompiled in every translation unit that includes it.
No blanks this time — just a brief and a blank canvas (with an outline to keep you on track). Build a tiny header-only string library, run it, and check your output against the example in the comments. This is exactly how real header-only libraries start.
Practice quiz
What is the difference between the standard library and a third-party library?
- There is none
- Third-party libraries are always faster
- The standard library ships with every compiler; a third-party library you must obtain, point the compiler at, and usually link
- The standard library cannot be #included
Answer: The standard library ships with every compiler; a third-party library you must obtain, point the compiler at, and usually link. The standard library (iostream, vector, string...) ships with the compiler — just #include it. Third-party code you download, find, and link yourself.
Where does a STATIC library's code end up?
- Copied INTO your executable at link time
- In a separate file loaded at run time
- On the heap
- It is never linked
Answer: Copied INTO your executable at link time. A static library (.a / .lib) is copied into your executable at link time, so the program is self-contained but larger.
What is true of a DYNAMIC (shared) library?
- It is baked into the exe
- It needs no header
- It cannot be shared between programs
- It stays a separate file (.so/.dll/.dylib) loaded at run time, so the exe is smaller
Answer: It stays a separate file (.so/.dll/.dylib) loaded at run time, so the exe is smaller. A dynamic/shared library stays separate and is loaded when the program runs. The exe is small and many programs share one copy, but the file must be present at run time.
What does a header-only library require to use it?
- A separate compile and link step
- Nothing but #include — all its code lives in the header
- A package manager
- A static .a file
Answer: Nothing but #include — all its code lives in the header. A header-only library (like nlohmann/json or Catch2) puts all code in headers, so you just #include it — nothing to compile or link separately.
Why must non-template functions in a header be marked 'inline'?
- To avoid 'multiple definition' errors when several .cpp files include the header
- To make them faster
- To make them private
- It is never necessary
Answer: To avoid 'multiple definition' errors when several .cpp files include the header. inline lets a definition live in a header without breaking the one-definition rule when multiple translation units include it.
What does the 'undefined reference' linker error usually mean?
- A syntax error in your code
- Out of memory
- The header was found and compiled, but the function's actual code was never linked in
- A missing semicolon
Answer: The header was found and compiled, but the function's actual code was never linked in. Including a header only declares that a function exists. 'undefined reference' is a LINKER error — add the library to the link step with -lname and -Lpath.
What does the -l flag do, and how do you name the library?
- Sets the language; use the full filename
- Links a library; drop the 'lib' prefix and extension, so -lcurl links libcurl.so
- Lists files; use the path
- Loads at run time only
Answer: Links a library; drop the 'lib' prefix and extension, so -lcurl links libcurl.so. -l<name> links a library. -lcurl links libcurl.so or libcurl.a — you drop the 'lib' prefix and the extension.
Which three flags do you use to link a non-header library?
- -c, -o, -g
- -O2, -O3, -Os
- -std, -Wall, -Werror
- -I (header dir), -L (library dir), -l (which library)
Answer: -I (header dir), -L (library dir), -l (which library). -I says where the headers are, -L says where the library files are, and -l says which library to link.
What do package managers like vcpkg and Conan do for you?
- Compile your main.cpp
- Download, build, and wire libraries (and their dependencies) into your build
- Replace the compiler
- Write your code
Answer: Download, build, and wire libraries (and their dependencies) into your build. They install libraries and wire them into your build (often via CMake's find_package), sparing you manual -I/-L/-l bookkeeping across many dependencies.
To CONSUME any library, what two steps are always required?
- Compile and run
- Download and delete
- Include its header, then link its compiled code
- Reserve and free
Answer: Include its header, then link its compiled code. Whatever the tooling, consuming a library is always: include its header, then link its compiled code (a package manager handles the linking for you).