CMake可视化工具中如何配置Visual Studio的调试/发布模式。

11

我正在设置我的Visual Studio项目使用CMake,但我遇到了两个问题,而我还没有能够解决。

1. 如何为Release设置一个预处理器定义,并为Debug设置另一个?

2. 我有一个包含OpenGL和DirectX的项目,因此对于DebugOpenGL和ReleaseOpenGL,我希望将所有DirectX cpp/h文件从构建中排除。对于DebugDirectX和ReleaseDirectX,请排除OpenGL文件。如何设置这个?

编辑:

这是我到目前为止得到的第一个问题的解答:

cmake_minimum_required(VERSION 2.8)

project(TEngine)

if(CMAKE_CONFIGURATION_TYPES AND MSVC)
#DebugOpenGL flags
set(CMAKE_CXX_FLAGS_DEBUGOPENGL "/D_DEBUG /MDd /Zi /Ob0 /Od /RTC1" CACHE STRING "Flags used by the C++ compiler during maintainer builds." FORCE)
set(CMAKE_C_FLAGS_DEBUGOPENGL "/D_DEBUG /MDd /Zi  /Ob0 /Od /RTC1" CACHE STRING "Flags used by the C compiler during maintainer builds." FORCE)
set(CMAKE_EXE_LINKER_FLAGS_DEBUGOPENGL "/debug /INCREMENTAL" CACHE STRING "Flags used for linking binaries during maintainer builds." FORCE )
set(CMAKE_SHARED_LINKER_FLAGS_DEBUGOPENGL "/debug /INCREMENTAL" CACHE STRING "Flags used by the shared libraries linker during maintainer builds." FORCE )

#ReleaseOpenGL flags
set(CMAKE_CXX_FLAGS_RELEASEOPENGL "/MD /O2 /Ob2 /D NDEBUG" CACHE STRING "Flags used by the C++ compiler during maintainer builds." FORCE)
set(CMAKE_C_FLAGS_RELEASEOPENGL "/MD /O2 /Ob2 /D NDEBUG" CACHE STRING "Flags used by the C compiler during maintainer builds." FORCE)
set(CMAKE_EXE_LINKER_FLAGS_RELEASEOPENGL "/INCREMENTAL:NO" CACHE STRING "Flags used for linking binaries during maintainer builds." FORCE )
set(CMAKE_SHARED_LINKER_FLAGS_RELEASEOPENGL "/INCREMENTAL:NO" CACHE STRING "Flags used by the shared libraries linker during maintainer builds." FORCE )

#DebugDirectX flags
set(CMAKE_CXX_FLAGS_DEBUGDIRECTX "/D_DEBUG /MDd /Zi /Ob0 /Od /RTC1" CACHE STRING "Flags used by the C++ compiler during maintainer builds." FORCE)
set(CMAKE_C_FLAGS_DEBUGDIRECTX "/D_DEBUG /MDd /Zi  /Ob0 /Od /RTC1" CACHE STRING "Flags used by the C compiler during maintainer builds." FORCE)
set(CMAKE_EXE_LINKER_FLAGS_DEBUGDIRECTX "/debug /INCREMENTAL" CACHE STRING "Flags used for linking binaries during maintainer builds." FORCE )
set(CMAKE_SHARED_LINKER_FLAGS_DEBUGDIRECTX "/debug /INCREMENTAL" CACHE STRING "Flags used by the shared libraries linker during maintainer builds." FORCE )

#ReleaseDirectx flags
set(CMAKE_CXX_FLAGS_RELEASEDIRECTX "/MD /O2 /Ob2 /D NDEBUG" CACHE STRING "Flags used by the C++ compiler during maintainer builds." FORCE)
set(CMAKE_C_FLAGS_RELEASEDIRECTX "/MD /O2 /Ob2 /D NDEBUG" CACHE STRING "Flags used by the C compiler during maintainer builds." FORCE)
set(CMAKE_EXE_LINKER_FLAGS_RELEASEDIRECTX "/INCREMENTAL:NO" CACHE STRING "Flags used for linking binaries during maintainer builds." FORCE )
set(CMAKE_SHARED_LINKER_FLAGS_RELEASEDIRECTX "/INCREMENTAL:NO" CACHE STRING "Flags used by the shared libraries linker during maintainer builds." FORCE )

