summaryrefslogtreecommitdiff
path: root/site_scons
diff options
context:
space:
mode:
authorAndrew Morrow <andrew.morrow@10gen.com>2019-12-16 23:21:42 +0000
committerevergreen <evergreen@mongodb.com>2019-12-16 23:21:42 +0000
commitda7f08a649e84846162a2a2276938cd61c90f017 (patch)
tree5d0d6c726b83d34a5e4375152ee48067fa30c749 /site_scons
parentbeba7157ee95d7118594fb8985fe965b329983a2 (diff)
downloadmongo-da7f08a649e84846162a2a2276938cd61c90f017.tar.gz
SERVER-44557 Set the default for MSVC_VERSION to VS2017
(cherry picked from commit 7c428b6fba15eb2058d52430b8d2c5f4df45d7ad)
Diffstat (limited to 'site_scons')
-rw-r--r--site_scons/site_tools/vcredist.py199
1 files changed, 199 insertions, 0 deletions
diff --git a/site_scons/site_tools/vcredist.py b/site_scons/site_tools/vcredist.py
new file mode 100644
index 00000000000..62e14010329
--- /dev/null
+++ b/site_scons/site_tools/vcredist.py
@@ -0,0 +1,199 @@
+# Copyright 2019 MongoDB Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import re
+import subprocess
+import winreg
+
+import SCons
+
+def exists(env):
+ result = 'msvc' in env['TOOLS']
+ return result
+
+# How to locate the Merge Modules path is described in:
+#
+# - VS2019: https://docs.microsoft.com/en-us/visualstudio/releases/2019/redistribution#visual-c-runtime-files
+# - VS2017: https://docs.microsoft.com/en-us/visualstudio/productinfo/2017-redistribution-vs#visual-c-runtime-files
+# - VS2015: https://docs.microsoft.com/en-us/visualstudio/productinfo/2015-redistribution-vs#visual-c-runtime
+#
+# However, please note that for VS2017 an VS2019, the documented paths are incorrect, per this
+# discussion:
+#
+# - https://developercommunity.visualstudio.com/content/problem/828060/what-are-the-correct-location-to-search-for-vc-crt.html
+#
+# This tool uses the currently undocumented but correct paths.
+
+# The keys are the values SCons accepts for TARGET_ARCH to name
+# different windows targets, the values are the tag that VS uses
+# for the associated redistributable for that platform.
+#
+# TODO: Expand this map as needed.
+target_arch_expansion_map = {
+ 'amd64' : 'x64',
+ 'arm' : None,
+ 'arm64' : 'arm64',
+ 'emt64' : 'x64',
+ 'i386' : 'x86',
+ 'x86' : 'x86',
+ 'x86_64' : 'x64',
+}
+
+def _get_programfiles():
+ result = os.getenv('ProgramFiles(x86)')
+ # When we run this under cygwin, the environment is broken, fall
+ # back to hard coded C:\Program Files (x86)
+ if result is None:
+ result = "C:\\Program Files (x86)"
+ if not os.path.isdir(result):
+ return None
+ return result
+
+def _get_merge_module_name_for_feature(env, feature):
+ version_components = env['MSVC_VERSION'].split('.')
+ return "Microsoft_VC{msvc_major}{msvc_minor}_{feature}_{target_arch}.msm".format(
+ msvc_major=version_components[0],
+ msvc_minor=version_components[1],
+ feature=feature,
+ target_arch=target_arch_expansion_map[env.subst('$TARGET_ARCH')]
+ )
+
+def generate(env):
+ if not exists(env):
+ return
+
+ env.Tool('msvc')
+
+ env.AddMethod(_get_merge_module_name_for_feature, "GetMergeModuleNameForFeature")
+
+ # Obtain the major and minor versions of the curently configured MSVC
+ # and ensure that we are using a VC 14 based toolchain.
+ #
+ # Please see
+ # https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering
+ # for details on the various version numbers in play for
+ # the Microsoft toolchain.
+ msvc_major, msvc_minor = env['MSVC_VERSION'].split('.')
+ if msvc_major != "14":
+ return
+
+ # We may or may not need to figure out the path to Program files,
+ # depending on the various paths we take throught this logic.
+ programfilesx86 = None
+
+ # TODO: Getting this path is a start, but we should later provide
+ # an abstraction over the names of the merge modules
+ # themselves. They seem to have the form
+ # Microsoft_VC{msvc_major}{msvc_minor}_{Feature}_{target_arch}.msm. It
+ # would be useful to provide an env.MergeModuleNameFor('feature')
+ # that consulted the values we have found here and used
+ # TARGET_ARCH (normalized somehow) to select the right one.
+ mergemodulepath = None
+
+ # On VS2015 the merge modules are in the program files directory,
+ # not under the VS install dir.
+ if msvc_minor == '0':
+
+ if not programfilesx86:
+ programfilesx86 = _get_programfiles()
+ if not programfilesx86:
+ return
+
+ mergemodulepath = os.path.join(programfilesx86, "Common Files", "Merge Modules")
+ if os.path.isdir(mergemodulepath):
+ env['MSVS']['VCREDISTMERGEMODULEPATH'] = mergemodulepath
+
+ if not 'VSINSTALLDIR' in env['MSVS']:
+
+ # Compute a VS version based on the VC version. VC 14.0 is VS 2015, VC
+ # 14.1 is VS 2017. Also compute the next theoretical version by
+ # incrementing the major version by 1. Then form a range from this
+ # that we can use as an argument to the -version flag to vswhere.
+ vs_version = int(msvc_major) + int(msvc_minor)
+ vs_version_next = vs_version + 1
+ vs_version_range = '[{vs_version}.0, {vs_version_next}.0)'.format(vs_version=vs_version, vs_version_next=vs_version_next)
+
+ if not programfilesx86:
+ programfilesx86 = _get_programfiles()
+ if not programfilesx86:
+ return
+
+ # Use vswhere (it has a fixed stable path) to query where Visual Studio is installed.
+ env['MSVS']['VSINSTALLDIR'] = subprocess.check_output([os.path.join(programfilesx86, "Microsoft Visual Studio", "Installer", "vswhere.exe"), "-version", vs_version_range, "-property", "installationPath", "-nologo"]).decode('utf-8').strip()
+
+ vsinstall_dir = env['MSVS']['VSINSTALLDIR']
+
+ # Combine and set the full merge module path
+ redist_root = os.path.join(vsinstall_dir, "VC", "Redist", "MSVC")
+ if not os.path.isdir(redist_root):
+ return
+ env['MSVS']['VCREDISTROOT'] = redist_root
+
+ # Check the registry key that has the runtime lib version
+ try:
+ # TOOO: This x64 needs to be abstracted away. Is it the host
+ # arch, or the target arch? My guess is host.
+ vsruntime_key_name = "SOFTWARE\\Microsoft\\VisualStudio\\{msvc_major}.0\\VC\\Runtimes\\x64".format(msvc_major=msvc_major)
+ vsruntime_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, vsruntime_key_name)
+ vslib_version, vslib_version_type = winreg.QueryValueEx(vsruntime_key, "Version")
+ except WindowsError:
+ return
+
+ # Fallback to directory search if we don't find the expected version
+ redist_path = os.path.join(redist_root, re.match("v(\d+\.\d+\.\d+)\.\d+", vslib_version).group(1))
+ if not os.path.isdir(redist_path):
+ redist_path = None
+ dirs = os.listdir(redist_root)
+ dirs.sort()
+ for dir in reversed(dirs):
+ candidate = os.path.join(redist_root, dir)
+ if os.path.isdir(candidate):
+ redist_path = candidate
+ break
+ else:
+ return
+ env['MSVS']['VCREDISTPATH'] = redist_path
+
+ if mergemodulepath is None and msvc_minor != "0":
+ mergemodulepath = os.path.join(redist_path, "MergeModules")
+ if os.path.isdir(mergemodulepath):
+ env['MSVS']['VCREDISTMERGEMODULEPATH'] = mergemodulepath
+
+ # Keep these in preference order. The way with the {} in between
+ # the dots appears to be the more modern form, but we select the
+ # older one when available to minimize disruption to existing
+ # automation that expects the redist executable embedded in our
+ # packages to have this shape. Some architectures, like arm64,
+ # don't appear to be provided under that syntax though, so we
+ # include the newer form for that purpose. If Microsoft ever stops
+ # providing the old form, we will automatically roll forward to
+ # the new form.
+ vcredist_search_template_sequence = [
+ "vcredist_{}.exe",
+ "vc_redist.{}.exe",
+ ]
+
+ expansion = target_arch_expansion_map.get(env.subst('$TARGET_ARCH'), None)
+ if not expansion:
+ return
+
+ vcredist_candidates = [c.format(expansion) for c in vcredist_search_template_sequence]
+ for candidate in vcredist_candidates:
+ candidate = os.path.join(redist_path, candidate)
+ if os.path.isfile(candidate):
+ break
+ else:
+ return
+ env['MSVS']['VCREDISTEXE'] = candidate