DavidA
DavidA

Reputation: 2359

How best to set output directory for a CMake C++ project built by Visual Studio 2017?

I have used Visual Studio 2017 to build C++ desktop projects using .vcxproj files. I like the default behavior where the output directory is a subdirectory below the project. For example:

|-myproj.sln
|-myproj.vcxproj
|-----------------|--x64 --|-- myproj_release --|-- myproj.exe

I now want to define the build using CMake instead of .vcxproj, so that I can build with Visual Studio Code as an alternative to Visual Studio 2017.

I converted my .vcxproj to a CMake project using cmake-converter. The resulting CMakeLists.txt contains:

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${OUTPUT_DEBUG}")
  set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${OUTPUT_DEBUG}")
  set(CMAKE_EXECUTABLE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${OUTPUT_DEBUG}")
else()
  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${OUTPUT_REL}")
  set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${OUTPUT_REL}")
  set(CMAKE_EXECUTABLE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${OUTPUT_REL}")
endif()

When I open this CMakeLists.txt with Visual Studio 2017 and build it, it puts the executable in subdirectory CMakeBuilds of my user directory. I guess this is because Visual Studio 2017 is determining CMAKE_BINARY_DIR.

What is the best way of getting the output directory to be in the source directory as happens with my .vcxproj file?

Upvotes: 1

Views: 10105

Answers (2)

Tsyvarev
Tsyvarev

Reputation: 65870

Visual Studio is a multiconfiguration generator. That is, it configures the project for several configurations at once. Because of that, when using such generators the variable CMAKE_BUILD_TYPE doesn't contain the configuration name, it is simply empty.

By default, with multiconfiguration generators, variables like CMAKE_LIBRARY_OUTPUT_DIRECTORY are automatically appended with per-configuration subdirectory. There are two ways to handle this behaviour:

  1. Use generator expressions when defining the variable. That expression may be evaluated conditionally, depended on the configuration type. E.g.:

     # For Debug configuration this will be evaluated to
     #   '${CMAKE_BINARY_DIR}/${OUTPUT_DEBUG}'
     # For Release configuration this will be evaluated to
     #   '${CMAKE_BINARY_DIR}/${OUTPUT_REL}'
     set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<$<CONFIG:DEBUG>:${OUTPUT_DEBUG}>$<$<CONFIG:RELEASE>:${OUTPUT_REL}>")
    
  2. Use _<CONFIG> versions of the variable. E.g.:

     # Output directory for libraries in Debug configuration
     set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/${OUTPUT_DEBUG})
     # Output directory for libraries in Release configuration
     set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/${OUTPUT_REL})
    

Upvotes: 6

DavidA
DavidA

Reputation: 2359

I think the answer for my question is to modify buildRoot in CmakeSettings.json:

"buildRoot": "${workspaceRoot}\\build\\${name}"

Upvotes: 6

Related Questions