set(CMAKE_CONFIGURATION_TYPES "DebugOpenGL;ReleaseOpenGL;DebugDirectX;ReleaseDirectX")
set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING
"Reset the configurations to what we need"
FORCE)

if(CMAKE_BUILD_TYPE STREQUAL "DebugOpenGL")
    add_definitions(/DTE_USE_OPENGL)
endif()
if(CMAKE_BUILD_TYPE STREQUAL "ReleaseOpenGL")
    add_definitions(/DTE_USE_OPENGL)
endif()
if(CMAKE_BUILD_TYPE STREQUAL "DebugDirectX")
    add_definitions(/DTE_USE_OPENGL)
endif()
if(CMAKE_BUILD_TYPE STREQUAL "ReleaseDirectX")
    add_definitions(/DTE_USE_OPENGL)
endif()
endif()

set(Boost_ADDITIONAL_VERSIONS "1.47" "1.47.0")
set(BOOST_ROOT "${TEngine_SOURCE_DIR}/Externals/boost_1_47_0")

if(WIN32)
    add_definitions(-DTEWINDOWS)
elseif(LINUX)
    add_definitions(-DTELINUX -DTE_USE_OPENGL)
endif()

subdirs(TEEngineTest TECore TEGraphics TEPhysics TEngine)
3个回答

24
  1. 我该如何在Release和Debug模式下设置预处理器定义?

正确的方法是使用生成器表达式在正确的范围内设置COMPILE_DEFINITIONS属性。

如果您想像add_definitions()一样向所有目标添加定义,则使用:

  set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS
    $<$<CONFIG:DebugOpenGL>:_DEBUG>
    $<$<CONFIG:ReleaseOpenGL>:NDEBUG>
    $<$<CONFIG:DebugDirectX>:_DEBUG>
    $<$<CONFIG:ReleaseDirectX>:NDEBUG>
  )

  set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS
    $<$<CONFIG:DebugOpenGL>:TE_USE_OPENGL>
    $<$<CONFIG:ReleaseOpenGL>:TE_USE_OPENGL>
    $<$<CONFIG:DebugDirectX>:TE_USE_DIRECTX>
    $<$<CONFIG:ReleaseDirectX>:TE_USE_DIRECTX>
  )

你还可以为特定的目标文件源文件设置COMPILE_DEFINITIONS。请参阅set_property
为了设置其他编译标志,您可以像上面一样在目录、目标或源文件上设置COMPILE_OPTIONS属性。但是,您也可以使用add_compile_options()命令,因为与add_definitions()不同,它支持生成器表达式。您也可以为目标设置COMPILE_OPTIONS,或使用target_compile_options()。对于源文件,在CMake 3.3及以上版本中,您仍然需要设置COMPILE_FLAGS属性。
  set(MY_DEBUG_OPTIONS /MDd /Zi /Ob0 /Od /RTC1)
  set(MY_RELEASE_OPTIONS /MD /Ob2 /O2)

  add_compile_options(
    "$<$<CONFIG:DebugOpenGL>:${MY_DEBUG_OPTIONS}>"
    "$<$<CONFIG:ReleaseOpenGL>:${MY_RELEASE_OPTIONS}>"
    "$<$<CONFIG:DebugDirectX>:${MY_DEBUG_OPTIONS}>"
    "$<$<CONFIG:ReleaseDirectX>:${MY_RELEASE_OPTIONS}>"
  )

请注意,在这些生成器表达式中放置选项列表需要在add_compile_options()中使用引号。

  1. 我有一个包含OpenGL和DirectX的项目,因此对于DebugOpenGL和ReleaseOpenGL,我希望从构建中排除所有DirectX cpp/h文件。对于DebugDirectX和ReleaseDirectx,则排除OpenGL文件。我该如何设置?

这可能是一个问题。虽然可以使用生成器表达式有条件地向目标添加源文件,但我不知道任何支持每个配置源文件的IDE。Visual Studio和CMake的Visual Studio生成器都不支持它。Xcode和Xcode生成器也不支持此功能。因此,如果您想使用Visual Studio或其他IDE进行构建,则无法执行此操作。

使用一次单个配置的生成器(例如makefile或ninja生成器)应该可以很好地支持此功能。

与其让源文件在配置之间有所不同,还有几种其他选项。以下是其中之一。

