Context:
我正在将一个项目从普通 Makefile 迁移到 CMake,以添加对多个编译器 (gfortran + ifort) 和操作系统 (Windows + Linux) 的支持。当我完成整个事情时,我正在尝试简化 CMake 行为并为用户提供一些额外的功能。
在跨操作系统和使用的编译器的可能组合规范和调整编译器选项之后,添加用户定义的构建类型“DEBUGVERBOSE”并启用所有检查和警告似乎是合理的。因为我们正在处理非常旧的旧版 Fortran 77 代码,所以这些设置会生成 >3000 个警告,这就是为什么我不想在标准调试构建类型中包含所有警告。对于未来的代码清理和调试来说,这似乎是合适的。
Issue:
我想将这个用户定义的构建类型“DEBUGVERBOSE”添加到 Visual Studio 2012 中的可用配置列表中。同时我想摆脱 cmake 生成的构建类型“MinSizeRel”和“RelWithDebInfo”以简化用户界面(因为我们从不使用这些配置)。
根据CMake-Wiki - 如何使用定制模式扩展构建模式? http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_specify_my_own_configurations_.28for_generators_that_allow_it.29_.3F我设置构建类型如下:
# Set Project Name and supported Languages(optional)
project (s4 Fortran C)
# Set Version Number
set (S4_VERSION_MAJOR 1)
set (s4_VERSION_MINOR 0)
# Set Source Language
enable_language (Fortran)
...
if(WIN32)
# Release flags
set(CMAKE_Fortran_FLAGS_RELEASE " ${CMAKE_Fortran_FLAGS_RELEASE} /D__WIN_intel__ /assume:byterecl")
# Debug Flags
set(CMAKE_Fortran_FLAGS_DEBUG " ${CMAKE_Fortran_FLAGS_DEBUG} /D__WIN_intel__ /assume:byterecl /Od /warn:all /check:all
/warn:notruncated_source /warn:nodeclarations /warn:nounused")
# verbose Debug flags (user-defined build type)
set(CMAKE_Fortran_FLAGS_DEBUGVERBOSE " /debug:full /dbglibs /D__WIN_intel__ /assume:byterecl /Od /warn:all /check:all"
CACHE STRING "Extended Debug Flags used by the Fortran compiler during verbose Debug builds.")
set(CMAKE_CXX_FLAGS_DEBUGVERBOSE " ${CMAKE_CXX_FLAGS_DEBUG}"
CACHE STRING "Flags used by the C++ compiler during verbose Debug builds." FORCE )
set(CMAKE_C_FLAGS_DEBUGVERBOSE " ${CMAKE_C_FLAGS_DEBUG}"
CACHE STRING "Flags used by the C compiler during verbose Debug builds." FORCE )
set(CMAKE_EXE_LINKER_FLAGS_DEBUGVERBOSE "${CMAKE_EXE_LINKER_FLAGS_DEBUG}"
CACHE STRING "Flags used for linking binaries during verbose Debug builds." FORCE )
set(CMAKE_SHARED_LINKER_FLAGS_DEBUGVERBOSE "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}"
CACHE STRING "Flags used by the shared libraries linker during verbose Debug builds." FORCE )
elseif(UNIX)
...<definition of Release, Debug, DebugVerbose Compiler Options>
endif()
# Edit available Configrations to make them available in IDE that support multiple-configuration (for example Visual Studio)
if(CMAKE_CONFIGURATION_TYPES)
set(CMAKE_CONFIGURATION_TYPES Release, Debug, Debugverbose)
set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING
"Reset the configurations to what we need" FORCE)
endif()
...<definition of lots of source files and build targets>...
# Visual Studio Userfile (set the debugging environment):
CreateUserfile()
这会在第一次 cmake-configure +generate 运行时设置(根据 cmake-gui 和 CMakeCache.txt)相应的变量。但直到第二次 cmake-configure + 生成之后,它们才会显示在 Visual Studio 解决方案中。我还在命令行中对此进行了测试,并且还需要运行两次才能将设置输入 Visual Studio。
这种行为似乎也存在于较旧的 cmake 和 Visual Studio 版本中,如中所示这个答案 https://stackoverflow.com/a/6562390/2969529 to “如何使用 CMake 创建新配置” https://stackoverflow.com/questions/4212945/how-to-create-a-new-configuration-with-cmake。这也会导致 cmake 错误报告0005811:为 MSVC 创建新配置 http://www.cmake.org/Bug/view.php?id=5811这可能是造成这种行为的原因。
我们使用的所有其他生成器(代码:Blocks + MinGW;UNIX Makefiles)都没有这种行为,并且可以在第一次运行时完成工作。我知道 Visual Studio 很特别,因为它是我们设置中唯一的多配置 IDE,但我通常不赞成不一致的行为,因为它会让用户感到困惑。
问题:
我的方法有什么问题吗,或者这个 cmake 行为(->需要多次运行)是有意的/目前不可更改吗?
目前的解决方法:
我找到了一个解决方法 -here http://www.cmake.org/pipermail/cmake/2012-January/048856.html- 我只将用户定义的构建类型附加到已有的配置中。请注意设置“项目”和“语言”之间“CMAKE_CONFIGURATION_TYPES”if 语句的位置!
# Set Project Name and supported Languages(optional)
project (s4 Fortran C)
# Set Version Number
set (S4_VERSION_MAJOR 1)
set (s4_VERSION_MINOR 0)
# Edit available Configrations to make them available in IDE that support multiple-configuration (for example Visual Studio)
if(CMAKE_CONFIGURATION_TYPES)
set(CMAKE_CONFIGURATION_TYPES Debugverbose)
set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING
"Append user-defined configuration to list of configurations to make it usable in Visual Studio" FORCE)
endif()
# Set Source Language
enable_language (Fortran)
...
if(WIN32)
...<definition of Release, Debug, DebugVerbose Compiler Options>
elseif(UNIX)
...<definition of Release, Debug, DebugVerbose Compiler Options>
endif
...<definition of lots of source files and build targets>...
# Visual Studio Userfile (set the debugging environment):
CreateUserfile()
使用此解决方案,“DEBUGVERBOSE”配置会在第一次 cmake-configure +generate 运行后添加到现有配置中,并且还会显示在 Visual Studio 中。但似乎不可能更改配置列表以忽略 cmake 生成的构建类型“MinSizeRel”和“RelWithDebInfo”(即使在多次 cmake 运行之后)。
随着上述帖子 http://www.cmake.org/pipermail/cmake/2012-January/048856.html来自 cmake 讨论组,是否可以改进我的解决方法,以便 Visual Studio 中仅存在配置“Release、Debug、DebugVerbose”?
EDIT :
正如彼得在this https://stackoverflow.com/a/21285845/2969529回答我的实现中有一个错误。遗憾的是,修复此问题并没有改变 Visual Studio 2012 的行为。
# Set Project Name and supported Languages(optional)
project (s4)
...
# Set Source Language
enable_language (Fortran C)
...
我在此修改中遇到的唯一区别是在将新的 CMakeCache.txt 与前一个进行比较时:CMake 添加了“CXX”的编译器标志。我认为这意味着 C++、C# 等编译器标志?
从此构建并重读之后相应的帖子 http://www.cmake.org/pipermail/cmake/2012-January/048856.html我从 cmake 讨论组开始进行实验。使用 PROJECT、enable_language 和 CMAKE_CONFIGURATION_TYPES 位置的几种组合进行测试,我想分享我的发现。
-
CMAKE_CONFIGURATION_TYPESafter项目(s4 Fortran C),例如省略启用语言:
如果没有启用语言,代码需要 2 次 CMake 传递才能使 Visual Studio 识别新设置,同时使用第一次传递更新缓存。因此,enable_language 似乎将设置传播到 Visual Studio *.sln 文件。
-
CMAKE_CONFIGURATION_TYPESbefore项目(s4)声明:
需要第二次 cmake 传递才能将设置传播到 CMakeCache.txt。但 Visual Studio 无法识别这些设置。通过此设置,似乎可以更改可用的构建类型,但由于 Visual Studio 无法识别它们,并且需要第二次 cmake 传递来传播它们,因此此选项对于我的情况不可行。
-
CMAKE_CONFIGURATION_TYPESbetween项目(s4)和enable_language(Fortran C):
CMakeCache.txt 和 Visual Studio 中的第一遍都会识别这些设置。后续的 cmake 传递不会更改缓存。因此我认为这个方法足够了。
但删除某些构建类型或重写 CMAKE_CONFIGURATION_TYPES 似乎是不可能的。我测试了上述讨论组的建议,例如使用 LIST(APPEND ...) 显式附加新的构建类型并检查/删除重复项。看来这些措施是在配置例程中隐式实现的,因为添加(或省略)这些措施并没有改变行为或缓存文件(无论是使用语句 LIST(APPEND ...) 还是 SET(...) )。
我注意到的另一个行为是用户定义的字符串
set(CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES}
CACHE STRING "Append user-defined configuration to list of configurations to make it usable in Visual Studio" FORCE)
仅在第 2 种情况下被认可。使用 3. Case 它似乎被忽略,并且标准 CMake 字符串似乎在缓存中设置。
RESULT :
根据这些发现,可以得出当前已实施的代码。
# Set Project Name
project (s4)
# Set Version Number
set (S4_VERSION_MAJOR 1)
set (s4_VERSION_MINOR 0)
# Edit available Configrations to make them available in IDE that support multiple-configuration (for example Visual Studio)
# has to be between "project" and "enable_language" to work as intended!
if(CMAKE_CONFIGURATION_TYPES)
list(APPEND CMAKE_CONFIGURATION_TYPES Debugverbose)
set(CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES}
CACHE STRING"Append user-defined configuration to list of configurations to make it usable in Visual Studio" FORCE)
endif()
# Set Source Language
enable_language (Fortran C)
...
我采用了 LIST(APPEND ...) 语句,因为它提高了可读性并明确说明了代码正在做什么。如上所述,它不会改变 CMake 的行为,例如自动检查重复项。
开放性问题:
我的实验结论有错误吗?也许有人足够了解内部 CMake 程序来详细说明上述行为?例如,为什么 set(CMAKE_CONFIGURATION_TYPES ...) 语句中的字符串无法识别?
原来的问题仍然存在:
有没有办法将 CMAKE_CONFIGURATION_TYPES 重置为用户定义的列表,并将这些设置传递到缓存和 Visual Studio,只需 1 个 CMake 传递?