Build and Install CMake Projects Out-of-Source

Run cmake straight inside your source tree and you will spend the next afternoon untangling generated files from real code. This walks through configuring, building and installing a project the safe way, in a separate build directory you can delete without a second thought. It matches CMake 3.28.3 from the cmake package.

Allow 15 to 30 minutes for a small project, plus whatever time it takes to fetch or inspect its source. You need a shell and a readable source tree with a top-level CMakeLists.txt, plus the compiler and build tools the project expects. None of this needs sudo: installing into a system prefix is a separate, privileged step that is deliberately not part of the first run.

1. Check the installed CMake and project layout

Two read-only checks before you touch anything, so you are not debugging a command copied for a different release or a directory that is not a CMake project at all.

cmake --version
test -f /path/to/project/CMakeLists.txt && echo "CMake project found"

On this machine the first command reports cmake version 3.28.3. Replace /path/to/project with the real source directory: if the second command prints nothing, stop and find the directory that actually holds the top-level file rather than pointing -S at a parent directory and hoping.

2. Configure an out-of-source build tree

Use explicit source and build paths: -S names the source tree, -B names the build tree. CMake creates the build directory as needed and stores its persistent configuration in CMakeCache.txt.

cmake -S /path/to/project -B /path/to/project-build

A successful configure ends with generator-specific output and a line like Build files have been written to: /path/to/project-build. Confirm it:

test -f /path/to/project-build/CMakeCache.txt && echo "Build tree is configured"

3. Set cache values deliberately

Pass project configuration as cache entries with -D. A single-configuration build type is the common example:

cmake -S /path/to/project \
  -B /path/to/project-build \
  -DCMAKE_BUILD_TYPE=Release

CMAKE_BUILD_TYPE only applies to single-configuration generators such as Unix Makefiles; multi-configuration generators pick a configuration at build time instead. Check the project's own documentation before adding project-specific variables, since CMake will happily accept a cache name the project ignores.

Repeated configure commands reuse the existing cache, which is convenient but can hide an old choice. See the current non-advanced values without editing anything:

cmake -L /path/to/project-build

Checkpoint: after changing an important option, rerun the configure command and read the summary rather than assuming the value stuck. If the project ships a preset, list them first with cmake --list-presets, then use one with cmake --preset NAME: a preset sets source, build, generator and cache together, so do not mix it with ad-hoc values unless the project documents that combination.

4. Build through CMake, not the native tool directly

Once configuration succeeds, let CMake call the generated build tool. That keeps the command stable if the project ever switches from Makefiles to Ninja.

cmake --build /path/to/project-build

Zero means the native build finished; the progress text varies. Verify the target exists rather than trusting a quiet exit:

cmake --build /path/to/project-build --target help
cmake --build /path/to/project-build --parallel 2

Anything after a standalone -- goes straight to the native build tool: treat that as an escape hatch for generator-specific behaviour, not a portable default. If a build fails, keep the first error, rerun with the same configuration, and read the compiler and dependency messages before you delete the build tree.

5. Install into a disposable prefix first

Installation changes the filesystem, so rehearse it somewhere under /tmp before you go near a system prefix. Set it during configuration:

cmake -S /path/to/project \
  -B /path/to/project-build \
  -DCMAKE_INSTALL_PREFIX=/tmp/cmake-guide-prefix
cmake --build /path/to/project-build
cmake --install /path/to/project-build

The install step runs the generated install rules without calling the native build tool directly. Check what landed:

find /tmp/cmake-guide-prefix -maxdepth 3 -type f -print

Some projects install nothing; some need a particular target or configuration. The prefix must be an absolute path when set through CMake's option, though you can override it for one install with cmake --install /path/to/project-build --prefix /tmp/cmake-guide-prefix.

Warning: cleaning up this disposable example means running rm -rf /tmp/cmake-guide-prefix, which is irreversible. Confirm the exact path first, never substitute a variable you have not inspected, and never reuse this pattern against a system directory.

6. Recover from stale or confused configuration

Most CMake confusion traces back to a cache still holding an earlier source path, generator or option. Rerun the explicit -S/-B command and read the output first. If the build tree is disposable and you want a clean slate, CMake 3.28.3 has --fresh:

cmake --fresh -S /path/to/project -B /path/to/project-build

That deletes the existing cache file and recreates it: any cache selections you did not put on the command line need supplying again, and project-specific generated state may need regenerating too. Rename the old tree first, or configure a fresh build directory, if you want to keep it for comparison.

Warning: do not reach for sudo cmake to fix a compiler, dependency or cache error. Elevated configuration can leave root-owned files that break later unprivileged builds. Fix the actual toolchain or permissions problem, and save privilege for the one install step that genuinely needs it.

Done means