-
Notifications
You must be signed in to change notification settings - Fork 5
/
FindVcvars.cmake
335 lines (281 loc) · 11.2 KB
/
FindVcvars.cmake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# 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}]"
)