Changing output directories

I wanted to modify the output destination for building my binaries through CMake. My objective was to organize the generation of executables, static libraries, and dynamic libraries based on architecture (64-bit/32-bit) and configuration (debug, release, etc.) into distinct directories corresponding to their respective attributes.


My first attempt led me to the following code:

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "output location...")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "output location...")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "output location...")

However, I soon discovered, as per the CMake documentation, that multi-configuration environments like Visual Studio typically include subdirectories for each of their configurations. For example, if I tried to set the executable location for “Debug and 64 bit” to something like “…/64-bit/debug/…”, then Visual studio would create an additional debug folder under the already existing debug folder like: “…/64-bit/debug/Debug/…”.


I found this to be frustrating, forcing me to find a solution to set individual configuration settings, as demonstrated below:

set(
    CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG
    "$Output to debug location...")

set(
    CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE
    "$Output to release location...")

"This list keeps going for other configurations and variables..."

Of course, this method achieved my desired outcome, but it’s quite lengthy and lacks flexibility. This leads me to my question:


Besides the approaches mentioned earlier, is there a better way to shorten this using generator expressions that can be used for both multi and single configuration environments?

Hello, @Saviz.

I used to encounter the similar question as you do. Here is my answer. Hope you can take what you need.

If you just don’t want any subdirectories created when building targets with Multi-Config generators, you can add $<1:xxx> for each output directories:

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "$<1:${CMAKE_BINARY_DIR}/bin>")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "$<1:${CMAKE_BINARY_DIR}/lib>")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "$<1:${CMAKE_BINARY_DIR}/lib>")

That way, both Multi- and Single-Config generators will generate their artifacts in:

  • ${CMAKE_BINARY_DIR}/bin
  • ${CMAKE_BINARY_DIR}/lib

And the mechanism behind this is because (according to my research):

  • If you don’t use any generator expression in (CMAKE_)XXX_OUPUT_DIRECTORY, then CMake will automatically append $<CONFIG> to those output directories when building targets with Multi-Cofnig generators.

However, it is typically helpful (for me) to seperate artifacts into different folders for each configuration. Besides, I tend to make the structure of output directories the same for both Multi- and Single-Config generators. Therefore, I usually add $<CONFIG> in those (CMAKE_)XXX_OUPUT_DIRECTORY explicitly. The following two schemes are what I suggest:

  • Scheme 1

    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/$<CONFIG>")
    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/$<CONFIG>")
    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/$<CONFIG>")
    
  • Scheme 2

    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIG>/bin")
    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIG>/lib")
    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIG>/lib")
    

Here is a simple demo I wrote for this issue:

  1. Download and unzip the archive: test-cmake-set-output-dir.zip (2.9 KB)

  2. Run the following commands:

    vcvarsall.bat x64
    cmake --preset multi
    cmake --build out/multi --config Debug
    cmake --build out/multi --config Release
    cmake --preset single
    cmake --build out/single
    

The following is the full log:

Click to expand log
D:\Test\test-cmake-set-output-dir>vcvarsall.bat x64
**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.11.23
** Copyright (c) 2021 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

D:\Test\test-cmake-set-output-dir>cmake --preset multi
Preset CMake variables:

  CMAKE_CXX_COMPILER="cl.exe"
  CMAKE_C_COMPILER="cl.exe"

-- The C compiler identification is MSVC 19.29.30147.0
-- The CXX compiler identification is MSVC 19.29.30147.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Performing Test COMPILER_HAS_DEPRECATED_ATTR
-- Performing Test COMPILER_HAS_DEPRECATED_ATTR - Failed
-- Performing Test COMPILER_HAS_DEPRECATED
-- Performing Test COMPILER_HAS_DEPRECATED - Success
-- Configuring done (4.3s)
-- Generating done (0.0s)
-- Build files have been written to: D:/Test/test-cmake-set-output-dir/out/multi

D:\Test\test-cmake-set-output-dir>cmake --build out/multi --config Debug
[6/6] Linking CXX executable Debug\bin\main.exe

D:\Test\test-cmake-set-output-dir>cmake --build out/multi --config Release
[6/6] Linking CXX executable Release\bin\main.exe

D:\Test\test-cmake-set-output-dir>cmake --preset single
Preset CMake variables:

  CMAKE_BUILD_TYPE="Release"
  CMAKE_CXX_COMPILER="cl.exe"
  CMAKE_C_COMPILER="cl.exe"

-- The C compiler identification is MSVC 19.29.30147.0
-- The CXX compiler identification is MSVC 19.29.30147.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Performing Test COMPILER_HAS_DEPRECATED_ATTR
-- Performing Test COMPILER_HAS_DEPRECATED_ATTR - Failed
-- Performing Test COMPILER_HAS_DEPRECATED
-- Performing Test COMPILER_HAS_DEPRECATED - Success
-- Configuring done (4.5s)
-- Generating done (0.0s)
-- Build files have been written to: D:/Test/test-cmake-set-output-dir/out/single

D:\Test\test-cmake-set-output-dir>cmake --build out/single
[6/6] Linking CXX executable Release\bin\main.exe

D:\Test\test-cmake-set-output-dir>

The following screenshot is the result of adopting scheme 2:

1 Like