Closed smanders closed 4 years ago
completed with commit to dev branch referenced above
there is a new issue on Windows setting the runtime library when
cmake_minimum_required(VERSION 3.17)
externpro builds all of it's projects (by default) with static runtime /MT
(but can be configured to build with /MD
)
https://github.com/smanders/externpro/blob/20.06.1/modules/macpro.cmake#L88-L92
if(MSVC)
cmake_dependent_option(XP_BUILD_STATIC "build with static runtime (/MT), OFF: dynamic runtime (/MD)" ON
"XP_STEP STREQUAL build" ON
)
endif()
this choice (/MT
or /MD
) is stored in externpro's share/cmake/xpopts.cmake
file
https://github.com/smanders/externpro/blob/20.06.1/modules/macpro.cmake#L311-L315
if(${CMAKE_PROJECT_NAME} STREQUAL externpro)
configure_file(${MODULES_DIR}/xpopts.cmake.in
${STAGE_DIR}/share/cmake/xpopts.cmake
@ONLY NEWLINE_STYLE LF
)
https://github.com/smanders/externpro/blob/20.06.1/modules/xpopts.cmake.in
set(XP_BUILD_STATIC_RT @XP_BUILD_STATIC@)
so at cmake-time of externpro, the choice to use /MT
or /MD
has been stored in a boolean XP_BUILD_STATIC_RT
projects can
so how do all these different projects determine what was chosen for the runtime library?
include(flags OPTIONAL)
, which calls xpCommonFlags()
https://github.com/smanders/externpro/blob/20.06.1/modules/flags.cmake#L9xpSetFlags()
, which calls xpCommonFlags()
and xpCommonFlags()
determines XP_BUILD_STATIC_RT
from the xpopts.cmake
file
https://github.com/smanders/externpro/blob/20.06.1/modules/xpfunmac.cmake#L1816
include(${xpThisDir}/xpopts.cmake) # determine XP_BUILD_STATIC_RT
the boolean XP_BUILD_STATIC_RT
is used to set the release and debug postfix for targets (executables and libraries) with a call to xpSetPostfix()
https://github.com/smanders/externpro/blob/20.06.1/modules/xpfunmac.cmake#L1802-L1810
function(xpSetPostfix)
if(XP_BUILD_STATIC_RT)
set(CMAKE_RELEASE_POSTFIX "-s" PARENT_SCOPE)
set(CMAKE_DEBUG_POSTFIX "-sd" PARENT_SCOPE)
else()
set(CMAKE_RELEASE_POSTFIX "" PARENT_SCOPE)
set(CMAKE_DEBUG_POSTFIX "-d" PARENT_SCOPE)
endif()
endfunction()
the boolean XP_BUILD_STATIC_RT
is also used by MSVC (which has CMAKE_CONFIGURATION_TYPES
) to modify the following CMAKE_[C|CXX]_FLAGS_*
...
https://github.com/smanders/externpro/blob/20.06.1/modules/xpfunmac.cmake#L1829-L1839
if(CMAKE_CONFIGURATION_TYPES)
# by default we'll modify the following list of flag variables,
# but you can call xpModifyRuntime with your own list
xpModifyRuntime(
CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_DEBUG
CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_DEBUG
# NOTE: these are the only flags we modify in common (including externpro-built projects), for now
)
endif()
and you can see in the implementation of xpModifyRuntime()
that if(XP_BUILD_STATIC_RT)
that any /MD
is replaced with /MT
(/MD
is the default runtime library set by cmake -- so we change the default here)
https://github.com/smanders/externpro/blob/20.06.1/modules/xpfunmac.cmake#L1779-L1800
function(xpModifyRuntime)
if(XP_BUILD_STATIC_RT)
set(from "/MD")
set(to "/MT")
else()
set(from "/MT")
set(to "/MD")
endif()
foreach(flagVar ${ARGV})
if(DEFINED ${flagVar})
if(${flagVar} MATCHES "${from}")
string(REGEX REPLACE "${from}" "${to}" flagTmp "${${flagVar}}")
if(${flagVar} MATCHES ".*CXX_FLAGS.*")
set(cType "C++ ")
elseif(${flagVar} MATCHES ".*C_FLAGS.*")
set(cType "C ")
endif()
set(${flagVar} ${flagTmp} CACHE STRING "Flags used by the ${cType}compiler." FORCE)
endif()
endif()
endforeach()
endfunction()
and this has been the way to change or set the runtime library for as long as we've been using cmake: modify the CMAKE_[C|CXX]_FLAGS_*
to have either /MT
or /MD
3.12
and 3.17
cmake 3.17.3 is installed on a Windows system
when a project requires an older version of cmake (3.12
for our purposes here)
cmake_minimum_required(VERSION 3.12)
after running cmake, we look for the compiler flags in the cmake cache
$ grep CMAKE_CXX_FLAGS_RELEASE CMakeCache.txt
CMAKE_CXX_FLAGS_RELEASE:STRING=/MT /O2 /Ob2 /DNDEBUG
//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1
and we see that /MT
is present, and we examine a generated Visual Studio project file
$ grep RuntimeLibrary nitf/nitf.vcxproj
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
and we see that MultiThreaded
or /MT
is set
when a project requires a newer version of cmake (3.17
for our purposes here)
cmake_minimum_required(VERSION 3.17)
after running cmake, we look for the compiler flags in the cmake cache
$ grep CMAKE_CXX_FLAGS_RELEASE CMakeCache.txt
CMAKE_CXX_FLAGS_RELEASE:STRING=/MT /O2 /Ob2 /DNDEBUG
//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1
and we see that /MT
is still present, but then we examine a generated Visual Studio project file
$ grep RuntimeLibrary nitf/nitf.vcxproj
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
and we see that MulitThreadedDLL
or /MD
is being used
edit: when cmake is run from a clean out-of-source build directory, it appears that the CMAKE_CXX_FLAGS aren't modified
$ grep CMAKE_CXX_FLAGS_RELEASE CMakeCache.txt
CMAKE_CXX_FLAGS_RELEASE:STRING=/O2 /Ob2 /DNDEBUG
//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1
newer cmake releases (but only when a project sets the minimum required to the new version) are no longer using CMAKE_[C|CXX]_FLAGS_*
to set the MSVC runtime library
it appears that cmake 3.15 introduced CMAKE_MSVC_RUNTIME_LIBRARY
and MSVC_RUNTIME_LIBRARY
cmake 3.15 release notes https://cmake.org/cmake/help/v3.15/release/3.15.html#variables
The
CMAKE_MSVC_RUNTIME_LIBRARY
variable andMSVC_RUNTIME_LIBRARY
target property were introduced to select the runtime library used by compilers targeting the MSVC ABI. See policy CMP0091.
this policy has the details... https://cmake.org/cmake/help/v3.15/policy/CMP0091.html
In CMake 3.14 and below, MSVC runtime library selection flags are added to the default
CMAKE_<LANG>_FLAGS_<CONFIG>
cache entries by CMake automatically. This allows users to edit their cache entries to adjust the flags. However, the presence of such default flags is problematic for projects that want to choose a different runtime library programmatically. In particular, it requires string editing of theCMAKE_<LANG>_FLAGS_<CONFIG>
variables with knowledge of the CMake builtin defaults so they can be replaced.CMake 3.15 and above prefer to leave the MSVC runtime library selection flags out of the default
CMAKE_<LANG>_FLAGS_<CONFIG>
values and instead offer a first-class abstraction. TheCMAKE_MSVC_RUNTIME_LIBRARY
variable andMSVC_RUNTIME_LIBRARY
target property may be set to select the MSVC runtime library. If they are not set then CMake uses the default valueMultiThreaded$<$<CONFIG:Debug>:Debug>DLL
which is equivalent to the original flags.
so we could use cmake_policy()
to set it to OLD
and
place MSVC runtime library flags in the default
CMAKE_<LANG>_FLAGS_<CONFIG>
cache entries and ignore theCMAKE_MSVC_RUNTIME_LIBRARY
abstraction
but at some point the OLD
behavior (deprecated by definition) may be removed in a future version of CMake
so it really would be best to modify the externpro cmake to support the NEW
behavior and use CMAKE_MSVC_RUNTIME_LIBRARY
and/or MSVC_RUNTIME_LIBRARY
-- and so I've reopened this issue to address this in externpro
stackoverflow discussion https://stackoverflow.com/questions/14172856/compile-with-mt-instead-of-md-using-cmake
several projects built via externpro report cmake warnings when built with cmake 3.17
I'm not going to address the llvm cmake warnings, since 1. we're on an older version and there's a chance these are fixed a newer version that hopefully we move to sometime soon, 2. we don't currently patch llvm, or clang, or clang-format, or clang-tidy, or clang-tools-extra -- and I'd rather keep it that way
cmake 3.17 Debug emits cmake warnings
for example, a Debug build of palam
$ cmake -DCMAKE_BUILD_TYPE=Debug /path/to/src
...
CMake Warning (dev) at /usr/share/cmake-3.17/Modules/CMakeDependentOption.cmake:39 (option):
Policy CMP0077 is not set: option() honors normal variables. Run "cmake
--help-policy CMP0077" for policy details. Use the cmake_policy command to
set the policy and suppress this warning.
For compatibility with older versions of CMake, option is clearing the
normal variable 'XP_USE_ASAN'.
Call Stack (most recent call first):
/opt/extern/externpro-20.06.1-gcc750-64-Linux/share/cmake/xpfunmac.cmake:1999 (cmake_dependent_option)
/opt/extern/externpro-20.06.1-gcc750-64-Linux/share/cmake/xpfunmac.cmake:2067 (xpSetFlagsGccDebug)
/opt/extern/externpro-20.06.1-gcc750-64-Linux/share/cmake/xpfunmac.cmake:2121 (xpSetFlagsGcc)
CMakeLists.txt:32 (xpSetFlags)
This warning is for project developers. Use -Wno-dev to suppress it.
CMake Warning (dev) at /usr/share/cmake-3.17/Modules/CMakeDependentOption.cmake:39 (option):
Policy CMP0077 is not set: option() honors normal variables. Run "cmake
--help-policy CMP0077" for policy details. Use the cmake_policy command to
set the policy and suppress this warning.
For compatibility with older versions of CMake, option is clearing the
normal variable 'XP_COVERAGE'.
Call Stack (most recent call first):
/opt/extern/externpro-20.06.1-gcc750-64-Linux/share/cmake/xpfunmac.cmake:2005 (cmake_dependent_option)
/opt/extern/externpro-20.06.1-gcc750-64-Linux/share/cmake/xpfunmac.cmake:2067 (xpSetFlagsGccDebug)
/opt/extern/externpro-20.06.1-gcc750-64-Linux/share/cmake/xpfunmac.cmake:2121 (xpSetFlagsGcc)
CMakeLists.txt:32 (xpSetFlags)
This warning is for project developers. Use -Wno-dev to suppress it.
same kind of cmake warning fixed previously https://github.com/smanders/externpro/commit/11274b9ec0e1db943dae0a4408484184631be91d
cmake-gui 3.17 on Windows has changed... the choice of generators no longer includes the platform
cmake-gui 3.12.0
cmake-gui 3.17.3
cmake 3.17 command line still lets you specify the generator and platform together
cmake -G "Visual Studio 15 2017 Win64"
see Visual Studio 15 2017 "For compatibility with CMake versions prior to 3.1" https://cmake.org/cmake/help/v3.17/generator/Visual%20Studio%2015%202017.html#platform-selection
however, Visual Studio 16 2019 no longer provides this compatibility and the platform is a separate argument
cmake -G "Visual Studio 16 2019" -A x64
https://cmake.org/cmake/help/v3.17/generator/Visual%20Studio%2016%202019.html#platform-selection
so the cmake-gui change (above) is moving us in the direction of specifying the platform (-A
) separate from the generator (-G
)
see cmake options https://cmake.org/cmake/help/v3.17/manual/cmake.1.html#options
the changes above break projects built by externpro when cmake-gui is used to choose the generator and platform -- the optional platform isn't relayed on to the projects built by externpro, so they default to Win32
on Windows
set(XP_CONFIGURE_GEN ${CMAKE_GENERATOR})
https://github.com/smanders/externpro/blob/20.06.1/modules/xpfunmac.cmake#L363
and XP_CONFIGURE_GEN
is used to set the CMAKE_GENERATOR
in the ExternalProject_Add()
command
ExternalProject_Add(${XP_TARGET} DEPENDS ${XP_DEPS} ${ADDITIONAL_DEPENDS}
DOWNLOAD_COMMAND "" DOWNLOAD_DIR ${NULL_DIR}
SOURCE_DIR ${SOURCE_DIR}
CMAKE_GENERATOR ${XP_CONFIGURE_GEN} CMAKE_ARGS ${XP_CONFIGURE_CMD}
BUILD_COMMAND ${XP_BUILD_CMD}
INSTALL_COMMAND ${XP_INSTALL_CMD} INSTALL_DIR ${NULL_DIR}
)
https://github.com/smanders/externpro/blob/20.06.1/modules/xpfunmac.cmake#L436-L442
so this all works fine if CMAKE_GENERATOR
includes the platform (Win64 for x64), but when the generator is separate from the platform, the platform defaults to Win32
the solution is that ExternalProject_Add()
has the ability to specify CMAKE_GENERATOR_PLATFORM
-- see "Configure Step Options" https://cmake.org/cmake/help/v3.17/module/ExternalProject.html
completed with commits to dev branch referenced above
now that externpro builds cmake 3.17 on linux https://github.com/smanders/externpro/issues/268 and installers are available for cmake 3.17.3 with the externpro 20.06.1 release https://github.com/smanders/externpro/releases/tag/20.06.1 -- externpro should require cmake 3.17 to build