Log warnings to stderr (#585)

Its particularly important during `construct_env` where stdout
is directly interpreted by the shell.

See: #385
This commit is contained in:
Sam Clegg
2020-08-07 11:26:32 -07:00
committed by GitHub
parent 16d4ec5489
commit 1e5c650388

119
emsdk.py
View File

@@ -51,6 +51,11 @@ WINDOWS = False
if os.name == 'nt' or (os.getenv('SYSTEMROOT') is not None and 'windows' in os.getenv('SYSTEMROOT').lower()) or (os.getenv('COMSPEC') is not None and 'windows' in os.getenv('COMSPEC').lower()): if os.name == 'nt' or (os.getenv('SYSTEMROOT') is not None and 'windows' in os.getenv('SYSTEMROOT').lower()) or (os.getenv('COMSPEC') is not None and 'windows' in os.getenv('COMSPEC').lower()):
WINDOWS = True WINDOWS = True
def errlog(msg):
print(msg, file=sys.stderr)
MINGW = False MINGW = False
MSYS = False MSYS = False
if os.getenv('MSYSTEM'): if os.getenv('MSYSTEM'):
@@ -62,7 +67,7 @@ if os.getenv('MSYSTEM'):
MINGW = True MINGW = True
if os.getenv('MSYSTEM') != 'MSYS' and os.getenv('MSYSTEM') != 'MINGW64': if os.getenv('MSYSTEM') != 'MSYS' and os.getenv('MSYSTEM') != 'MINGW64':
# https://stackoverflow.com/questions/37460073/msys-vs-mingw-internal-environment-variables # https://stackoverflow.com/questions/37460073/msys-vs-mingw-internal-environment-variables
print('Warning: MSYSTEM environment variable is present, and is set to "' + os.getenv('MSYSTEM') + '". This shell has not been tested with emsdk and may not work.') errlog('Warning: MSYSTEM environment variable is present, and is set to "' + os.getenv('MSYSTEM') + '". This shell has not been tested with emsdk and may not work.')
MACOS = False MACOS = False
if platform.mac_ver()[0] != '': if platform.mac_ver()[0] != '':
@@ -107,8 +112,8 @@ elif machine.startswith('aarch64') or machine.lower().startswith('arm64'):
elif platform.machine().startswith('arm'): elif platform.machine().startswith('arm'):
ARCH = 'arm' ARCH = 'arm'
else: else:
print("Warning: unknown machine architecture " + machine) errlog("Warning: unknown machine architecture " + machine)
print() errlog()
# Don't saturate all cores to not steal the whole system, but be aggressive. # Don't saturate all cores to not steal the whole system, but be aggressive.
CPU_CORES = int(os.environ.get('EMSDK_NUM_CORES', max(multiprocessing.cpu_count() - 1, 1))) CPU_CORES = int(os.environ.get('EMSDK_NUM_CORES', max(multiprocessing.cpu_count() - 1, 1)))
@@ -316,8 +321,8 @@ def win_set_environment_variable_direct(key, value, system=True):
# 'Access is denied.' # 'Access is denied.'
if e.args[0] == 5: if e.args[0] == 5:
exit_with_error('Error! Failed to set the environment variable \'' + key + '\'! Setting environment variables permanently requires administrator access. Please rerun this command with administrative privileges. This can be done for example by holding down the Ctrl and Shift keys while opening a command prompt in start menu.') exit_with_error('Error! Failed to set the environment variable \'' + key + '\'! Setting environment variables permanently requires administrator access. Please rerun this command with administrative privileges. This can be done for example by holding down the Ctrl and Shift keys while opening a command prompt in start menu.')
print('Failed to write environment variable ' + key + ':', file=sys.stderr) errlog('Failed to write environment variable ' + key + ':')
print(str(e), file=sys.stderr) errlog(str(e))
win32api.RegCloseKey(folder) win32api.RegCloseKey(folder)
os.environ['PATH'] = prev_path os.environ['PATH'] = prev_path
return None return None
@@ -353,8 +358,8 @@ def win_get_environment_variable(key, system=True):
except Exception as e: except Exception as e:
if e.args[0] != 2: if e.args[0] != 2:
# 'The system cannot find the file specified.' # 'The system cannot find the file specified.'
print('Failed to read environment variable ' + key + ':', file=sys.stderr) errlog('Failed to read environment variable ' + key + ':')
print(str(e), file=sys.stderr) errlog(str(e))
try: try:
win32api.RegCloseKey(folder) win32api.RegCloseKey(folder)
except Exception: except Exception:
@@ -405,16 +410,16 @@ def win_set_environment_variable(key, value, system=True):
# Escape % signs so that we don't expand references to environment variables. # Escape % signs so that we don't expand references to environment variables.
value = value.replace('%', '^%') value = value.replace('%', '^%')
if len(value) >= 1024: if len(value) >= 1024:
exit_with_error('ERROR! The new environment variable ' + key + ' is more than 1024 characters long! A value this long cannot be set via command line: please add the environment variable specified above to system environment manually via Control Panel.', file=sys.stderr) exit_with_error('ERROR! The new environment variable ' + key + ' is more than 1024 characters long! A value this long cannot be set via command line: please add the environment variable specified above to system environment manually via Control Panel.')
cmd = ['SETX', key, value] cmd = ['SETX', key, value]
debug_print(str(cmd)) debug_print(str(cmd))
retcode = subprocess.call(cmd, stdout=subprocess.PIPE) retcode = subprocess.call(cmd, stdout=subprocess.PIPE)
if retcode != 0: if retcode != 0:
print('ERROR! Failed to set environment variable ' + key + '=' + value + '. You may need to set it manually.', file=sys.stderr) errlog('ERROR! Failed to set environment variable ' + key + '=' + value + '. You may need to set it manually.')
except Exception as e: except Exception as e:
print('ERROR! Failed to set environment variable ' + key + '=' + value + ':', file=sys.stderr) errlog('ERROR! Failed to set environment variable ' + key + '=' + value + ':')
print(str(e), file=sys.stderr) errlog(str(e))
print('You may need to set it manually.', file=sys.stderr) errlog('You may need to set it manually.')
def win_delete_environment_variable(key, system=True): def win_delete_environment_variable(key, system=True):
@@ -512,7 +517,7 @@ def fix_potentially_long_windows_pathname(pathname):
return pathname return pathname
# Test if emsdk calls fix_potentially_long_windows_pathname() with long relative paths (which is problematic) # Test if emsdk calls fix_potentially_long_windows_pathname() with long relative paths (which is problematic)
if not os.path.isabs(pathname) and len(pathname) > 200: if not os.path.isabs(pathname) and len(pathname) > 200:
print('Warning: Seeing a relative path "' + pathname + '" which is dangerously long for being referenced as a short Windows path name. Refactor emsdk to be able to handle this!') errlog('Warning: Seeing a relative path "' + pathname + '" which is dangerously long for being referenced as a short Windows path name. Refactor emsdk to be able to handle this!')
if pathname.startswith('\\\\?\\'): if pathname.startswith('\\\\?\\'):
return pathname return pathname
pathname = os.path.normpath(pathname.replace('/', '\\')) pathname = os.path.normpath(pathname.replace('/', '\\'))
@@ -701,9 +706,9 @@ def download_file(url, dstpath, download_even_if_exists=False, filename_prefix='
print(']') print(']')
sys.stdout.flush() sys.stdout.flush()
except Exception as e: except Exception as e:
print("Error: Downloading URL '" + url + "': " + str(e)) errlog("Error: Downloading URL '" + url + "': " + str(e))
if "SSL: CERTIFICATE_VERIFY_FAILED" in str(e) or "urlopen error unknown url type: https" in str(e): if "SSL: CERTIFICATE_VERIFY_FAILED" in str(e) or "urlopen error unknown url type: https" in str(e):
print("Warning: Possibly SSL/TLS issue. Update or install Python SSL root certificates (2048-bit or greater) supplied in Python folder or https://pypi.org/project/certifi/ and try again.") errlog("Warning: Possibly SSL/TLS issue. Update or install Python SSL root certificates (2048-bit or greater) supplied in Python folder or https://pypi.org/project/certifi/ and try again.")
rmfile(file_name) rmfile(file_name)
return None return None
except KeyboardInterrupt: except KeyboardInterrupt:
@@ -967,13 +972,13 @@ def make_build(build_root, build_type, build_target_platform='x64'):
print('Running build: ' + str(make)) print('Running build: ' + str(make))
ret = subprocess.check_call(make, cwd=build_root, env=build_env(generator_to_use)) ret = subprocess.check_call(make, cwd=build_root, env=build_env(generator_to_use))
if ret != 0: if ret != 0:
print('Build failed with exit code ' + ret + '!', file=sys.stderr) errlog('Build failed with exit code ' + ret + '!')
print('Working directory: ' + build_root, file=sys.stderr) errlog('Working directory: ' + build_root)
return False return False
except Exception as e: except Exception as e:
print('Build failed due to exception!', file=sys.stderr) errlog('Build failed due to exception!')
print('Working directory: ' + build_root, file=sys.stderr) errlog('Working directory: ' + build_root)
print(str(e), file=sys.stderr) errlog(str(e))
return False return False
return True return True
@@ -1004,25 +1009,25 @@ def cmake_configure(generator, build_root, src_root, build_type, extra_cmake_arg
open(os.path.join(build_root, 'recmake.' + ('bat' if WINDOWS else 'sh')), 'w').write(' '.join(map(quote_parens, cmdline))) open(os.path.join(build_root, 'recmake.' + ('bat' if WINDOWS else 'sh')), 'w').write(' '.join(map(quote_parens, cmdline)))
ret = subprocess.check_call(cmdline, cwd=build_root, env=build_env(CMAKE_GENERATOR)) ret = subprocess.check_call(cmdline, cwd=build_root, env=build_env(CMAKE_GENERATOR))
if ret != 0: if ret != 0:
print('CMake invocation failed with exit code ' + ret + '!', file=sys.stderr) errlog('CMake invocation failed with exit code ' + ret + '!')
print('Working directory: ' + build_root, file=sys.stderr) errlog('Working directory: ' + build_root)
return False return False
except OSError as e: except OSError as e:
if e.errno == errno.ENOENT: if e.errno == errno.ENOENT:
print(str(e), file=sys.stderr) errlog(str(e))
print('Could not run CMake, perhaps it has not been installed?', file=sys.stderr) errlog('Could not run CMake, perhaps it has not been installed?')
if WINDOWS: if WINDOWS:
print('Installing this package requires CMake. Get it from http://www.cmake.org/', file=sys.stderr) errlog('Installing this package requires CMake. Get it from http://www.cmake.org/')
elif LINUX: elif LINUX:
print('Installing this package requires CMake. Get it via your system package manager (e.g. sudo apt-get install cmake), or from http://www.cmake.org/', file=sys.stderr) errlog('Installing this package requires CMake. Get it via your system package manager (e.g. sudo apt-get install cmake), or from http://www.cmake.org/')
elif MACOS: elif MACOS:
print('Installing this package requires CMake. Get it via a macOS package manager (Homebrew: "brew install cmake", or MacPorts: "sudo port install cmake"), or from http://www.cmake.org/', file=sys.stderr) errlog('Installing this package requires CMake. Get it via a macOS package manager (Homebrew: "brew install cmake", or MacPorts: "sudo port install cmake"), or from http://www.cmake.org/')
return False return False
raise raise
except Exception as e: except Exception as e:
print('CMake invocation failed due to exception!', file=sys.stderr) errlog('CMake invocation failed due to exception!')
print('Working directory: ' + build_root, file=sys.stderr) errlog('Working directory: ' + build_root)
print(str(e), file=sys.stderr) errlog(str(e))
return False return False
return True return True
@@ -2112,8 +2117,8 @@ def is_emsdk_sourced_from_github():
def update_emsdk(): def update_emsdk():
if is_emsdk_sourced_from_github(): if is_emsdk_sourced_from_github():
print('You seem to have bootstrapped Emscripten SDK by cloning from GitHub. In this case, use "git pull" instead of "emsdk update" to update emsdk. (Not doing that automatically in case you have local changes)', file=sys.stderr) errlog('You seem to have bootstrapped Emscripten SDK by cloning from GitHub. In this case, use "git pull" instead of "emsdk update" to update emsdk. (Not doing that automatically in case you have local changes)')
print('Alternatively, use "emsdk update-tags" to refresh the latest list of tags from the different Git repositories.', file=sys.stderr) errlog('Alternatively, use "emsdk update-tags" to refresh the latest list of tags from the different Git repositories.')
sys.exit(1) sys.exit(1)
if not download_and_unzip(emsdk_zip_download_url, emsdk_path(), download_even_if_exists=True, clobber=False): if not download_and_unzip(emsdk_zip_download_url, emsdk_path(), download_even_if_exists=True, clobber=False):
sys.exit(1) sys.exit(1)
@@ -2174,7 +2179,7 @@ def load_llvm_precompiled_tags_64bit():
def exit_with_error(msg): def exit_with_error(msg):
sys.stdout.write(str(msg) + '\n') errlog(str(msg))
sys.exit(1) sys.exit(1)
@@ -2348,7 +2353,7 @@ def remove_nonexisting_tools(tool_list, log_errors=True):
tool = tool_list[i] tool = tool_list[i]
if not tool.is_installed(): if not tool.is_installed():
if log_errors: if log_errors:
print("Warning: The SDK/tool '" + str(tool) + "' cannot be activated since it is not installed! Skipping this tool...") errlog("Warning: The SDK/tool '" + str(tool) + "' cannot be activated since it is not installed! Skipping this tool...")
tool_list.pop(i) tool_list.pop(i)
continue continue
i += 1 i += 1
@@ -2563,10 +2568,6 @@ def adjusted_path(tools_to_activate, log_additions=False, system_path_only=False
return (separator.join(whole_path), new_emsdk_tools) return (separator.join(whole_path), new_emsdk_tools)
def log_stderr(msg):
sys.stderr.write(str(msg) + '\n')
def construct_env(tools_to_activate): def construct_env(tools_to_activate):
env_string = '' env_string = ''
newpath, added_path = adjusted_path(tools_to_activate) newpath, added_path = adjusted_path(tools_to_activate)
@@ -2585,10 +2586,10 @@ def construct_env(tools_to_activate):
assert False assert False
if added_path: if added_path:
log_stderr('Adding directories to PATH:') errlog('Adding directories to PATH:')
for item in added_path: for item in added_path:
log_stderr('PATH += ' + item) errlog('PATH += ' + item)
log_stderr('') errlog('')
# A core variable EMSDK points to the root of Emscripten SDK directory. # A core variable EMSDK points to the root of Emscripten SDK directory.
env_vars = [('EMSDK', to_unix_path(emsdk_path()))] env_vars = [('EMSDK', to_unix_path(emsdk_path()))]
@@ -2611,7 +2612,7 @@ def construct_env(tools_to_activate):
env_vars += [(key, value)] env_vars += [(key, value)]
if env_vars: if env_vars:
log_stderr('Setting environment variables:') errlog('Setting environment variables:')
for key, value in env_vars: for key, value in env_vars:
if POWERSHELL: if POWERSHELL:
env_string += '$env:' + key + '="' + value + '"\n' env_string += '$env:' + key + '="' + value + '"\n'
@@ -2623,15 +2624,15 @@ def construct_env(tools_to_activate):
env_string += 'export ' + key + '="' + value + '";\n' env_string += 'export ' + key + '="' + value + '";\n'
else: else:
assert False assert False
log_stderr(key + ' = ' + value) errlog(key + ' = ' + value)
return env_string return env_string
def error_on_missing_tool(name): def error_on_missing_tool(name):
if name.endswith('-64bit') and not is_os_64bit(): if name.endswith('-64bit') and not is_os_64bit():
print("Error: '%s' is only provided for 64-bit OSes." % name) errlog("Error: '%s' is only provided for 64-bit OSes." % name)
else: else:
print("Error: No tool or SDK found by name '%s'." % name) errlog("Error: No tool or SDK found by name '%s'." % name)
return 1 return 1
@@ -2684,7 +2685,7 @@ def main():
global BUILD_FOR_TESTING, ENABLE_LLVM_ASSERTIONS, TTY_OUTPUT global BUILD_FOR_TESTING, ENABLE_LLVM_ASSERTIONS, TTY_OUTPUT
if len(sys.argv) <= 1: if len(sys.argv) <= 1:
print("Missing command; Type 'emsdk help' to get a list of commands.") errlog("Missing command; Type 'emsdk help' to get a list of commands.")
return 1 return 1
if sys.argv[1] in ('help', '--help', '-h'): if sys.argv[1] in ('help', '--help', '-h'):
print(' emsdk: Available commands:') print(' emsdk: Available commands:')
@@ -2806,9 +2807,9 @@ def main():
arg_uses = extract_bool_arg('--uses') arg_uses = extract_bool_arg('--uses')
arg_global = extract_bool_arg('--global') arg_global = extract_bool_arg('--global')
if extract_bool_arg('--embedded'): if extract_bool_arg('--embedded'):
print('embedded mode is now the only mode available', file=sys.stderr) errlog('embedded mode is now the only mode available')
if extract_bool_arg('--no-embedded'): if extract_bool_arg('--no-embedded'):
print('embedded mode is now the only mode available', file=sys.stderr) errlog('embedded mode is now the only mode available')
return 1 return 1
arg_notty = extract_bool_arg('--notty') arg_notty = extract_bool_arg('--notty')
@@ -2833,7 +2834,7 @@ def main():
CMAKE_GENERATOR = build_generator.group(1) CMAKE_GENERATOR = build_generator.group(1)
sys.argv[i] = '' sys.argv[i] = ''
else: else:
print("Cannot parse CMake generator string: " + sys.argv[i] + ". Try wrapping generator string with quotes", file=sys.stderr) errlog("Cannot parse CMake generator string: " + sys.argv[i] + ". Try wrapping generator string with quotes")
return 1 return 1
elif sys.argv[i].startswith('--build='): elif sys.argv[i].startswith('--build='):
build_type = re.match(r'^--build=(.+)$', sys.argv[i]) build_type = re.match(r'^--build=(.+)$', sys.argv[i])
@@ -2846,10 +2847,10 @@ def main():
CMAKE_BUILD_TYPE_OVERRIDE = build_types[build_type_index] CMAKE_BUILD_TYPE_OVERRIDE = build_types[build_type_index]
sys.argv[i] = '' sys.argv[i] = ''
except: except:
print('Unknown CMake build type "' + build_type + '" specified! Please specify one of ' + str(build_types), file=sys.stderr) errlog('Unknown CMake build type "' + build_type + '" specified! Please specify one of ' + str(build_types))
return 1 return 1
else: else:
print("Invalid command line parameter " + sys.argv[i] + ' specified!', file=sys.stderr) errlog("Invalid command line parameter " + sys.argv[i] + ' specified!')
return 1 return 1
sys.argv = [x for x in sys.argv if not len(x) == 0] sys.argv = [x for x in sys.argv if not len(x) == 0]
@@ -3014,14 +3015,14 @@ def main():
return error_on_missing_tool(arg) return error_on_missing_tool(arg)
tools_to_activate += [tool] tools_to_activate += [tool]
if not tools_to_activate: if not tools_to_activate:
print('No tools/SDKs specified to activate! Usage:\n emsdk activate tool/sdk1 [tool/sdk2] [...]') errlog('No tools/SDKs specified to activate! Usage:\n emsdk activate tool/sdk1 [tool/sdk2] [...]')
return 1 return 1
active_tools = set_active_tools(tools_to_activate, permanently_activate=arg_global) active_tools = set_active_tools(tools_to_activate, permanently_activate=arg_global)
if not active_tools: if not active_tools:
print('No tools/SDKs found to activate! Usage:\n emsdk activate tool/sdk1 [tool/sdk2] [...]') errlog('No tools/SDKs found to activate! Usage:\n emsdk activate tool/sdk1 [tool/sdk2] [...]')
return 1 return 1
if WINDOWS and not arg_global: if WINDOWS and not arg_global:
print('The changes made to environment variables only apply to the currently running shell instance. Use the \'emsdk_env.bat\' to re-enter this environment later, or if you\'d like to permanently register this environment globally to all users in Windows Registry, rerun this command with the option --global.') errlog('The changes made to environment variables only apply to the currently running shell instance. Use the \'emsdk_env.bat\' to re-enter this environment later, or if you\'d like to permanently register this environment globally to all users in Windows Registry, rerun this command with the option --global.')
return 0 return 0
elif cmd == 'install': elif cmd == 'install':
# Process args # Process args
@@ -3033,7 +3034,7 @@ def main():
CPU_CORES = int(multicore.group(1)) CPU_CORES = int(multicore.group(1))
sys.argv[i] = '' sys.argv[i] = ''
else: else:
print("Invalid command line parameter " + sys.argv[i] + ' specified!', file=sys.stderr) errlog("Invalid command line parameter " + sys.argv[i] + ' specified!')
return 1 return 1
elif sys.argv[i] == '--shallow': elif sys.argv[i] == '--shallow':
global GIT_CLONE_SHALLOW global GIT_CLONE_SHALLOW
@@ -3050,7 +3051,7 @@ def main():
sys.argv[i] = '' sys.argv[i] = ''
sys.argv = [x for x in sys.argv if not len(x) == 0] sys.argv = [x for x in sys.argv if not len(x) == 0]
if len(sys.argv) <= 2: if len(sys.argv) <= 2:
print("Missing parameter. Type 'emsdk install <tool name>' to install a tool or an SDK. Type 'emsdk list' to obtain a list of available tools. Type 'emsdk install latest' to automatically install the newest version of the SDK.") errlog("Missing parameter. Type 'emsdk install <tool name>' to install a tool or an SDK. Type 'emsdk list' to obtain a list of available tools. Type 'emsdk install latest' to automatically install the newest version of the SDK.")
return 1 return 1
for t in sys.argv[2:]: for t in sys.argv[2:]:
tool = find_tool(t) tool = find_tool(t)
@@ -3064,16 +3065,16 @@ def main():
return 0 return 0
elif cmd == 'uninstall': elif cmd == 'uninstall':
if len(sys.argv) <= 2: if len(sys.argv) <= 2:
print("Syntax error. Call 'emsdk uninstall <tool name>'. Call 'emsdk list' to obtain a list of available tools.") errlog("Syntax error. Call 'emsdk uninstall <tool name>'. Call 'emsdk list' to obtain a list of available tools.")
return 1 return 1
tool = find_tool(sys.argv[2]) tool = find_tool(sys.argv[2])
if tool is None: if tool is None:
print("Error: Tool by name '" + sys.argv[2] + "' was not found.") errlog("Error: Tool by name '" + sys.argv[2] + "' was not found.")
return 1 return 1
tool.uninstall() tool.uninstall()
return 0 return 0
print("Unknown command '" + cmd + "' given! Type 'emsdk help' to get a list of commands.") errlog("Unknown command '" + cmd + "' given! Type 'emsdk help' to get a list of commands.")
return 1 return 1