[c++] CMake output/build directory

I'm pretty new to CMake, and read a few tutorials on how to use it, and wrote some complicated 50 lines of CMake script in order to make a program for 3 different compilers. This probably concludes all my knowledge in CMake.

Now my problem is that I have some source code, whose folder I don't want to touch/mess with when I make the program. I want that all CMake and make output files and folders to go into ../Compile/, so I changed a few variables in my CMake script for that, and it worked for sometime when I did something like this on my laptop:

Compile$ cmake ../src
Compile$ make

Where with that I had a clean output in the folder I'm in right now, which is exactly what I'm looking for.

Now I moved to another computer, and recompiled CMake 2.8.11.2, and I'm almost back to square one! It always compiles the thing into the src folder where my CMakeLists.txt is located.

The part where I choose the directory in my CMake script is this:

set(dir ${CMAKE_CURRENT_SOURCE_DIR}/../Compile/)
set(EXECUTABLE_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(LIBRARY_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dir})
set(CMAKE_BUILD_FILES_DIRECTORY ${dir})
set(CMAKE_BUILD_DIRECTORY ${dir})
set(CMAKE_BINARY_DIR  ${dir})
SET(EXECUTABLE_OUTPUT_PATH ${dir})
SET(LIBRARY_OUTPUT_PATH ${dir}lib)
SET(CMAKE_CACHEFILE_DIR ${dir})

And now it always ends with:

-- Build files have been written to: /.../src

Am I missing something?

This question is related to c++ build makefile cmake output

The answer is


There's little need to set all the variables you're setting. CMake sets them to reasonable defaults. You should definitely not modify CMAKE_BINARY_DIR or CMAKE_CACHEFILE_DIR. Treat these as read-only.

First remove the existing problematic cache file from the src directory:

cd src
rm CMakeCache.txt
cd ..

Then remove all the set() commands and do:

cd Compile && rm -rf *
cmake ../src

As long as you're outside of the source directory when running CMake, it will not modify the source directory unless your CMakeList explicitly tells it to do so.

Once you have this working, you can look at where CMake puts things by default, and only if you're not satisfied with the default locations (such as the default value of EXECUTABLE_OUTPUT_PATH), modify only those you need. And try to express them relative to CMAKE_BINARY_DIR, CMAKE_CURRENT_BINARY_DIR, PROJECT_BINARY_DIR etc.

If you look at CMake documentation, you'll see variables partitioned into semantic sections. Except for very special circumstances, you should treat all those listed under "Variables that Provide Information" as read-only inside CMakeLists.


You should not rely on a hard coded build dir name in your script, so the line with ../Compile must be changed.

It's because it should be up to user where to compile.

Instead of that use one of predefined variables: http://www.cmake.org/Wiki/CMake_Useful_Variables (look for CMAKE_BINARY_DIR and CMAKE_CURRENT_BINARY_DIR)


Turning my comment into an answer:

In case anyone did what I did, which was start by putting all the build files in the source directory:

cd src
cmake .

cmake will put a bunch of build files and cache files (CMakeCache.txt, CMakeFiles, cmake_install.cmake, etc) in the src dir.

To change to an out of source build, I had to remove all of those files. Then I could do what @Angew recommended in his answer:

mkdir -p src/build
cd src/build
cmake ..

As of CMake Wiki:

CMAKE_BINARY_DIR if you are building in-source, this is the same as CMAKE_SOURCE_DIR, otherwise this is the top level directory of your build tree

Compare these two variables to determine if out-of-source build was started


It sounds like you want an out of source build. There are a couple of ways you can create an out of source build.

  1. Do what you were doing, run

    cd /path/to/my/build/folder
    cmake /path/to/my/source/folder
    

    which will cause cmake to generate a build tree in /path/to/my/build/folder for the source tree in /path/to/my/source/folder.

    Once you've created it, cmake remembers where the source folder is - so you can rerun cmake on the build tree with

    cmake /path/to/my/build/folder
    

    or even

    cmake .
    

    if your current directory is already the build folder.

  2. For CMake 3.13 or later, use these options to set the source and build folders

    cmake -B/path/to/my/build/folder -S/path/to/my/source/folder
    
  3. For older CMake, use some undocumented options to set the source and build folders:

    cmake -B/path/to/my/build/folder -H/path/to/my/source/folder
    

    which will do exactly the same thing as (1), but without the reliance on the current working directory.

CMake puts all of its outputs in the build tree by default, so unless you are liberally using ${CMAKE_SOURCE_DIR} or ${CMAKE_CURRENT_SOURCE_DIR} in your cmake files, it shouldn't touch your source tree.

