Always build on Windows with Visual Studio 2019

This commit is contained in:
Kovid Goyal 2021-03-18 21:22:31 +05:30
parent 3735585739
commit 75586d8eb0
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 120 additions and 59 deletions

View File

@ -166,7 +166,7 @@ def read_extensions():
def init_env():
from setup.build_environment import msvc, is64bit, win_inc, win_lib, NMAKE
from setup.build_environment import win_ld, is64bit, win_inc, win_lib, NMAKE, win_cc
from distutils import sysconfig
linker = None
if isunix:
@ -211,7 +211,7 @@ def init_env():
cflags.append('-I'+sysconfig.get_python_inc())
if iswindows:
cc = cxx = msvc.cc
cc = cxx = win_cc
cflags = '/c /nologo /MD /W3 /EHsc /utf-8 /DNDEBUG'.split()
ldflags = '/DLL /nologo /INCREMENTAL:NO /NODEFAULTLIB:libcmt.lib'.split()
# cflags = '/c /nologo /Ox /MD /W3 /EHsc /Zi'.split()
@ -226,7 +226,7 @@ def init_env():
ldflags.append('/LIBPATH:'+p)
cflags.append('-I%s'%sysconfig.get_python_inc())
ldflags.append('/LIBPATH:'+os.path.join(sysconfig.PREFIX, 'libs'))
linker = msvc.linker
linker = win_ld
return namedtuple('Environment', 'cc cxx cflags ldflags linker make')(
cc=cc, cxx=cxx, cflags=cflags, ldflags=ldflags, linker=linker, make=NMAKE if iswindows else 'make')

View File

@ -6,22 +6,22 @@ __license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import os, subprocess, re
import os, subprocess, re, shutil
from distutils.spawn import find_executable
from setup import ismacos, iswindows, is64bit, islinux, ishaiku
is64bit
NMAKE = RC = msvc = MT = win_inc = win_lib = None
NMAKE = RC = msvc = MT = win_inc = win_lib = win_cc = win_ld = None
if iswindows:
from distutils import msvc9compiler
msvc = msvc9compiler.MSVCCompiler()
msvc.initialize()
NMAKE = msvc.find_exe('nmake.exe')
RC = msvc.find_exe('rc.exe')
MT = msvc.find_exe('mt.exe')
win_inc = [x for x in os.environ['include'].split(';') if x]
win_lib = [x for x in os.environ['lib'].split(';') if x]
from setup.vcvars import query_vcvarsall
env = query_vcvarsall(is64bit)
NMAKE = shutil.which('nmake.exe', path=env['PATH'])
RC = shutil.which('rc.exe', path=env['PATH'])
MT = shutil.which('mt.exe', path=env['PATH'])
win_cc = shutil.which('cl.exe', path=env['PATH'])
win_ld = shutil.which('link.exe', path=env['PATH'])
win_inc = [x for x in env['INCLUDE'].split(';') if x]
win_lib = [x for x in env['LIB'].split(';') if x]
QMAKE = 'qmake'
for x in ('qmake-qt5', 'qt5-qmake', 'qmake'):

View File

