| # Copyright 2020 The Emscripten Authors. All rights reserved. |
| # Emscripten is available under two separate licenses, the MIT license and the |
| # University of Illinois/NCSA Open Source License. Both these licenses can be |
| # found in the LICENSE file. |
| |
| import logging |
| import os |
| import platform |
| import sys |
| from tools.shared import PIPE, run_process, CLANG_CC, CLANG_CXX |
| from tools.utils import MACOS, WINDOWS, path_from_root |
| |
| logger = logging.getLogger('clang_native') |
| |
| |
| def get_native_triple(): |
| arch = { |
| 'aarch64': 'arm64', |
| 'arm64': 'arm64', |
| 'x86_64': 'x86_64', |
| 'AMD64': 'x86_64', |
| }[platform.machine()] |
| OS = { |
| 'linux': 'linux', |
| 'darwin': 'darwin', |
| 'win32': 'windows-msvc', |
| }[sys.platform] |
| return f'{arch}-{OS}' |
| |
| |
| # These extra args need to be passed to Clang when targeting a native host system executable |
| def get_clang_native_args(): |
| triple = ['--target=' + get_native_triple()] |
| if MACOS: |
| return triple + ['-isystem', path_from_root('system/include/libcxx')] |
| elif os.name == 'nt': |
| # TODO: If Windows.h et al. are needed, will need to add something like '-isystemC:/Program |
| # Files (x86)/Microsoft SDKs/Windows/v7.1A/Include'. |
| return triple + ['-DWIN32'] |
| else: |
| return triple |
| |
| |
| # This environment needs to be present when targeting a native host system executable |
| CACHED_CLANG_NATIVE_ENV = None |
| |
| |
| def get_clang_native_env(): |
| global CACHED_CLANG_NATIVE_ENV |
| if CACHED_CLANG_NATIVE_ENV is not None: |
| return CACHED_CLANG_NATIVE_ENV |
| env = os.environ.copy() |
| |
| env['CC'] = CLANG_CC |
| env['CXX'] = CLANG_CXX |
| env['LD'] = CLANG_CXX |
| |
| if MACOS: |
| path = run_process(['xcrun', '--show-sdk-path'], stdout=PIPE).stdout.strip() |
| logger.debug('Using MacOS SDKROOT: ' + path) |
| env['SDKROOT'] = path |
| elif WINDOWS: |
| # If already running in Visual Studio Command Prompt manually, no need to |
| # add anything here, so just return. |
| if 'VSINSTALLDIR' in env and 'INCLUDE' in env and 'LIB' in env: |
| CACHED_CLANG_NATIVE_ENV = env |
| return env |
| |
| # VSINSTALLDIR is not in environment, so the user is not running in Visual Studio |
| # Command Prompt. Attempt to autopopulate INCLUDE and LIB directives. |
| |
| # Guess where Visual Studio is installed (VSINSTALLDIR env. var in VS X64 Command Prompt) |
| if 'VSINSTALLDIR' in env: |
| visual_studio_path = env['VSINSTALLDIR'] |
| elif 'VS170COMNTOOLS' in env: |
| visual_studio_path = os.path.normpath(os.path.join(env['VS170COMNTOOLS'], '../..')) |
| elif 'ProgramFiles(x86)' in env: |
| visual_studio_path = os.path.normpath(os.path.join(env['ProgramFiles(x86)'], 'Microsoft Visual Studio', '2022', 'Community')) |
| elif 'ProgramFiles' in env: |
| visual_studio_path = os.path.normpath(os.path.join(env['ProgramFiles'], 'Microsoft Visual Studio', '2022', 'Community')) |
| else: |
| visual_studio_path = 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Community' |
| if not os.path.isdir(visual_studio_path): |
| raise Exception('Visual Studio was not found in "' + visual_studio_path + '"! Run in Visual Studio X64 command prompt to avoid the need to autoguess this location (or set VSINSTALLDIR env var).') |
| |
| # Guess where Program Files (x86) is located |
| if 'ProgramFiles(x86)' in env: |
| prog_files_x86 = env['ProgramFiles(x86)'] |
| elif 'ProgramFiles' in env: |
| prog_files_x86 = env['ProgramFiles'] |
| elif os.path.isdir('C:\\Program Files (x86)'): |
| prog_files_x86 = 'C:\\Program Files (x86)' |
| elif os.path.isdir('C:\\Program Files'): |
| prog_files_x86 = 'C:\\Program Files' |
| else: |
| raise Exception('Unable to detect Program files directory for native Visual Studio build!') |
| |
| # Find include directory root |
| def highest_version_subdir(path): |
| candidates = [] |
| for entry in os.listdir(path): |
| full = os.path.join(path, entry) |
| if os.path.isdir(full): |
| try: |
| candidates.append((tuple(int(p) for p in entry.split('.')), full)) |
| except ValueError: |
| continue |
| if len(candidates) == 0: |
| return None |
| return max(candidates, key=lambda x: x[0])[1] |
| |
| vc_root = os.path.join(visual_studio_path, 'VC') |
| vc_code_root = highest_version_subdir(os.path.join(vc_root, 'Tools', 'MSVC')) |
| if not vc_code_root: |
| raise Exception ('Unable to find Visual Studio INCLUDE root directory. Run in Visual Studio command prompt to avoid the need to autoguess this location.') |
| |
| windows_sdk_dir = highest_version_subdir(os.path.join(prog_files_x86, 'Windows Kits')) |
| if not windows_sdk_dir: |
| raise Exception ('Unable to find Windows SDK root directory. Run in Visual Studio command prompt to avoid the need to autoguess this location.') |
| |
| env.setdefault('VSINSTALLDIR', visual_studio_path) |
| env.setdefault('VCINSTALLDIR', os.path.join(visual_studio_path, 'VC')) |
| |
| windows_sdk_include_dir = highest_version_subdir(os.path.join(windows_sdk_dir, 'include')) |
| windows_sdk_lib_dir = highest_version_subdir(os.path.join(windows_sdk_dir, 'lib')) |
| |
| def append_path_item(key, path): |
| if not os.path.isdir(path): |
| logger.warning(f'VS path {path} does not exist') |
| return |
| |
| if key not in env or len(env[key].strip()) == 0: |
| env[key] = path |
| else: |
| env[key] = env[key] + ';' + path |
| |
| append_path_item('INCLUDE', os.path.join(vc_code_root, 'include')) |
| append_path_item('INCLUDE', os.path.join(vc_code_root, 'ATLMFC', 'include')) |
| append_path_item('INCLUDE', os.path.join(vc_root, 'Auxiliary', 'VS', 'include')) |
| for d in ['ucrt', 'um', 'shared', 'winrt', 'cppwinrt']: |
| append_path_item('INCLUDE', os.path.join(windows_sdk_include_dir, d)) |
| logger.debug('Visual Studio native build INCLUDE: ' + env['INCLUDE']) |
| |
| append_path_item('LIB', os.path.join(vc_code_root, 'ATLMFC', 'lib', 'x64')) |
| append_path_item('LIB', os.path.join(vc_code_root, 'lib', 'x64')) |
| append_path_item('LIB', os.path.join(windows_sdk_lib_dir, 'ucrt', 'x64')) |
| append_path_item('LIB', os.path.join(windows_sdk_lib_dir, 'um', 'x64')) |
| logger.debug('Visual Studio native build LIB: ' + env['LIB']) |
| |
| env['PATH'] = env['PATH'] + ';' + os.path.join(env['VCINSTALLDIR'], 'BIN') |
| logger.debug('Visual Studio native build PATH: ' + env['PATH']) |
| |
| CACHED_CLANG_NATIVE_ENV = env |
| return env |