The biggest thing that can go wrong is if you have previously generated a build tree in your source tree (i.e. you have an in source build). Once you've done this the second part of (1) above kicks in, and cmake doesn't make any changes to the source or build locations. Thus, you cannot create an out-of-source build for a source directory with an in-source build. You can fix this fairly easily by removing (at a minimum) CMakeCache.txt from the source directory. There are a few other files (mostly in the CMakeFiles directory) that CMake generates that you should remove as well, but these won't cause cmake to treat the source tree as a build tree.

Since out-of-source builds are often more desirable than in-source builds, you might want to modify your cmake to require out of source builds:

# Ensures that we do an out of source build

MACRO(MACRO_ENSURE_OUT_OF_SOURCE_BUILD MSG)
     STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}"
     "${CMAKE_BINARY_DIR}" insource)
     GET_FILENAME_COMPONENT(PARENTDIR ${CMAKE_SOURCE_DIR} PATH)
     STRING(COMPARE EQUAL "${CMAKE_SOURCE_DIR}"
     "${PARENTDIR}" insourcesubdir)
    IF(insource OR insourcesubdir)
        MESSAGE(FATAL_ERROR "${MSG}")
    ENDIF(insource OR insourcesubdir)
ENDMACRO(MACRO_ENSURE_OUT_OF_SOURCE_BUILD)

MACRO_ENSURE_OUT_OF_SOURCE_BUILD(
    "${CMAKE_PROJECT_NAME} requires an out of source build."
)

The above macro comes from a commonly used module called MacroOutOfSourceBuild. There are numerous sources for MacroOutOfSourceBuild.cmake on google but I can't seem to find the original and it's short enough to include here in full.

Unfortunately cmake has usually written a few files by the time the macro is invoked, so although it will stop you from actually performing the build you will still need to delete CMakeCache.txt and CMakeFiles.

You may find it useful to set the paths that binaries, shared and static libraries are written to - in which case see how do I make cmake output into a 'bin' dir? (disclaimer, I have the top voted answer on that question...but that's how I know about it).


Examples related to c++

Method Call Chaining; returning a pointer vs a reference? How can I tell if an algorithm is efficient? Difference between opening a file in binary vs text How can compare-and-swap be used for a wait-free mutual exclusion for any shared data structure? Install Qt on Ubuntu #include errors detected in vscode Cannot open include file: 'stdio.h' - Visual Studio Community 2017 - C++ Error How to fix the error "Windows SDK version 8.1" was not found? Visual Studio 2017 errors on standard headers How do I check if a Key is pressed on C++

Examples related to build

error: This is probably not a problem with npm. There is likely additional logging output above Module not found: Error: Can't resolve 'core-js/es6' WARNING in budgets, maximum exceeded for initial How can I change the app display name build with Flutter? Error - Android resource linking failed (AAPT2 27.0.3 Daemon #0) Still getting warning : Configuration 'compile' is obsolete and has been replaced with 'implementation' Could not find com.android.tools.build:gradle:3.0.0-alpha1 in circle ci Error:Execution failed for task ':app:compileDebugKotlin'. > Compilation error. See log for more details Component is part of the declaration of 2 modules Maven build Compilation error : Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project Maven

Examples related to makefile

MINGW64 "make build" error: "bash: make: command not found" "No rule to make target 'install'"... But Makefile exists How to overcome "'aclocal-1.15' is missing on your system" warning? How to install and use "make" in Windows? How to get a shell environment variable in a makefile? Using local makefile for CLion instead of CMake Difference between using Makefile and CMake to compile the code How to set child process' environment variable in Makefile Windows 7 - 'make' is not recognized as an internal or external command, operable program or batch file Debugging the error "gcc: error: x86_64-linux-gnu-gcc: No such file or directory"

Examples related to cmake

Copy file from source directory to binary directory using CMake CMake error at CMakeLists.txt:30 (project): No CMAKE_C_COMPILER could be found Installing cmake with home-brew CMake does not find Visual C++ compiler What's the CMake syntax to set and use variables? How do I add a library path in cmake? How to build x86 and/or x64 on Windows from command line with CMAKE? Difference between using Makefile and CMake to compile the code Add external libraries to CMakeList.txt c++ Cmake is not able to find Python-libraries

Examples related to output

How to create multiple output paths in Webpack config Where does the slf4j log file get saved? CMake output/build directory Suppress console output in PowerShell Output grep results to text file, need cleaner output How to use python numpy.savetxt to write strings and float number to an ASCII file? How to read a CSV file from a URL with Python? How can I suppress column header output for a single SQL statement? How to recover closed output window in netbeans? How can I see normal print output created during pytest run?