Changing output directories

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