In CMake, how do I work around the Debug and Release directories Visual Studio 2010 tries to add?

28,070

Solution 1

It depends a bit on what you want precisely, but I would recommend to take a look at the available target properties, similar to this question.

It depends a bit on what you want exactly. For each target, you could manually set the library_output_directory or runtime_output_directory properties.

if ( MSVC )
    set_target_properties( ${targetname} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${youroutputdirectory} )
    set_target_properties( ${targetname} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_DEBUG ${youroutputdirectory} )
    set_target_properties( ${targetname} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_RELEASE ${youroutputdirectory} )
    # etc for the other available configuration types (MinSizeRel, RelWithDebInfo)
endif ( MSVC )

You could also do this globally for all sub-projects, using something like this:

# First for the generic no-config case (e.g. with mingw)
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${youroutputdirectory} )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${youroutputdirectory} )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${youroutputdirectory} )
# Second, for multi-config builds (e.g. msvc)
foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} )
    string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG )
    set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${youroutputdirectory} )
    set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${youroutputdirectory} )
    set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${youroutputdirectory} )
endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES )

Solution 2

https://cmake.org/cmake/help/latest/prop_tgt/LIBRARY_OUTPUT_DIRECTORY.html explains that:

Multi-configuration generators (VS, Xcode) append a per-configuration subdirectory to the specified directory unless a generator expression is used.

Thus, the only workaround is to use a generator expression. One cool way to do it is by using $<0:> at the end of your path. So if your path is /what/ever/, you will need to replace it with /what/ever/$<0:>.

Example with the target: Nuua and the path: C:/Nuua/bin/

set_target_properties(nuua PROPERTIES RUNTIME_OUTPUT_DIRECTORY C:/Nuua/bin/$<0:>)

Solution 3

In current versions of CMake you can use a generator expression for LIBRARY_OUTPUT_DIRECTORY to avoid the configuration-specific suffix.

I just added $<$<CONFIG:Debug>:>, which always expands to nothing, to mine. This looks a bit weird, but it does work, and it's not so weird you can't explain it with a brief comment:

# Use a generator expression so that the specified folder is used directly, without any
# configuration-dependent suffix.
#
# See https://cmake.org/cmake/help/v3.8/prop_tgt/LIBRARY_OUTPUT_DIRECTORY.html
set_target_properties(library PROPERTIES
                      LIBRARY_OUTPUT_DIRECTORY my/folder/$<$<CONFIG:Debug>:>)

Solution 4

Big thanks to Erik's for the hint to use $<0:>

If you have multiple targets that you want that solution for you could do something like

# Get Targets in ${CMAKE_CURRENT_SOURCE_DIR}
get_property(current_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)
foreach(TARGET ${current_targets})
    set_target_properties(${TARGET} PROPERTIES
                        RUNTIME_OUTPUT_DIRECTORY  ${CMAKE_BINARY_DIR}/$<0:> 
                        LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$<0:>
                        ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$<0:>)
endforeach()

to perform it for all targets in ${CMAKE_CURRENT_SOURCE_DIR} without having to add it for each executable/library individually

Share:
28,070
Stuart Golodetz
Author by

Stuart Golodetz

Enthusiastic computer scientist and somewhat sporadic author of articles for ACCU journals. Likes: games programming, challenges, learning new things, code craftsmanship, watching people achieving to the best of their ability, Git. Dislikes: untidy code, weak architecture, bad software processes, indifference, technological fads. Very quick bio: My D.Phil. was in medical image segmentation at the University of Oxford. I then worked in industry for a bit, doing credit risk management at SunGard and software analytics/logic programming at Semmle. After returning to Oxford for the first time, I spent a few years working as a postdoc on computer vision and SLAM. I then spent a couple of years running a research group for an autonomous driving startup called FiveAI. I've since returned to Oxford for the second time, where I'm currently working on UAV SLAM and related topics.

Updated on January 15, 2022

Comments

  • Stuart Golodetz
    Stuart Golodetz over 2 years

    I'm trying to build one of my CMake-based projects from a couple of years ago with Visual Studio 2010 and I'm running into problems to do with the output directory for a project. Visual Studio has always been very keen on adding Debug/ and Release/ subdirectories when outputting binaries, and for various reasons I've always been very keen on removing them - now that I'm using a new version of CMake and a new version of Visual Studio, the old workaround in CMake no longer seems to work, and I'm looking to find out the "new" way of doing it.

    With a previous version of CMake (2.6) and a previous version of Visual Studio (2008), I used the following:

    IF(MSVC_IDE)
        # A hack to get around the "Debug" and "Release" directories Visual Studio tries to add
        SET_TARGET_PROPERTIES(${targetname} PROPERTIES PREFIX "../")
        SET_TARGET_PROPERTIES(${targetname} PROPERTIES IMPORT_PREFIX "../")
    ENDIF(MSVC_IDE)
    

    This worked fine, but no longer seems to do the trick. Please does anyone know of a similar but more up-to-date workaround that will work with CMake 2.8.6 and Visual Studio 2010?

  • Stuart Golodetz
    Stuart Golodetz over 12 years
    Brilliant, thanks - it turns out I was looking for the ARCHIVE_OUTPUT_DIRECTORY_{config} properties on the target. Cheers! :)
  • choosyg
    choosyg over 9 years
    I do exactly the same and it works until e.g. add_executable(test test.cpp) get_target_property(test_EXE test LOCATION) is called, it still has the D:/Codebase/test/bin/$(Configuration)/test.exe any idea how to fix this issue?
  • Artalus
    Artalus over 5 years
    I wish there was a SO feature for third party to review questions on CMake over time and mark answers made 6 years later as "forget everything mentioned before, THIS is how you do the X in 2019"
  • Pavel K.
    Pavel K. about 5 years
    I've a bit confused with word "Debug" in the suggested expression, possible it can be simplified to "$<$<CONFIG:>:>" ?
  • Tom Seddon
    Tom Seddon about 5 years
    @PavelK. I think the $<CONFIG:> test requires a configuration name. Perhaps you could use $<0:> or something instead, though.
  • Royi
    Royi over 4 years
    Which variable will hold the output folder for the current project (Without working with the different configurations)? Namely if I work on release will point to the x64\Release` and if I run debug mode will point to the x64\Debug` folder? Namely I don't want to change it, I just want to access it.
  • legends2k
    legends2k about 3 years
    What does $<0:> signify? Just a generator expression which evaluates to nil?
  • legends2k
    legends2k about 3 years
    Erik's answer quotes CMake documentation that explains why this works.
  • legends2k
    legends2k over 2 years
    It evalutes to an empty string. Without the expression the generator is free to set RUNTIME_OUTPUT_DIRECTORY to per-configuration sub-directory. Having the expression forces the generator to evaluate and set this property to the expected directory!