您可以拥有多个目标,并使源文件在它们之间有所不同:

set(OPENGL_SOURCES src/opengl/func1.cpp src/opengl/func2.cpp)
set(DIRECTX_SOURCES src/opengl/func1.cpp src/opengl/func2.cpp)

add_executable(opengl_foo ${COMMON_SOURCES} ${OPENGL_SOURCES})
add_executable(directx_foo ${COMMON_SOURCES} ${DIRECTX_SOURCES})

请注意,这意味着您可以回到仅具有Debug和Release配置的状态,这将简化其余的配置。
或者,您可以通过在源代码中使用一些间接方式来保留单独的OpenGL和DirectX配置。创建一些“虚拟”的cpp文件和头文件,并根据预处理器定义在它们之间切换以包含您的opengl文件或directx文件:
// src/func1.h
#ifdef TE_USE_OPENGL
#  include "opengl/func1.h.inc"
#elif defined(TC_USE_DIRECTX)
#  include "directx/func1.h.inc"
#endif

// src/func1.cpp
#ifdef TE_USE_OPENGL
#  include "opengl/func1.cpp.inc"
#elif defined(TC_USE_DIRECTX)
#  include "directx/func1.cpp.inc"
#endif

然后在CMake中简单地引用这些虚拟文件:

add_executable(foo src/func1.h src/func1.cpp)

现在构建不同的配置将会拉取不同的代码。如果你将文件重命名为以.inc结尾,甚至可以在add_executable()中引用它们,这样它们就会显示在VS中,但VS不会直接构建它们。

虽然可以使用生成器表达式有条件地将源文件添加到目标中,但我不知道任何支持每个配置源文件的 IDE。Visual Studio允许这样做,可以通过在<ItemGroup>标记上放置条件,或在项目条目本身下面使用<ExcludedFromBuild>元素(带有条件)。 - ulatekh

14
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
  add_definitions(/DYOURDEFINITION)
endif()

这在 MSVS 多配置解决方案上下文中不起作用。你需要的是:

set(MY_DEFINITION 
    $<$<CONFIG:Debug>:definition_for_debug>
    $<$<CONFIG:RelWithDebInfo>:definition_for_rel_with_debug>
    $<$<CONFIG:Release>:definition_for_release> 
    $<$<CONFIG:MinSizeRel>:definition_for_tight_release>
    )

4

1:

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
  add_definitions(/DYOURDEFINITION)
endif()

2:如果我理解正确,您需要创建一个选项变量。

option(USE_OPENGL "Use OpenGL or DirectX")

在添加新目标时,请检查是否存在该项:

if(USE_OPENGL)
add_subdirectory(OpenGL)
else()
add_subdirectory(DirectX)
endif()

当然,你应该在OpenGL/和DirectX/目录下创建CMakeLists.txt文件。

我没有将文件放在不同的子文件夹中,但是我希望这些文件在项目中。对于OpenGL配置,我想要排除DirectX cpp/h文件;而对于DirectX配置,我想要排除OpenGL文件。在Visual Studio中,您可以右键单击文件并选择从构建中排除。第1个问题已得到解答,谢谢 :) - bitgregor
1
没问题,只需将我的答案中的add_subdirectory()调用替换为set(SOURCES Opengl1.cpp Opengl2.cpp etc)。在else分支中执行set(SOURCES DirectX1.cpp DirectX2.cpp etc)。最后,在if子句之外通过将${SRCS}传递给它来创建您的构建目标。 - arrowd
1
很好的回答,arrowdodger...只是稍微补充一下:如果你在CMake中使用set(SOURCES)和一些if-else语句,那么“未选择”的源文件将不会出现在Visual Studio中。 - André
1
另外还要补充一点:当从命令行运行cmake时,CMAKE_BUILD_TYPE未定义,因此1)中的检查可能会失败。也许更好的方法是使用COMPILE_DEFINITIONS属性,在那里您可以区分配置...虽然我必须承认这不是最优雅的解决方案。 - André
我现在正在尝试使用1。我正在构建Windows的GUI版本。配置已设置,但配置没有设置预处理器定义。我已经编辑了最初的帖子,附上了我的内容。 - bitgregor
我不需要遍历配置吗?我认为CMAKE_BUILD_TYPE总是设置为相同的值,对吗? - bitgregor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接