From ce19f7a4bbbcfdc0af27ef4aa3d22f2b01b07f83 Mon Sep 17 00:00:00 2001 From: Yohei Yukawa Date: Thu, 21 Nov 2024 21:33:41 +0900 Subject: [PATCH] WIP: Build mozc_tip64.dll for ARM64 --- src/base/system_util.cc | 20 ++++----- src/build_mozc.py | 68 +++++++++++++++++++++++-------- src/build_tools/protoc_wrapper.py | 2 + src/gyp/common_win.gypi | 37 ++++++++++++++--- src/win32/tip/tip_text_service.cc | 4 +- 5 files changed, 96 insertions(+), 35 deletions(-) diff --git a/src/base/system_util.cc b/src/base/system_util.cc index ec1b70e0f..93ae8c220 100644 --- a/src/base/system_util.cc +++ b/src/base/system_util.cc @@ -376,7 +376,14 @@ class ProgramFilesX86Cache { path->clear(); wchar_t program_files_path_buffer[MAX_PATH] = {}; -#if defined(_M_X64) +#if defined(_M_IX86) + // In 32-bit processes (such as server, renderer, and other binaries), + // CSIDL_PROGRAM_FILES always points 32-bit Program Files directory + // even if they are running in 64-bit Windows. + const HRESULT result = + ::SHGetFolderPathW(nullptr, CSIDL_PROGRAM_FILES, nullptr, + SHGFP_TYPE_CURRENT, program_files_path_buffer); +#else // !_M_IX86 // In 64-bit processes (such as Text Input Prosessor DLL for 64-bit apps), // CSIDL_PROGRAM_FILES points 64-bit Program Files directory. In this case, // we should use CSIDL_PROGRAM_FILESX86 to find server, renderer, and other @@ -384,16 +391,7 @@ class ProgramFilesX86Cache { const HRESULT result = ::SHGetFolderPathW(nullptr, CSIDL_PROGRAM_FILESX86, nullptr, SHGFP_TYPE_CURRENT, program_files_path_buffer); -#elif defined(_M_IX86) - // In 32-bit processes (such as server, renderer, and other binaries), - // CSIDL_PROGRAM_FILES always points 32-bit Program Files directory - // even if they are running in 64-bit Windows. - const HRESULT result = - ::SHGetFolderPathW(nullptr, CSIDL_PROGRAM_FILES, nullptr, - SHGFP_TYPE_CURRENT, program_files_path_buffer); -#else // !_M_X64 && !_M_IX86 -#error "Unsupported CPU architecture" -#endif // _M_X64, _M_IX86, and others +#endif // _M_IX86 if (FAILED(result)) { return result; } diff --git a/src/build_mozc.py b/src/build_mozc.py index f3f55e9dc..7b7dbb6ee 100755 --- a/src/build_mozc.py +++ b/src/build_mozc.py @@ -43,6 +43,7 @@ import optparse import os import pathlib +import platform import re import subprocess import sys @@ -349,29 +350,64 @@ def ParseCleanOptions(args): return parser.parse_args(args) -def UpdateEnvironmentFilesForWindows(out_dir): +def ReadEnvironmentFile(path): + nul = chr(0) + with open(path, 'rb') as f: + content = f.read() + entries = content.decode('utf-8').split(nul) + env = dict() + for e in entries: + if '=' in e: + key, value = e.split('=', 1) + env[key] = value + return env + + +def WriteEnvironmentFile(path, env): + nul = chr(0) + entries = [f'{key}={value}' for (key, value) in env.items()] + entries.extend(['', '']) + with open(path, 'wb') as f: + f.write(nul.join(entries).encode('utf-8')) + + +def UpdateEnvironmentFilesForWindows(out_dir, vcvarsall_path): """Add required environment variables for Ninja build.""" python_path_root = MOZC_ROOT python_path = os.path.abspath(python_path_root) original_python_paths = os.environ.get('PYTHONPATH', '') if original_python_paths: python_path = os.pathsep.join([original_python_paths, python_path]) - nul = chr(0) - additional_content = nul.join([ - 'PYTHONPATH=' + python_path, - 'VSLANG=1033', # 1033 == MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) - nul]).encode('utf-8') + for d in os.listdir(out_dir): abs_dir = os.path.abspath(os.path.join(out_dir, d)) - with open(os.path.join(abs_dir, 'environment.x86'), 'rb') as x86_file: - x86_content = x86_file.read()[:-1] + additional_content - with open(os.path.join(abs_dir, 'environment.x86'), 'wb') as x86_file: - x86_file.write(x86_content) - with open(os.path.join(abs_dir, 'environment.x64'), 'rb') as x64_file: - x64_content = x64_file.read()[:-1] + additional_content - with open(os.path.join(abs_dir, 'environment.x64'), 'wb') as x64_file: - x64_file.write(x64_content) - + # Tweak generated build rules for ARM64 + if d.endswith('arm64'): + build_ninja = os.path.join(abs_dir, 'build.ninja') + with open(build_ninja, 'r', encoding='utf-8') as f: + lines = f.readlines() + for i in range(0, 2): + lines[i] = lines[i].replace('x64\\cl.exe', 'arm64\\cl.exe') + lines[i] = lines[i].replace('x86\\cl.exe', 'arm64\\cl.exe') + with open(build_ninja, 'w', encoding='utf-8') as f: + f.writelines(lines) + + for arch in ['x86', 'x64']: + env_file = os.path.join(abs_dir, f'environment.{arch}') + env = ReadEnvironmentFile(env_file) + # Tweak for ARM64 + if d.endswith('arm64'): + vs_arch = platform.uname().machine + if vs_arch != 'arm64': + vs_arch = vs_arch + '_arm64' + vs_env = get_vs_env_vars(vs_arch) + env['INCLUDE'] = vs_env['INCLUDE'] + env['LIB'] = vs_env['LIB'] + env['LIBPATH'] = vs_env['LIBPATH'] + env['PATH'] = vs_env['PATH'] + env['PYTHONPATH'] = python_path + env['VSLANG'] = '1033' # == MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) + WriteEnvironmentFile(env_file, env) def GypMain(options, unused_args): @@ -548,7 +584,7 @@ def GypMain(options, unused_args): # For internal Ninja build on Windows, set up environment files if IsWindows(): out_dir = os.path.join(MOZC_ROOT, 'out_win') - UpdateEnvironmentFilesForWindows(out_dir) + UpdateEnvironmentFilesForWindows(out_dir, options.vcvarsall_path) if IsWindows() and qt_dir and qt_ver: # When Windows build is configured to use DLL version of Qt, copy Qt's DLLs diff --git a/src/build_tools/protoc_wrapper.py b/src/build_tools/protoc_wrapper.py index e1e507292..e66f294a5 100755 --- a/src/build_tools/protoc_wrapper.py +++ b/src/build_tools/protoc_wrapper.py @@ -85,6 +85,8 @@ def main(): protoc_path = opts.protoc_command if opts.protoc_dir: protoc_path = os.path.join(os.path.abspath(opts.protoc_dir), protoc_path) + if os.name == 'nt' and protoc_path.endswith('_arm64\\protoc.exe'): + protoc_path = protoc_path.replace('_arm64\\protoc', '_x64\\protoc') # The path of proto file should be transformed as a relative path from # the project root so that correct relative paths should be embedded into diff --git a/src/gyp/common_win.gypi b/src/gyp/common_win.gypi index 3383b3a1b..8f53b7104 100644 --- a/src/gyp/common_win.gypi +++ b/src/gyp/common_win.gypi @@ -128,9 +128,7 @@ }, 'VCLinkerTool': { 'TargetMachine': '<(win_target_machine_x86)', - 'AdditionalOptions': [ - '/SAFESEH', - ], + 'ImageHasSafeExceptionHandlers': 'true', 'EnableUAC': 'true', 'UACExecutionLevel': '0', # level="asInvoker" 'UACUIAccess': 'false', # uiAccess="false" @@ -158,6 +156,30 @@ }, 'VCLinkerTool': { 'TargetMachine': '<(win_target_machine_x64)', + 'AdditionalOptions': [ + '/CETCOMPAT', + ], + }, + }, + }, + 'arm64_Base': { + 'abstract': 1, + 'msvs_configuration_attributes': { + 'OutputDirectory': '<(build_base)/$(ConfigurationName)_arm64', + 'IntermediateDirectory': '<(build_base)/$(ConfigurationName)_arm64/obj/$(ProjectName)', + }, + 'msvs_target_platform': 'arm64', + 'msvs_settings': { + 'VCCLCompilerTool': { + 'AdditionalOptions': [ + '/bigobj', + ], + }, + 'VCLinkerTool': { + 'ImageHasSafeExceptionHandlers': 'false', + 'AdditionalOptions': [ + '/MACHINE:ARM64', + ], }, }, }, @@ -270,6 +292,12 @@ 'Release_x64': { 'inherit_from': ['x64_Base', 'Release_Base', 'Win_Static_Release_CRT_Base'], }, + 'Debug_arm64': { + 'inherit_from': ['arm64_Base', 'Debug_Base', 'Win_Static_Debug_CRT_Base'], + }, + 'Release_arm64': { + 'inherit_from': ['arm64_Base', 'Release_Base', 'Win_Static_Release_CRT_Base'], + }, }, 'default_configuration': 'Debug', 'defines': [ @@ -338,9 +366,6 @@ 'user32.lib', 'uuid.lib', ], - 'AdditionalOptions': [ - '/CETCOMPAT', - ], 'DataExecutionPrevention': '2', # /NXCOMPAT 'EnableCOMDATFolding': '2', # /OPT:ICF 'GenerateDebugInformation': 'true', # /DEBUG diff --git a/src/win32/tip/tip_text_service.cc b/src/win32/tip/tip_text_service.cc index 71aafdb7f..d19cae25a 100644 --- a/src/win32/tip/tip_text_service.cc +++ b/src/win32/tip/tip_text_service.cc @@ -251,9 +251,9 @@ struct ComPtrHash { size_t operator()(const wil::com_ptr_nothrow &value) const { // Caveats: On x86 environment, both _M_X64 and _M_IX86 are defined. So we // need to check _M_X64 first. -#if defined(_M_X64) +#if defined(_M_X64) || defined(_M_ARM64) constexpr size_t kUnusedBits = 3; // assuming 8-byte aligned -#elif defined(_M_IX86) // defined(_M_X64) +#elif defined(_M_IX86) // defined(_M_X64) or defined(_M_ARM64) constexpr size_t kUnusedBits = 2; // assuming 4-byte aligned #else // defined(_M_IX86) #error "unsupported platform"