Skip to content

Commit

Permalink
Dont rely on setuptools to find vcvars it doesnt work
Browse files Browse the repository at this point in the history
  • Loading branch information
kovidgoyal committed Nov 19, 2023
1 parent 93797b2 commit 9fe93b2
Showing 1 changed file with 137 additions and 47 deletions.
184 changes: 137 additions & 47 deletions .github/workflows/win-ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
# vim:fileencoding=utf-8
# License: Apache 2.0 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>

from __future__ import print_function

import ctypes.wintypes
import errno
import glob
import io
import os
import re
import shlex
import shutil
import subprocess
import sys
import tarfile
import time
from functools import lru_cache

ZLIB = "http://zlib.net/zlib-{}.tar.xz".format("1.3")
LIBXML2 = "https://gitlab.gnome.org/GNOME/libxml2/-/archive/v2.12.0/libxml2-v2.12.0.tar.gz"
Expand Down Expand Up @@ -81,11 +82,6 @@ def run(*args, env=None, cwd=None):
raise SystemExit(p.returncode)


def distutils_vcvars():
from setuptools._distutils.msvc9compiler import find_vcvarsall, get_build_version
return find_vcvarsall(get_build_version())


def remove_dups(variable):
old_list = variable.split(os.pathsep)
new_list = []
Expand All @@ -95,45 +91,6 @@ def remove_dups(variable):
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)'
result = {}
try:
popen = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True)
except FileNotFoundError as err:
raise SystemExit(f'Failed to execute: {cmd!r} with error: {err}')
try:
stdout, stderr = popen.communicate()
if popen.wait() != 0:
raise RuntimeError(stderr.decode("mbcs"))

stdout = stdout.decode("mbcs")
for line in stdout.splitlines():
if '=' not in line:
continue
line = line.strip()
key, value = line.split('=', 1)
key = key.lower()
if key == 'path':
if value.endswith(os.pathsep):
value = value[:-1]
value = remove_dups(value)
result[key] = value

finally:
popen.stdout.close()
popen.stderr.close()
return result


def query_vcvarsall():
vcvarsall = distutils_vcvars()
print('Querying vcvars:', vcvarsall)
return query_process('"%s" %s & set' % (vcvarsall, plat))


def download_and_extract(url):
raw = io.BytesIO(download_file(url))
with tarfile.open(fileobj=raw, mode='r:*') as f:
Expand Down Expand Up @@ -264,8 +221,141 @@ def lxml():
os.rename(package, os.path.join(SW, 'python', 'lib', 'site-packages', 'lxml'))


CSIDL_PROGRAM_FILES = 38
CSIDL_PROGRAM_FILESX86 = 42


@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


@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():
path = get_output(
find_vswhere(),
"-latest",
"-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():
base_path = get_output(
find_vswhere(),
"-latest",
"-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 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,
stderr=subprocess.PIPE)
try:
stdout, stderr = popen.communicate()
if popen.wait() != 0:
raise RuntimeError(stderr.decode("mbcs"))

stdout = stdout.decode("mbcs")
for line in stdout.splitlines():
if '=' not in line:
continue
line = line.strip()
key, value = line.split('=', 1)
key = key.lower()
if key == 'path':
if value.endswith(os.pathsep):
value = value[:-1]
value = remove_dups(value)
result[key] = value

finally:
popen.stdout.close()
popen.stderr.close()
return result


@lru_cache()
def query_vcvarsall(is64bit=True):
plat = 'amd64' if is64bit else 'amd64_x86'
vcvarsall = find_vcvarsall()
env = query_process(f'"{vcvarsall}" {plat} & set', is64bit)
pat = re.compile('vs(\d+)comntools', re.I)

comn_tools = {}

for k in env:
m = pat.match(k)
if m is not None:
comn_tools[k] = int(m.group(1))
comntools = sorted(comn_tools, key=comn_tools.__getitem__)[-1]


def g(k):
try:
return env[k]
except KeyError:
try:
return env[k.lower()]
except KeyError:
for k, v in env.items():
print(f'{k}={v}', file=sys.stderr)
raise

return {
k: g(k)
for k in (
'PATH LIB INCLUDE LIBPATH WINDOWSSDKDIR'
f' {comntools} PLATFORM'
' UCRTVERSION UNIVERSALCRTSDKDIR VCTOOLSVERSION WINDOWSSDKDIR'
' WINDOWSSDKVERSION WINDOWSSDKVERBINPATH WINDOWSSDKBINPATH'
' VISUALSTUDIOVERSION VSCMD_ARG_HOST_ARCH VSCMD_ARG_TGT_ARCH'
).split()
}


def install_deps():
run(PYTHON, '-m', 'pip', 'install', 'setuptools')
env = query_vcvarsall()
os.environ.update(env)
print(PYTHON)
Expand Down

0 comments on commit 9fe93b2

Please sign in to comment.