Last active
November 30, 2022 23:49
-
-
Save WardBenjamin/3ff3398bf8e35ed4034d298ed32793d6 to your computer and use it in GitHub Desktop.
Windows MSCV CMake Toolchain
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
# file Copyright.txt or https://cmake.org/licensing for details. | |
#[=======================================================================[.rst: | |
FindVcvars | |
---------- | |
Finds a "vcvars" batch script. | |
The module can be used when configuring a project or when running | |
in cmake -P script mode. | |
These variables can be used to choose which "vcvars" batch script is looked up. | |
.. variable:: Vcvars_MSVC_ARCH | |
Possible values are `32` or `64` | |
If not explicitly set in the calling scope, the variable is initialized | |
based on the value of :variable:`CMAKE_SIZEOF_VOID_P` in configuration mode, and | |
to 64 in script mode. | |
.. variable:: Vcvars_MSVC_VERSION | |
Possible values corresponds to :variable:`MSVC_VERSION`. | |
If not explicitly set in the calling scope, :variable:`Vcvars_MSVC_VERSION` is | |
initialized using :variable:`MSVC_VERSION` variable if it is defined, otherwise | |
the variable :variable:`Vcvars_MSVC_VERSION` is initialized based on the most | |
recent version of Visual Studio installed on the system. | |
This will define the following variables: | |
.. variable:: Vcvars_BATCH_FILE | |
Path to ``vcvars32.bat``, ``vcvarsamd64.bat`` or ``vcvars64.bat``. | |
.. variable:: Vcvars_LAUNCHER | |
Path to a generated wrapper script allowing to execute program after | |
setting environment defined by `Vcvars_BATCH_FILE`. | |
It can be used within :module:`ExternalProject` steps | |
specifying command like this:: | |
set(cmd_wrapper) | |
if(MSVC) | |
find_package(Vcvars REQUIRED) | |
set(cmd_wrapper ${Vcvars_LAUNCHER}) | |
endif() | |
ExternalProject_Add(AwesomeProject | |
[...] | |
BUILD_COMMAND ${cmd_wrapper} <command> arg1 arg2 [...] | |
[...] | |
) | |
This module also defines the following functions | |
.. command:: Vcvars_GetVisualStudioPaths | |
The ``Vcvars_GetVisualStudioPaths()`` function returns a list of all | |
possible Visual Studio registry paths associated with a given ``<msvc_version>`` | |
and ``<msvc_arch>``:: | |
Vcvars_GetVisualStudioPaths(<msvc_version> <msvc_arch> <output_var>) | |
The options are: | |
``<msvc_version>`` | |
Specify the Visual Studio compiler version. See :variable:`MSVC_VERSION` | |
for possible values. | |
``<msvc_arch>`` | |
Specify the Visual Studio architecture. Possible values are `32` or `64`. | |
``<output_var>`` | |
The name of the variable to be set with the list of registry paths. | |
.. command:: Vcvars_ConvertMsvcVersionToVsVersion | |
The ``Vcvars_ConvertMsvcVersionToVsVersion()`` function converts a | |
:variable:`MSVC_VERSION` of the form ``NNNN`` to a Visual Studio version | |
of the form ``XX.Y`:: | |
Vcvars_ConvertMsvcVersionToVsVersion(<msvc_version> <output_var>) | |
The options are: | |
``<msvc_version>`` | |
Specify the Visual Studio compiler version. See :variable:`MSVC_VERSION` | |
for possible values. | |
``<output_var>`` | |
The name of the variable to be set with the Visual Studio version. | |
#]=======================================================================] | |
cmake_minimum_required(VERSION 3.5) | |
# Global variables used only in this script (unset at the end) | |
set(_Vcvars_MSVC_ARCH_REGEX "^(32|64)$") | |
set(_Vcvars_MSVC_VERSION_REGEX "^[0-9][0-9][0-9][0-9]$") | |
set(_Vcvars_SUPPORTED_MSVC_VERSIONS | |
1939 1938 1937 1936 1935 1934 1933 1932 1931 1930 # VS 2022 | |
1929 1928 1927 1926 1925 1924 1923 1922 1921 1920 # VS 2019 | |
1916 1915 1914 1913 1912 1911 1910 # VS 2017 | |
1900 # VS 2015 | |
1800 # VS 2013 | |
1700 # VS 2012 | |
1600 # VS 2010 | |
1500 # VS 2008 | |
1400 # VS 2005 | |
) | |
function(_vcvars_message) | |
if(NOT Vcvars_FIND_QUIETLY) | |
message(${ARGN}) | |
endif() | |
endfunction() | |
function(Vcvars_ConvertMsvcVersionToVsVersion msvc_version output_var) | |
if(NOT msvc_version MATCHES ${_Vcvars_MSVC_VERSION_REGEX}) | |
message(FATAL_ERROR "msvc_version is expected to match `${_Vcvars_MSVC_VERSION_REGEX}`") | |
endif() | |
# See https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering | |
if((msvc_version GREATER_EQUAL 1930) AND (msvc_version LESS 1940)) # VS 2022 | |
set(vs_version "17") | |
elseif((msvc_version GREATER_EQUAL 1920) AND (msvc_version LESS 1930)) # VS 2019 | |
set(vs_version "16") | |
elseif((msvc_version GREATER_EQUAL 1910) AND (msvc_version LESS 1920)) # VS 2017 | |
set(vs_version "15") | |
elseif(msvc_version EQUAL 1900) # VS 2015 | |
set(vs_version "14.0") | |
elseif(msvc_version EQUAL 1800) # VS 2013 | |
set(vs_version "12.0") | |
elseif(msvc_version EQUAL 1700) # VS 2012 | |
set(vs_version "11.0") | |
elseif(msvc_version EQUAL 1600) # VS 2010 | |
set(vs_version "10.0") | |
elseif(msvc_version EQUAL 1500) # VS 2008 | |
set(vs_version "9.0") | |
elseif(msvc_version EQUAL 1400) # VS 2005 | |
set(vs_version "8.0") | |
elseif(msvc_version EQUAL 1310) # VS 2003 | |
set(vs_version "7.1") | |
elseif(msvc_version EQUAL 1300) # VS 2002 | |
set(vs_version "7.0") | |
elseif(msvc_version EQUAL 1200) # VS 6.0 | |
set(vs_version "6.0") | |
else() | |
message(FATAL_ERROR "failed to convert msvc_version [${msvc_version}]. It is not a known version number.") | |
endif() | |
set(${output_var} ${vs_version} PARENT_SCOPE) | |
endfunction() | |
function(Vcvars_GetVisualStudioPaths msvc_version msvc_arch output_var) | |
if(NOT msvc_version MATCHES ${_Vcvars_MSVC_VERSION_REGEX}) | |
message(FATAL_ERROR "msvc_version is expected to match `${_Vcvars_MSVC_VERSION_REGEX}`") | |
endif() | |
if(NOT msvc_arch MATCHES ${_Vcvars_MSVC_ARCH_REGEX}) | |
message(FATAL_ERROR "msvc_arch argument is expected to match '${_Vcvars_MSVC_ARCH_REGEX}'") | |
endif() | |
Vcvars_ConvertMsvcVersionToVsVersion(${msvc_version} vs_version) | |
set(_vs_installer_paths "") | |
set(_vs_registry_paths "") | |
if(vs_version VERSION_GREATER_EQUAL "15.0") | |
# Query the VS Installer tool for locations of VS 2017 and above. | |
string(REGEX REPLACE "^([0-9]+)\.[0-9]+$" "\\1" vs_installer_version ${vs_version}) | |
cmake_host_system_information(RESULT _vs_dir QUERY VS_${vs_installer_version}_DIR) | |
if(_vs_dir) | |
list(APPEND _vs_installer_paths "${_vs_dir}/VC/Auxiliary/Build") | |
endif() | |
else() | |
# Registry keys for locations of VS 2015 and below | |
set(_hkeys | |
"HKEY_USERS" | |
"HKEY_CURRENT_USER" | |
"HKEY_LOCAL_MACHINE" | |
"HKEY_CLASSES_ROOT" | |
) | |
set(_suffixes | |
"" | |
"_Config" | |
) | |
set(_arch_path "bin/amd64") | |
if(msvc_arch STREQUAL "32") | |
set(_arch_path "bin") | |
endif() | |
set(_vs_registry_paths) | |
foreach(_hkey IN LISTS _hkeys) | |
foreach(_suffix IN LISTS _suffixes) | |
set(_vc "VC") | |
if(_vs_version STREQUAL "6.0") | |
set(_vc "Microsoft Visual C++") | |
endif() | |
list(APPEND _vs_registry_paths | |
"[${_hkey}\\SOFTWARE\\Microsoft\\VisualStudio\\${vs_version}${_suffix}\\Setup\\${_vc};ProductDir]/${_arch_path}" | |
) | |
endforeach() | |
endforeach() | |
endif() | |
set(_vs_installer_paths ${_vs_installer_paths} ${_vs_registry_paths}) | |
if(_vs_installer_paths STREQUAL "") | |
set(_vs_installer_paths "${output_var}-${msvc_version}-${msvc_arch}-NOTFOUND") | |
endif() | |
set(${output_var} ${_vs_installer_paths} PARENT_SCOPE) | |
endfunction() | |
# default | |
if(NOT DEFINED Vcvars_MSVC_ARCH) | |
if(NOT DEFINED CMAKE_SIZEOF_VOID_P) | |
set(Vcvars_MSVC_ARCH "64") | |
_vcvars_message(STATUS "Setting Vcvars_MSVC_ARCH to '${Vcvars_MSVC_ARCH}' as CMAKE_SIZEOF_VOID_P was none") | |
else() | |
if("${CMAKE_SIZEOF_VOID_P}" EQUAL 4) | |
set(Vcvars_MSVC_ARCH "32") | |
elseif("${CMAKE_SIZEOF_VOID_P}" EQUAL 8) | |
set(Vcvars_MSVC_ARCH "64") | |
else() | |
message(FATAL_ERROR "CMAKE_SIZEOF_VOID_P [${CMAKE_SIZEOF_VOID_P}] is expected to be either 4 or 8") | |
endif() | |
# Display message only once in config mode | |
if(NOT DEFINED Vcvars_BATCH_FILE) | |
_vcvars_message(STATUS "Setting Vcvars_MSVC_ARCH to '${Vcvars_MSVC_ARCH}' as CMAKE_SIZEOF_VOID_P was `${CMAKE_SIZEOF_VOID_P}`") | |
endif() | |
endif() | |
endif() | |
if(NOT DEFINED Vcvars_MSVC_VERSION) | |
if(DEFINED MSVC_VERSION) | |
set(Vcvars_MSVC_VERSION ${MSVC_VERSION}) | |
# Display message only once in config mode | |
if(NOT DEFINED Vcvars_BATCH_FILE) | |
_vcvars_message(STATUS "Setting Vcvars_MSVC_VERSION to '${Vcvars_MSVC_VERSION}' as MSVC_VERSION was `${MSVC_VERSION}`") | |
endif() | |
endif() | |
endif() | |
if(NOT DEFINED Vcvars_BATCH_FILE) | |
set(Vcvars_BATCH_FILE "Vcvars_BATCH_FILE-NOTFOUND") | |
endif() | |
if(NOT DEFINED Vcvars_LAUNCHER) | |
set(Vcvars_LAUNCHER "Vcvars_LAUNCHER-NOTFOUND") | |
endif() | |
# check Vcvars_MSVC_ARCH is properly set | |
if(NOT Vcvars_MSVC_ARCH MATCHES ${_Vcvars_MSVC_ARCH_REGEX}) | |
message(FATAL_ERROR "Vcvars_MSVC_ARCH [${Vcvars_MSVC_ARCH}] is expected to match `${_Vcvars_MSVC_ARCH_REGEX}`") | |
endif() | |
# which vcvars script ? | |
if(Vcvars_MSVC_ARCH STREQUAL "64") | |
set(_Vcvars_SCRIPTS vcvarsamd64.bat vcvars64.bat) | |
else() | |
set(_Vcvars_SCRIPTS vcvars32.bat) | |
endif() | |
# set Vcvars_BATCH_FILE | |
if(NOT DEFINED Vcvars_MSVC_VERSION) | |
# auto-discover Vcvars_MSVC_VERSION value | |
_vcvars_message(STATUS "Setting Vcvars_MSVC_VERSION") | |
foreach(_candidate_msvc_version IN LISTS _Vcvars_SUPPORTED_MSVC_VERSIONS) | |
Vcvars_GetVisualStudioPaths(${_candidate_msvc_version} "${Vcvars_MSVC_ARCH}" _paths) | |
Vcvars_ConvertMsvcVersionToVsVersion(${_candidate_msvc_version} _candidate_vs_version) | |
set(_msg " Visual Studio ${_candidate_vs_version} (${_candidate_msvc_version})") | |
_vcvars_message(STATUS "${_msg}") | |
find_program(Vcvars_BATCH_FILE NAMES ${_Vcvars_SCRIPTS} | |
DOC "Visual Studio ${_candidate_vs_version} ${_Vcvars_SCRIPTS}" | |
PATHS ${_paths} | |
) | |
if(Vcvars_BATCH_FILE) | |
_vcvars_message(STATUS "${_msg} - found") | |
set(Vcvars_MSVC_VERSION ${_candidate_msvc_version}) | |
_vcvars_message(STATUS "Setting Vcvars_MSVC_VERSION to '${Vcvars_MSVC_VERSION}' as it was the newest Visual Studio installed providing vcvars scripts") | |
break() | |
else() | |
_vcvars_message(STATUS "${_msg} - not found") | |
endif() | |
endforeach() | |
unset(_candidate_msvc_version) | |
unset(_candidate_vs_version) | |
unset(_paths) | |
else() | |
# use provided Vcvars_MSVC_VERSION value | |
if(NOT Vcvars_MSVC_VERSION MATCHES ${_Vcvars_MSVC_VERSION_REGEX}) | |
message(FATAL_ERROR "Vcvars_MSVC_VERSION [${Vcvars_MSVC_VERSION}] is expected to match `${_Vcvars_MSVC_VERSION_REGEX}`") | |
endif() | |
Vcvars_GetVisualStudioPaths(${Vcvars_MSVC_VERSION} "${Vcvars_MSVC_ARCH}" _paths) | |
Vcvars_ConvertMsvcVersionToVsVersion(${Vcvars_MSVC_VERSION} _vs_version) | |
find_program(Vcvars_BATCH_FILE NAMES ${_Vcvars_SCRIPTS} | |
DOC "Visual Studio ${_vs_version} ${_Vcvars_SCRIPTS}" | |
PATHS ${_paths} | |
) | |
unset(_paths) | |
unset(_vs_version) | |
endif() | |
# configure wrapper script | |
set(Vcvars_LAUNCHER) | |
if(Vcvars_BATCH_FILE) | |
set(_in "${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/Vcvars_wrapper.bat.in") | |
get_filename_component(_basename ${Vcvars_BATCH_FILE} NAME_WE) | |
set(_out "${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${_basename}_wrapper.bat") | |
file(WRITE ${_in} "call \"@Vcvars_BATCH_FILE@\" | |
%* | |
") | |
configure_file(${_in} ${_out} @ONLY) | |
set(Vcvars_LAUNCHER ${_out}) | |
unset(_in) | |
unset(_out) | |
endif() | |
# cleanup | |
unset(_Vcvars_SCRIPTS) | |
# outputs | |
include(FindPackageHandleStandardArgs) | |
find_package_handle_standard_args(Vcvars | |
FOUND_VAR Vcvars_FOUND | |
REQUIRED_VARS | |
Vcvars_BATCH_FILE | |
Vcvars_LAUNCHER | |
Vcvars_MSVC_VERSION | |
Vcvars_MSVC_ARCH | |
FAIL_MESSAGE | |
"Failed to find vcvars scripts for Vcvars_MSVC_VERSION [${Vcvars_MSVC_VERSION}] and Vcvars_MSVC_ARCH [${Vcvars_MSVC_ARCH}]" | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Partially based on https://discourse.cmake.org/t/is-there-a-way-to-integrate-the-call-to-vcvarsall-bat-into-the-cmakepresets-json-file/3100/15 | |
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") | |
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindVcvars") | |
find_package(Vcvars) | |
if (NOT ${Vcvars_FOUND}) | |
message(FATAL_ERROR "[windows-msvc.toolchain.cmake] Looks like no Visual Studio installed") | |
endif() | |
# got vcvars launcher ! | |
set(cmd_wrapper ${Vcvars_LAUNCHER}) | |
execute_process(COMMAND ${cmd_wrapper} set OUTPUT_VARIABLE env_dump OUTPUT_STRIP_TRAILING_WHITESPACE) | |
#1. Escape troublesome characters before filtering | |
string(REPLACE ";" "__semicolon__" env_dump "${env_dump}") | |
string(REPLACE "\\" "__backslash__" env_dump "${env_dump}") | |
string(REPLACE "\"" "__doublequote__" env_dump "${env_dump}") | |
string(REGEX REPLACE "[\r\n]+" ";" env_dump "${env_dump}") # Condense multi-line strings onto a single line | |
list(FILTER env_dump INCLUDE REGEX ".+\=.+") # Keep only lines in the format xx=yy | |
# Format and inject all of the environment variables | |
foreach(key_value ${env_dump}) | |
string(REPLACE "=" ";" key_value_as_list ${key_value}) | |
list(GET key_value_as_list 0 key) | |
list(GET key_value_as_list 1 value) | |
# Put the characters back the way they belong | |
string(REPLACE "__semicolon__" "\;" key "${key}") | |
string(REPLACE "__backslash__" "\\" key "${key}") | |
string(REPLACE "__doublequote__" "\"" key "${key}") | |
string(REPLACE "__semicolon__" ";" value "${value}") | |
string(REPLACE "__backslash__" "\\" value "${value}") | |
string(REPLACE "__doublequote__" "\"" value "${value}") | |
set(ENV{${key}} "${value}") | |
# message("${key}: ${value}") | |
endforeach() | |
# Adjust cmake vars to find MSVC headers & resolve libs path | |
set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES $ENV{INCLUDE}) | |
link_directories($ENV{LIB}) | |
message(STATUS "[windows-msvc.toolchain.cmake] Environment dumping finished") | |
set(CMAKE_C_COMPILER "cl.exe") | |
set(CMAKE_CXX_COMPILER "cl.exe") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment