'Platform detection in CMake
I've added some functionality from boost::asio, which has precipitated some compiler "warnings":
Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately.
That problem was dealt with here. I'd like to have CMake detect when I am building on Windows and make the appropriate definitions or command line arguments.
Solution 1:[1]
Here is a simple solution.
macro(get_WIN32_WINNT version)
if (WIN32 AND CMAKE_SYSTEM_VERSION)
set(ver ${CMAKE_SYSTEM_VERSION})
string(REPLACE "." "" ver ${ver})
string(REGEX REPLACE "([0-9])" "0\\1" ver ${ver})
set(${version} "0x${ver}")
endif()
endmacro()
get_WIN32_WINNT(ver)
add_definitions(-D_WIN32_WINNT=${ver})
Solution 2:[2]
Inside the CMakeLists.txt file you can do:
IF (WIN32)
# set stuff for windows
ELSE()
# set stuff for other systems
ENDIF()
Solution 3:[3]
Here's an expanded version of KneLL's answer, also checking for Windows 10.
if(WIN32)
macro(get_WIN32_WINNT version)
if(CMAKE_SYSTEM_VERSION)
set(ver ${CMAKE_SYSTEM_VERSION})
string(REGEX MATCH "^([0-9]+).([0-9])" ver ${ver})
string(REGEX MATCH "^([0-9]+)" verMajor ${ver})
# Check for Windows 10, b/c we'll need to convert to hex 'A'.
if("${verMajor}" MATCHES "10")
set(verMajor "A")
string(REGEX REPLACE "^([0-9]+)" ${verMajor} ver ${ver})
endif()
# Remove all remaining '.' characters.
string(REPLACE "." "" ver ${ver})
# Prepend each digit with a zero.
string(REGEX REPLACE "([0-9A-Z])" "0\\1" ver ${ver})
set(${version} "0x${ver}")
endif()
endmacro()
get_WIN32_WINNT(ver)
add_definitions(-D_WIN32_WINNT=${ver})
endif()
Solution 4:[4]
As karlphilip pointed out, you can use if(WIN32) for platform detection.
You'll have a number of possibilities for passing preprocessor defines to the application:
- Use a configure header that gets preprocessed by CMake's configure_file. This approach has the advantage that all
#defines are actually part of the code and not of the build environment. The disadvantage is that it requires an (automatic) preprocessing step by CMake - Use add_definitions. This will add the preprocessor flag for all source files in the project, so it's more of a quick and dirty approach.
Use the COMPILE_DEFINITIONS property. This allows fine grained control over the defines on a per-file (and even per-config) basis:
set_property(SOURCE ${YOUR_SOURCE_FILES} APPEND PROPERTY COMPILE_DEFINITIONS YOUR_FLAG1 YOUR_FLAG2)In modern CMake versions (2.8.12 and higher) you can also use the more convenient
target_compile_definitionscommand for this.
I usually prefer the latter, but that's mostly a matter of personal taste.
Solution 5:[5]
I would like to clarify one detail here that nobody has mentioned yet. This point especially applies when cross compiling, but is valid otherwise too.
CMAKE_HOST_WIN32 is the variable that is set when compiling ON Windows.
WIN32 is the variable that is set when compiling FOR a Windows target platform.
So CMAKE_HOST_WIN32 is the correct flag to use considering OP's question literally "when I am building on Windows". In many cases WIN32 and CMAKE_HOST_WIN32 will be equivalent, but not in all cases.
WIN32 will be set too in the beginning when cross-compiling ON Windows FOR non-Windows, but will be implicitly unset at some point during CMake execution (I believe inside project call). Last time I checked WIN32 was set during executing toolchain.cmake, but was not set at a later point. So in these cases this flag can be dangerous as its state changes during the execution. You should NOT use WIN32 inside a toolchain file!
If you need details about the platform you are building ON, you can try variables CMAKE_HOST_SYSTEM_NAME and CMAKE_HOST_SYSTEM_VERSION
MESSAGE("CMAKE_HOST_SYSTEM_NAME ${CMAKE_HOST_SYSTEM_NAME}")
MESSAGE("CMAKE_HOST_SYSTEM_VERSION ${CMAKE_HOST_SYSTEM_VERSION}")
gives me the following output (on CMake version 3.19.2)
CMAKE_HOST_SYSTEM_NAME Windows
CMAKE_HOST_SYSTEM_VERSION 10.0.19044
There is also CMAKE_HOST_SYSTEM which inside toolchain file gave me blank, but after project call it gave "Windows-10.0.19044"
Solution 6:[6]
An improved version of KneLLs answer:
macro(get_WIN32_WINNT version)
if (WIN32 AND CMAKE_SYSTEM_VERSION)
set(ver ${CMAKE_SYSTEM_VERSION})
string(REGEX REPLACE "^([0-9])[.]([0-9]).*" "0\\10\\2" ver ${ver})
set(${version} "0x${ver}")
endif()
endmacro()
get_WIN32_WINNT(ver)
add_definitions(-D_WIN32_WINNT=${ver})
KneLLs version did no work in my case, because CMAKE_SYSTEM_VERSION was 6.3.9600 which resulted in ${ver}=0x060306090000
This version will fail for Windows 10 and later, though. One has to check if the first number is bigger than 9 and convert it to the correct hexadecimal value.
Solution 7:[7]
Probably the most concise version with Win10 support, requires CMake 3.13+
macro(get_win_hex outvar)
string(REGEX MATCH "^([0-9]+)\\.([0-9]+)" ${outvar} ${CMAKE_SYSTEM_VERSION})
math(EXPR ${outvar} "(${CMAKE_MATCH_1} << 8) + ${CMAKE_MATCH_2}" OUTPUT_FORMAT HEXADECIMAL)
endmacro()
if(WIN32)
get_win_hex(winver)
add_compile_definitions(_WIN32_WINNT=${winver})
endif()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | KneLL |
| Solution 2 | karlphillip |
| Solution 3 | |
| Solution 4 | |
| Solution 5 | |
| Solution 6 | Twonky |
| Solution 7 |
