#!/usr/bin/env python3 # # This script generates JSON files that are easier-to-parse equivalents of # the SetEnv batch script provided by Visual Studio, which sets necessary # environment variables. These JSON files are used by the Chromium build # system to obtain specific paths to Microsoft SDK resources. # # The GenerateSetEnvCmd() function is lightly modified from # https://chromium.googlesource.com/chromium/tools/depot_tools.git/+/5eef793337de052b29dc5ec6eb22676938dadbe4/win_toolchain/package_from_installed.py # # original code from # https://github.com/iskunk/ungoogled-chromium-windows/blob/feature/win_cross/cross-build/gen-setenv.py import collections import glob import json import os import sys dir = sys.argv[1] _vc_tools = glob.glob('VC/Tools/MSVC/*', root_dir=dir)[0] _win_version = glob.glob('[1-9]*', root_dir=f'{dir}/Windows Kits/10/Lib')[0] def GenerateSetEnvCmd(target_dir): """Generate a batch file that gyp expects to exist to set up the compiler environment. This is normally generated by a full install of the SDK, but we do it here manually since we do not do a full install.""" vc_tools_parts = _vc_tools.split('/') # All these paths are relative to the root of the toolchain package. include_dirs = [ ['Windows Kits', '10', 'Include', _win_version, 'um'], ['Windows Kits', '10', 'Include', _win_version, 'shared'], ['Windows Kits', '10', 'Include', _win_version, 'winrt'], ] include_dirs.append(['Windows Kits', '10', 'Include', _win_version, 'ucrt']) include_dirs.extend([ vc_tools_parts + ['include'], vc_tools_parts + ['atlmfc', 'include'], ]) libpath_dirs = [ vc_tools_parts + ['lib', 'x86', 'store', 'references'], ['Windows Kits', '10', 'UnionMetadata', _win_version], ] # Common to x86, x64, and arm64 env = collections.OrderedDict([ # Yuck: These have a trailing \ character. No good way to represent this # in an OS-independent way. ('VSINSTALLDIR', [['.\\']]), ('VCINSTALLDIR', [['VC\\']]), ('INCLUDE', include_dirs), ('LIBPATH', libpath_dirs), ]) # x86. Always use amd64_x86 cross, not x86 on x86. env['VCToolsInstallDir'] = [vc_tools_parts[:]] # Yuck: This one ends in a path separator as well. env['VCToolsInstallDir'][0][-1] += os.path.sep env_x86 = collections.OrderedDict([ ( 'PATH', [ ['Windows Kits', '10', 'bin', _win_version, 'x64'], vc_tools_parts + ['bin', 'HostX64', 'x86'], vc_tools_parts + ['bin', 'HostX64', 'x64'], # Needed for mspdb1x0.dll. ]), ('LIB', [ vc_tools_parts + ['lib', 'x86'], ['Windows Kits', '10', 'Lib', _win_version, 'um', 'x86'], ['Windows Kits', '10', 'Lib', _win_version, 'ucrt', 'x86'], vc_tools_parts + ['atlmfc', 'lib', 'x86'], ]), ]) # x64. env_x64 = collections.OrderedDict([ ('PATH', [ ['Windows Kits', '10', 'bin', _win_version, 'x64'], vc_tools_parts + ['bin', 'HostX64', 'x64'], ]), ('LIB', [ vc_tools_parts + ['lib', 'x64'], ['Windows Kits', '10', 'Lib', _win_version, 'um', 'x64'], ['Windows Kits', '10', 'Lib', _win_version, 'ucrt', 'x64'], vc_tools_parts + ['atlmfc', 'lib', 'x64'], ]), ]) # arm64. env_arm64 = collections.OrderedDict([ ('PATH', [ ['Windows Kits', '10', 'bin', _win_version, 'x64'], vc_tools_parts + ['bin', 'HostX64', 'arm64'], vc_tools_parts + ['bin', 'HostX64', 'x64'], ]), ('LIB', [ vc_tools_parts + ['lib', 'arm64'], ['Windows Kits', '10', 'Lib', _win_version, 'um', 'arm64'], ['Windows Kits', '10', 'Lib', _win_version, 'ucrt', 'arm64'], vc_tools_parts + ['atlmfc', 'lib', 'arm64'], ]), ]) def BatDirs(dirs): return ';'.join(['%cd%\\' + os.path.join(*d) for d in dirs]) set_env_prefix = os.path.join(target_dir, r'Windows Kits/10/bin/SetEnv') with open(set_env_prefix + '.cmd', 'w') as f: # The prologue changes the current directory to the root of the # toolchain package, so that path entries can be set up without needing # ..\..\..\ components. f.write('@echo off\n' ':: Generated by win_toolchain\\package_from_installed.py.\n' 'pushd %~dp0..\\..\\..\n') for var, dirs in env.items(): f.write('set %s=%s\n' % (var, BatDirs(dirs))) f.write('if "%1"=="/x64" goto x64\n') f.write('if "%1"=="/arm64" goto arm64\n') for var, dirs in env_x86.items(): f.write('set %s=%s%s\n' % (var, BatDirs(dirs), ';%PATH%' if var == 'PATH' else '')) f.write('goto :END\n') f.write(':x64\n') for var, dirs in env_x64.items(): f.write('set %s=%s%s\n' % (var, BatDirs(dirs), ';%PATH%' if var == 'PATH' else '')) f.write('goto :END\n') f.write(':arm64\n') for var, dirs in env_arm64.items(): f.write('set %s=%s%s\n' % (var, BatDirs(dirs), ';%PATH%' if var == 'PATH' else '')) f.write('goto :END\n') f.write(':END\n') # Restore the original directory. f.write('popd\n') with open(set_env_prefix + '.x86.json', 'wt', newline='') as f: assert not set(env.keys()) & set(env_x86.keys()), 'dupe keys' json.dump( { 'env': collections.OrderedDict( list(env.items()) + list(env_x86.items())) }, f, indent=2) with open(set_env_prefix + '.x64.json', 'wt', newline='') as f: assert not set(env.keys()) & set(env_x64.keys()), 'dupe keys' json.dump( { 'env': collections.OrderedDict( list(env.items()) + list(env_x64.items())) }, f, indent=2) with open(set_env_prefix + '.arm64.json', 'wt', newline='') as f: assert not set(env.keys()) & set(env_arm64.keys()), 'dupe keys' json.dump( { 'env': collections.OrderedDict( list(env.items()) + list(env_arm64.items())) }, f, indent=2) GenerateSetEnvCmd(dir) # EOF