@ -1,18 +1,89 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
import ctypes.wintypes
import os
import re
import subprocess
import sys
from functools import lru_cache
from glob import glob
# See the table at https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering
python_msc_version = int(re.search(r'\[MSC v\.(\d+) ', sys.version).group(1))
if python_msc_version < 1920:
raise SystemExit(f'Python MSC version {python_msc_version} too old, needs Visual studio 2019')
if python_msc_version > 1929:
raise SystemExit(f'Python MSC version {python_msc_version} too new, needs Visual studio 2019')
# The values are for VisualStudio 2019 (python_msc_version 192_)
VS_VERSION = '16.0'
COMN_TOOLS_VERSION = '160'
CSIDL_PROGRAM_FILES = 38
CSIDL_PROGRAM_FILESX86 = 42
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
@lru_cache()
def get_program_files_location(which=CSIDL_PROGRAM_FILESX86):
SHGFP_TYPE_CURRENT = 0
buf = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH)
ctypes.windll.shell32.SHGetFolderPathW(
0, which, 0, SHGFP_TYPE_CURRENT, buf)
return buf.value
import os, sys, subprocess
plat = 'amd64' if sys.maxsize > 2**32 else 'x86'
@lru_cache()
def find_vswhere():
for which in (CSIDL_PROGRAM_FILESX86, CSIDL_PROGRAM_FILES):
root = get_program_files_location(which)
vswhere = os.path.join(root, "Microsoft Visual Studio", "Installer",
"vswhere.exe")
if os.path.exists(vswhere):
return vswhere
raise SystemExit('Could not find vswhere.exe')
def get_output(*cmd):
return subprocess.check_output(cmd, encoding='mbcs', errors='strict')
@lru_cache()
def find_visual_studio(version=VS_VERSION):
path = get_output(
find_vswhere(),
"-version", version,
"-requires",
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
"-property",
"installationPath",
"-products",
"*"
).strip()
return os.path.join(path, "VC", "Auxiliary", "Build")
@lru_cache()
def find_msbuild(version=VS_VERSION):
base_path = get_output(
find_vswhere(),
"-version", version,
"-requires", "Microsoft.Component.MSBuild",
"-property", 'installationPath'
).strip()
return glob(os.path.join(
base_path, 'MSBuild', '*', 'Bin', 'MSBuild.exe'))[0]
def find_vcvarsall():
productdir = find_visual_studio()
vcvarsall = os.path.join(productdir, "vcvarsall.bat")
if os.path.isfile(vcvarsall):
return vcvarsall
raise SystemExit("Unable to find vcvarsall.bat in productdir: " +
productdir)
def distutils_vcvars():
from distutils.msvc9compiler import find_vcvarsall, get_build_version
return find_vcvarsall(get_build_version())
def remove_dups(variable):
old_list = variable.split(os.pathsep)
@ -22,11 +93,13 @@ def remove_dups(variable):
new_list.append(i)
return os.pathsep.join(new_list)
def query_process(cmd):
if plat == 'amd64' and 'PROGRAMFILES(x86)' not in os.environ:
os.environ['PROGRAMFILES(x86)'] = os.environ['PROGRAMFILES'] + ' (x86)'
def query_process(cmd, is64bit):
if is64bit and 'PROGRAMFILES(x86)' not in os.environ:
os.environ['PROGRAMFILES(x86)'] = get_program_files_location()
result = {}
popen = subprocess.Popen(cmd, stdout=subprocess.PIPE,
popen = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
try:
stdout, stderr = popen.communicate()
@ -51,38 +124,26 @@ def query_process(cmd):
popen.stderr.close()
return result
def query_vcvarsall():
vcvarsall = distutils_vcvars()
return query_process('"%s" %s & set' % (vcvarsall, plat))
env = query_vcvarsall()
paths = env['path'].split(';')
lib = env['lib']
include = env['include']
libpath = env['libpath']
sdkdir = env['windowssdkdir']
@lru_cache()
def query_vcvarsall(is64bit=True):
plat = 'amd64' if is64bit else 'amd64_x86'
vcvarsall = find_vcvarsall()
env = query_process('"%s" %s & set' % (vcvarsall, plat), is64bit)
def unix(paths):
up = []
for p in paths:
prefix, p = p.replace(os.sep, '/').partition('/')[0::2]
up.append('/cygdrive/%s/%s'%(prefix[0].lower(), p))
return ':'.join(up)
raw = '''\
#!/bin/sh
export PATH="%s:$PATH"
export LIB="%s"
export INCLUDE="%s"
export LIBPATH="%s"
export WindowsSdkDir="%s"
'''%(unix(paths), lib.replace('\\', r'\\'), include.replace('\\', r'\\'), libpath.replace('\\', r'\\'), sdkdir.replace('\\', r'\\'))
print(raw.encode('utf-8'))
def g(k):
try:
return env[k]
except KeyError:
return env[k.lower()]
return {
k: g(k)
for k in (
'PATH LIB INCLUDE LIBPATH WINDOWSSDKDIR'
f' VS{COMN_TOOLS_VERSION}COMNTOOLS PLATFORM'
' UCRTVERSION UNIVERSALCRTSDKDIR VCTOOLSVERSION WINDOWSSDKDIR'
' WINDOWSSDKVERSION WINDOWSSDKVERBINPATH WINDOWSSDKBINPATH'
' VISUALSTUDIOVERSION VSCMD_ARG_HOST_ARCH VSCMD_ARG_TGT_ARCH'
).split()
}