Skip to content

Commit

Permalink
win: Add support for cross-compiling ARM64
Browse files Browse the repository at this point in the history
Adds ARM64 targets to generated .sln/.vcxproj files for cross-compiling
node modules to Windows on Arm, 64-bit. To use, run
`set npm_config_arch=arm64` on the command prompt before `npm install`.

PR-URL: nodejs#1678
  • Loading branch information
kaadam committed Feb 25, 2019
1 parent bb8b294 commit 2e98492
Show file tree
Hide file tree
Showing 7 changed files with 31 additions and 9 deletions.
3 changes: 2 additions & 1 deletion gyp/pylib/gyp/MSVSNew.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@ def __init__(self, path, version, entries=None, variants=None,
self.variants = variants[:]
else:
# Use default
self.variants = ['Debug|Win32', 'Release|Win32']
self.variants = ['Debug|Win32', 'Release|Win32', "Debug|ARM64", "Release|ARM64"]

# TODO(rspangler): Need to be able to handle a mapping of solution config
# to project config. Should we be able to handle variants being a dict,
# or add a separate variant_map variable? If it's a dict, we can't
Expand Down
2 changes: 1 addition & 1 deletion gyp/pylib/gyp/MSVSProject.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def __init__(self, project_path, version, name, guid=None, platforms=None):

# Default to Win32 for platforms.
if not platforms:
platforms = ['Win32']
platforms = ['Win32', 'ARM64']

# Initialize the specifications of the various sections.
self.platform_section = ['Platforms']
Expand Down
1 change: 1 addition & 0 deletions gyp/pylib/gyp/MSVSSettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,7 @@ def _ValidateSettings(validators, settings, stderr):
_Same(_midl, 'TargetEnvironment',
_Enumeration(['NotSet',
'Win32', # /env win32
'ARM64', # /env ARM64
'Itanium', # /env ia64
'X64'])) # /env x64
_Same(_midl, 'EnableErrorChecks',
Expand Down
12 changes: 11 additions & 1 deletion gyp/pylib/gyp/generator/msvs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1887,6 +1887,8 @@ def _InitNinjaFlavor(params, target_list, target_dicts):
configuration = '$(Configuration)'
if params.get('target_arch') == 'x64':
configuration += '_x64'
if params.get('target_arch') == 'arm64':
configuration += '_arm64'
spec['msvs_external_builder_out_dir'] = os.path.join(
gyp.common.RelativePath(params['options'].toplevel_dir, gyp_dir),
ninja_generator.ComputeOutputDir(params),
Expand Down Expand Up @@ -2651,9 +2653,17 @@ def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name):
]
]

preferred_tool_architecture = None

if os.environ.get('PROCESSOR_ARCHITECTURE') == 'AMD64' or \
os.environ.get('PROCESSOR_ARCHITEW6432') == 'AMD64':
properties[0].append(['PreferredToolArchitecture', 'x64'])
preferred_tool_architecture = 'x64'

if os.environ.get('npm_config_arch') == 'arm64':
preferred_tool_architecture = 'ARM64'

if preferred_tool_architecture:
properties[0].append(['PreferredToolArchitecture', preferred_tool_architecture])

if spec.get('msvs_enable_winrt'):
properties[0].append(['DefaultLanguage', 'en-US'])
Expand Down
2 changes: 1 addition & 1 deletion gyp/pylib/gyp/generator/ninja.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ def __init__(self, hash_for_rules, target_outputs, base_dir, build_dir,
if flavor == 'win':
# See docstring of msvs_emulation.GenerateEnvironmentFiles().
self.win_env = {}
for arch in ('x86', 'x64'):
for arch in ('x86', 'x64', 'arm64'):
self.win_env[arch] = 'environment.' + arch

# Relative path from build output dir to base dir.
Expand Down
17 changes: 12 additions & 5 deletions gyp/pylib/gyp/msvs_emulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,11 @@ def GetExtension(self):
def GetVSMacroEnv(self, base_to_build=None, config=None):
"""Get a dict of variables mapping internal VS macro names to their gyp
equivalents."""
target_arch = self.GetArch(config)
if target_arch == 'x86':
target_platform = 'Win32'
else:
target_platform = target_arch
target_platform = 'Win32' if self.GetArch(config) == 'x86' else 'x64'
target_name = self.spec.get('product_prefix', '') + \
self.spec.get('product_name', self.spec['target_name'])
Expand Down Expand Up @@ -299,7 +304,7 @@ def GetArch(self, config):
if not platform: # If no specific override, use the configuration's.
platform = configuration_platform
# Map from platform to architecture.
return {'Win32': 'x86', 'x64': 'x64'}.get(platform, 'x86')
return {'Win32': 'x86', 'x64': 'x64', 'ARM64': 'arm64'}.get(platform, 'x86')

def _TargetConfig(self, config):
"""Returns the target-specific configuration."""
Expand Down Expand Up @@ -519,7 +524,7 @@ def GetLibFlags(self, config, gyp_to_build_path):
libflags.extend(self._GetAdditionalLibraryDirectories(
'VCLibrarianTool', config, gyp_to_build_path))
lib('LinkTimeCodeGeneration', map={'true': '/LTCG'})
lib('TargetMachine', map={'1': 'X86', '17': 'X64', '3': 'ARM'},
lib('TargetMachine', map={'1': 'X86', '17': 'X64', '3': 'ARM', '4': 'ARM64'},
prefix='/MACHINE:')
lib('AdditionalOptions')
return libflags
Expand Down Expand Up @@ -563,7 +568,7 @@ def GetLdflags(self, config, gyp_to_build_path, expand_special,
'VCLinkerTool', append=ldflags)
self._GetDefFileAsLdflags(ldflags, gyp_to_build_path)
ld('GenerateDebugInformation', map={'true': '/DEBUG'})
ld('TargetMachine', map={'1': 'X86', '17': 'X64', '3': 'ARM'},
ld('TargetMachine', map={'1': 'X86', '17': 'X64', '3': 'ARM', '4': 'ARM64'},
prefix='/MACHINE:')
ldflags.extend(self._GetAdditionalLibraryDirectories(
'VCLinkerTool', config, gyp_to_build_path))
Expand Down Expand Up @@ -860,7 +865,9 @@ def midl(name, default=None):
('iid', iid),
('proxy', proxy)]
# TODO(scottmg): Are there configuration settings to set these flags?
target_platform = 'win32' if self.GetArch(config) == 'x86' else 'x64'
target_platform = self.GetArch(config)
if target_platform == 'x86':
target_platform = 'win32'
flags = ['/char', 'signed', '/env', target_platform, '/Oicf']
return outdir, output, variables, flags

Expand Down Expand Up @@ -1014,7 +1021,7 @@ def GenerateEnvironmentFiles(toplevel_build_dir, generator_flags,
meet your requirement (e.g. for custom toolchains), you can pass
"-G ninja_use_custom_environment_files" to the gyp to suppress file
generation and use custom environment files prepared by yourself."""
archs = ('x86', 'x64')
archs = ('x86', 'x64', 'arm64')
if generator_flags.get('ninja_use_custom_environment_files', 0):
cl_paths = {}
for arch in archs:
Expand Down
3 changes: 3 additions & 0 deletions lib/configure.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ function configure (gyp, argv, callback) {

// set the target_arch variable
variables.target_arch = gyp.opts.arch || process.arch || 'ia32'
if (variables.target_arch == 'arm64') {
defaults['msvs_configuration_platform'] = 'ARM64'
}

// set the node development directory
variables.nodedir = nodeDir
Expand Down

0 comments on commit 2e98492

Please sign in to comment.