From fa6dc7bad8002e8502af104e44a576e899db16a3 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 29 Apr 2019 15:39:20 -0700 Subject: [PATCH] Fix some flake8 warnings in emsdk (#224) Only some checks are enabled here in order to make this change easier to review and less error prone. --- .flake8 | 3 + .travis.yml | 4 + emsdk | 295 +++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 228 insertions(+), 74 deletions(-) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..e131765 --- /dev/null +++ b/.flake8 @@ -0,0 +1,3 @@ +[flake8] +ignore = E111,E114,E501,E261,E266,E121,E402,E241,E701 +filename = emsdk diff --git a/.travis.yml b/.travis.yml index 834e16d..b0741a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,11 @@ services: before_install: - docker pull ubuntu:16.04 +install: + - pip install flake8==3.4.1 + script: + - flake8 - set -o errexit - echo "running..." - docker build . diff --git a/emsdk b/emsdk index d832cbf..15d0322 100755 --- a/emsdk +++ b/emsdk @@ -1,21 +1,35 @@ #!/usr/bin/env python from __future__ import print_function -import sys, optparse, subprocess, os, os.path, errno, zipfile, string, json, platform, shutil, tarfile, tempfile, multiprocessing, re, stat, copy + +import copy +import errno +import json +import multiprocessing +import os +import os.path +import platform +import re +import shutil +import stat +import subprocess +import sys +import tempfile +import zipfile + if sys.version_info >= (3,): from urllib.parse import urljoin from urllib.request import urlopen - from urllib.error import HTTPError import functools else: from urlparse import urljoin - from urllib2 import urlopen, HTTPError + from urllib2 import urlopen # EMSDK_DEV is a developer mode flag, which, if true, the SDK is downloaded from a 'staging' online source, # instead of the public source. New releases are first deployed to the staging source for testing, before # being published to the public. Don't enable this unless you develop EMSDK itself and need to access the # staging source repository instead. -EMSDK_DEV = bool(os.getenv('EMSDK_DEV')) if os.getenv('EMSDK_DEV') != None else False +EMSDK_DEV = bool(os.getenv('EMSDK_DEV')) if os.getenv('EMSDK_DEV') is not None else False if EMSDK_DEV: print('EMSDK_DEV active.') @@ -29,13 +43,13 @@ emscripten_git_repo = 'https://github.com/kripken/emscripten.git' binaryen_git_repo = 'https://github.com/WebAssembly/binaryen.git' # Enable this to do very verbose printing about the different steps that are being run. Useful for debugging. -VERBOSE = bool(os.getenv('EMSDK_VERBOSE')) if os.getenv('EMSDK_VERBOSE') != None else False +VERBOSE = bool(os.getenv('EMSDK_VERBOSE')) if os.getenv('EMSDK_VERBOSE') is not None else False TTY_OUTPUT = sys.stdout.isatty() POWERSHELL = bool(os.getenv('EMSDK_POWERSHELL')) WINDOWS = False -if os.name == 'nt' or (os.getenv('SYSTEMROOT') != None and 'windows' in os.getenv('SYSTEMROOT').lower()) or (os.getenv('COMSPEC') != 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 ENVPATH_SEPARATOR = ';' @@ -55,7 +69,8 @@ if not OSX and (platform.system() == 'Linux' or os.name == 'posix'): LINUX = True ENVPATH_SEPARATOR = ':' -CPU_CORES = max(multiprocessing.cpu_count()-1, 1) # 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 = max(multiprocessing.cpu_count() - 1, 1) CMAKE_BUILD_TYPE_OVERRIDE = None @@ -72,10 +87,14 @@ ENABLE_WASM = False # Other valid values are 'ON' and 'OFF' ENABLE_LLVM_ASSERTIONS = 'auto' + def to_unix_path(p): return p.replace('\\', '/') -def emsdk_path(): return to_unix_path(os.path.dirname(os.path.realpath(__file__))) + +def emsdk_path(): + return to_unix_path(os.path.dirname(os.path.realpath(__file__))) + emscripten_config_directory = os.path.expanduser("~/") # If .emscripten exists, we are configuring as embedded inside the emsdk directory. @@ -84,6 +103,7 @@ if os.path.exists(os.path.join(emsdk_path(), '.emscripten')): EMSDK_SET_ENV = 'emsdk_set_env.ps1' if POWERSHELL else 'emsdk_set_env.bat' if (WINDOWS and not MSYS) else 'emsdk_set_env.sh' + # Finds the given executable 'program' in PATH. Operates like the Unix tool 'which'. def which(program): def is_exe(fpath): @@ -100,7 +120,7 @@ def which(program): if is_exe(exe_file): return exe_file - if WINDOWS and not '.' in fname: + if WINDOWS and '.' not in fname: if is_exe(exe_file + '.exe'): return exe_file + '.exe' if is_exe(exe_file + '.cmd'): @@ -110,6 +130,7 @@ def which(program): return None + def vswhere(version): try: program_files = os.environ['ProgramFiles(x86)'] if 'ProgramFiles(x86)' in os.environ else os.environ['ProgramFiles'] @@ -119,18 +140,20 @@ def vswhere(version): if len(output) == 0: output = json.loads(subprocess.check_output([vswhere_path, '-latest', '-version', '[%s.0,%s.0)' % (version, version + 1), '-products', '*', '-property', 'installationPath', '-format', 'json'])) return str(output[0]['installationPath']) if len(output) > 0 else '' - except Exception as e: + except Exception: return '' + def vs_filewhere(installation_path, platform, file): try: vcvarsall = os.path.join(installation_path, 'VC\\Auxiliary\\Build\\vcvarsall.bat') env = subprocess.check_output('cmd /c "%s" %s & where %s' % (vcvarsall, platform, file)) paths = [path[:-len(file)] for path in env.split('\r\n') if path.endswith(file)] return paths[0] - except Exception as e: + except Exception: return '' + CMAKE_GENERATOR = 'Unix Makefiles' if WINDOWS: # Detect which CMake generator to use when building on Windows @@ -143,15 +166,19 @@ if WINDOWS: vs2017_exists = len(vswhere(15)) > 0 vs2015_exists = 'VS140COMNTOOLS' in os.environ or 'VSSDK140Install' in os.environ or os.path.isdir(os.path.join(program_files, 'Microsoft Visual Studio 14.0')) vs2013_exists = 'VS120COMNTOOLS' in os.environ or os.path.isdir(os.path.join(program_files, 'Microsoft Visual Studio 12.0')) - mingw_exists = which('mingw32-make') != None and which('g++') != None + mingw_exists = which('mingw32-make') is not None and which('g++') is not None if vs2015_exists: CMAKE_GENERATOR = 'Visual Studio 14' elif vs2017_exists: CMAKE_GENERATOR = 'Visual Studio 15' # VS2017 has an LLVM build issue, see https://github.com/kripken/emscripten-fastcomp/issues/185 elif mingw_exists: CMAKE_GENERATOR = 'MinGW Makefiles' elif vs2013_exists: CMAKE_GENERATOR = 'Visual Studio 12' # VS2013 is no longer supported, so attempt it as a last resort if someone might want to insist using it. else: CMAKE_GENERATOR = '' # No detected generator -if VERBOSE: print('CMAKE_GENERATOR: ' + CMAKE_GENERATOR) + + +if VERBOSE: + print('CMAKE_GENERATOR: ' + CMAKE_GENERATOR) sys.argv = list(filter(lambda x: x not in ['--mingw', '--vs2013', '--vs2015', '--vs2017'], sys.argv)) + # Computes a suitable path prefix to use when building with a given generator. def cmake_generator_prefix(): if CMAKE_GENERATOR == 'Visual Studio 15': return '_vs2017' @@ -159,6 +186,7 @@ def cmake_generator_prefix(): elif CMAKE_GENERATOR == 'MinGW Makefiles': return '_mingw' return '' # Unix Makefiles and Visual Studio 2013 do not specify a path prefix for backwards path compatibility + # Removes a directory tree even if it was readonly, and doesn't throw exception on failure. def remove_tree(d): if VERBOSE: print('remove_tree(' + str(d) + ')') @@ -174,14 +202,18 @@ def remove_tree(d): if VERBOSE: print('remove_tree threw an exception, ignoring: ' + str(e)) pass + def import_pywin32(): if WINDOWS: try: - import win32api, win32con - except Exception as e: + import win32api + import win32con + return win32api, win32con + except Exception: print('Failed to import Python Windows extensions win32api and win32con. Make sure you are using the version of python available in emsdk, or install PyWin extensions to the distribution of Python you are attempting to use. (This script was launched in python instance from "' + sys.executable + '")') sys.exit(1) + def win_set_environment_variable_direct(key, value, system=True): prev_path = os.environ['PATH'] try: @@ -189,7 +221,7 @@ def win_set_environment_variable_direct(key, value, system=True): if py: py_path = to_native_path(py.expand_vars(py.activated_path)) os.environ['PATH'] = os.environ['PATH'] + ';' + py_path - import_pywin32() + win32api, win32con = import_pywin32() if system: # Read globally from ALL USERS section. folder = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment', 0, win32con.KEY_ALL_ACCESS) else: # Register locally from CURRENT USER section. @@ -210,6 +242,7 @@ def win_set_environment_variable_direct(key, value, system=True): os.environ['PATH'] = prev_path win32api.SendMessage(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment') + def win_get_environment_variable(key, system=True): prev_path = os.environ['PATH'] try: @@ -218,7 +251,8 @@ def win_get_environment_variable(key, system=True): py_path = to_native_path(py.expand_vars(py.activated_path)) os.environ['PATH'] = os.environ['PATH'] + ';' + py_path try: - import win32api, win32con + import win32api + import win32con if system: # Read globally from ALL USERS section. folder = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment') else: # Register locally from CURRENT USER section. @@ -242,16 +276,19 @@ def win_get_environment_variable(key, system=True): os.environ['PATH'] = prev_path return value + def win_environment_variable_exists(key, system=True): value = win_get_environment_variable(key, system) - return value != None and len(value) > 0 + return value is not None and len(value) > 0 + def win_get_active_environment_variable(key): value = win_get_environment_variable(key, False) - if value != None: + if value is not None: return value return win_get_environment_variable(key, True) + def win_set_environment_variable(key, value, system=True): if VERBOSE: print('set ' + str(key) + '=' + str(value) + ', in system=' + str(system), file=sys.stderr) previous_value = win_get_environment_variable(key, system) @@ -289,10 +326,12 @@ def win_set_environment_variable(key, value, system=True): print(str(e), file=sys.stderr) print('You may need to set it manually.', file=sys.stderr) + def win_delete_environment_variable(key, system=True): if VERBOSE: print('win_delete_environment_variable(key=' + key + ', system=' + str(system) + ')') win_set_environment_variable(key, None, system) + # Returns the absolute pathname to the given path inside the Emscripten SDK. def sdk_path(path): if os.path.isabs(path): @@ -300,18 +339,21 @@ def sdk_path(path): else: return to_unix_path(os.path.join(os.path.dirname(os.path.realpath(__file__)), path)) + # Modifies the given file in-place to contain '\r\n' line endings. def file_to_crlf(filename): text = open(filename, 'r').read() text = text.replace('\r\n', '\n').replace('\n', '\r\n') open(filename, 'wb').write(text) + # Modifies the given file in-place to contain '\n' line endings. def file_to_lf(filename): text = open(filename, 'r').read() text = text.replace('\r\n', '\n') open(filename, 'wb').write(text) + # Removes a single file, suppressing exceptions on failure. def rmfile(filename): if VERBOSE: print('rmfile(' + filename + ')') @@ -320,12 +362,14 @@ def rmfile(filename): except: pass + def fix_lineendings(filename): if WINDOWS: file_to_crlf(filename) else: file_to_lf(filename) + # http://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python def mkdir_p(path): if VERBOSE: print('mkdir_p(' + path + ')') @@ -338,11 +382,13 @@ def mkdir_p(path): pass else: raise + def num_files_in_directory(path): if not os.path.isdir(path): return 0 return len([name for name in os.listdir(path) if os.path.exists(os.path.join(path, name))]) + def run(cmd, cwd=None): if VERBOSE: print('run(cmd=' + str(cmd) + ', cwd=' + str(cwd) + ')') process = subprocess.Popen(cmd, cwd=cwd, env=os.environ.copy()) @@ -351,6 +397,7 @@ def run(cmd, cwd=None): print(str(cmd) + ' failed with error code ' + str(process.returncode) + '!') return process.returncode + # http://pythonicprose.blogspot.fi/2009/10/python-extract-targz-archive.html def untargz(source_filename, dest_dir, unpack_even_if_exists=False): if VERBOSE: print('untargz(source_filename=' + source_filename + ', dest_dir=' + dest_dir + ')') @@ -360,10 +407,11 @@ def untargz(source_filename, dest_dir, unpack_even_if_exists=False): print("Unpacking '" + source_filename + "' to '" + dest_dir + "'") mkdir_p(dest_dir) run(['tar', '-xvf' if VERBOSE else '-xf', sdk_path(source_filename), '--strip', '1'], cwd=dest_dir) - #tfile = tarfile.open(source_filename, 'r:gz') - #tfile.extractall(dest_dir) + # tfile = tarfile.open(source_filename, 'r:gz') + # tfile.extractall(dest_dir) return True + # On Windows, it is not possible to reference path names that are longer than ~260 characters, unless the path is referenced via a "\\?\" prefix. # See https://msdn.microsoft.com/en-us/library/aa365247.aspx#maxpath and http://stackoverflow.com/questions/3555527/python-win32-filename-length-workaround # In that mode, forward slashes cannot be used as delimiters. @@ -374,6 +422,7 @@ def fix_potentially_long_windows_pathname(pathname): if pathname.startswith('\\\\?\\'): return pathname return '\\\\?\\' + os.path.normpath(pathname.replace('/', '\\')) + # http://stackoverflow.com/questions/12886768/simple-way-to-unzip-file-in-python-on-all-oses def unzip(source_filename, dest_dir, unpack_even_if_exists=False): if VERBOSE: print('unzip(source_filename=' + source_filename + ', dest_dir=' + dest_dir + ')') @@ -390,7 +439,7 @@ def unzip(source_filename, dest_dir, unpack_even_if_exists=False): for member in zf.infolist(): words = member.filename.split('/') if len(words) > 1: # If there is a directory component? - if common_subdir == None: + if common_subdir is None: common_subdir = words[0] elif common_subdir != words[0]: common_subdir = None @@ -435,6 +484,7 @@ def unzip(source_filename, dest_dir, unpack_even_if_exists=False): return True + # This function interprets whether the given string looks like a path to a directory instead of a file, without looking at the actual filesystem. # 'a/b/c' points to directory, so does 'a/b/c/', but 'a/b/c.x' is parsed as a filename def path_points_to_directory(path): @@ -451,20 +501,22 @@ def path_points_to_directory(path): else: return True + def get_content_length(download): try: meta = download.info() if hasattr(meta, "getheaders") and hasattr(meta.getheaders, "Content-Length"): return int(meta.getheaders("Content-Length")[0]) elif hasattr(download, "getheader") and download.getheader('Content-Length'): return int(download.getheader('Content-Length')) elif hasattr(meta, "getheader") and meta.getheader('Content-Length'): return int(meta.getheader('Content-Length')) - except Exception as e: + except Exception: pass return 0 + # On success, returns the filename on the disk pointing to the destination file that was produced # On failure, returns None. -def download_file(url, dstpath, download_even_if_exists=False, filename_prefix = ''): +def download_file(url, dstpath, download_even_if_exists=False, filename_prefix=''): if VERBOSE: print('download_file(url=' + url + ', dstpath=' + dstpath + ')') file_name = filename_prefix + url.split('/')[-1] if path_points_to_directory(dstpath): @@ -519,19 +571,22 @@ def download_file(url, dstpath, download_even_if_exists=False, filename_prefix = except KeyboardInterrupt as e: print("Aborted by User, exiting") rmfile(file_name) - exit(1) + sys.exit(1) return file_name + def download_text_file(url, dstpath, download_even_if_exists=False, filename_prefix=''): filename = download_file(url, dstpath, download_even_if_exists, filename_prefix) fix_lineendings(os.path.join(emsdk_path(), filename)) + def run_get_output(cmd, cwd=None): if VERBOSE: print('run_get_output(cmd=' + str(cmd) + ', cwd=' + str(cwd) + ')') process = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, env=os.environ.copy(), universal_newlines=True) (stdout, stderr) = process.communicate() return (process.returncode, stdout, stderr) + # must_succeed: If false, the search is performed silently without printing out errors if not found. Empty string is returned if git is not found. # If true, the search is required to succeed, and the execution will terminate with sys.exit(1) if not found. def GIT(must_succeed=True): @@ -557,13 +612,15 @@ def GIT(must_succeed=True): sys.exit(1) return '' # Not found + def git_repo_version(repo_path): - (returncode, stdout, stderr) = run_get_output([GIT(), 'log', '-n', '1', '--pretty="%aD %H"'], cwd=repo_path) + returncode, stdout, stderr = run_get_output([GIT(), 'log', '-n', '1', '--pretty="%aD %H"'], cwd=repo_path) if returncode == 0: return stdout.strip() else: return "" + def git_clone(url, dstpath): if VERBOSE: print('git_clone(url=' + url + ', dstpath=' + dstpath + ')') if os.path.isdir(os.path.join(dstpath, '.git')): @@ -575,6 +632,7 @@ def git_clone(url, dstpath): git_clone_args += ['--depth', '1'] return run([GIT(), 'clone'] + git_clone_args + [url, dstpath]) == 0 + def git_checkout_and_pull(repo_path, branch): if VERBOSE: print('git_checkout_and_pull(repo_path=' + repo_path + ', branch=' + branch + ')') ret = run([GIT(), 'fetch', 'origin'], repo_path) @@ -586,7 +644,7 @@ def git_checkout_and_pull(repo_path, branch): # run([GIT, 'checkout', '-b', branch, '--track', 'origin/'+branch], repo_path) ret = run([GIT(), 'checkout', '--quiet', branch], repo_path) # this line assumes that the user has not gone and manually messed with the repo and added new remotes to ambiguate the checkout. if ret != 0: return False - ret = run([GIT(), 'merge', '--ff-only', 'origin/'+branch], repo_path) # this line assumes that the user has not gone and made local changes to the repo + ret = run([GIT(), 'merge', '--ff-only', 'origin/' + branch], repo_path) # this line assumes that the user has not gone and made local changes to the repo if ret != 0: return False except: print('git operation failed!') @@ -595,6 +653,7 @@ def git_checkout_and_pull(repo_path, branch): print("Current repository version: " + git_repo_version(repo_path)) return True + def git_clone_checkout_and_pull(url, dstpath, branch): if VERBOSE: print('git_clone_checkout_and_pull(url=' + url + ', dstpath=' + dstpath + ', branch=' + branch + ')') success = git_clone(url, dstpath) @@ -603,6 +662,7 @@ def git_clone_checkout_and_pull(url, dstpath, branch): success = git_checkout_and_pull(dstpath, branch) return success + # Each tool can have its own build type, or it can be overridden on the command line. def decide_cmake_build_type(tool): global CMAKE_BUILD_TYPE_OVERRIDE @@ -611,6 +671,7 @@ def decide_cmake_build_type(tool): else: return tool.cmake_build_type + # The root directory of the build. def fastcomp_build_dir(tool): generator_suffix = '' @@ -629,10 +690,12 @@ def fastcomp_build_dir(tool): build_dir = 'build_' + tool.version + generator_suffix + bitness_suffix return build_dir + def exe_suffix(filename): if WINDOWS and not filename.endswith('.exe'): return filename + '.exe' else: return filename + # The directory where the binaries are produced. (relative to the installation root directory of the tool) def fastcomp_build_bin_dir(tool): build_dir = fastcomp_build_dir(tool) @@ -654,6 +717,7 @@ def fastcomp_build_bin_dir(tool): else: return os.path.join(build_dir, 'bin') + def build_env(generator): build_env = os.environ.copy() @@ -687,6 +751,7 @@ def build_env(generator): return build_env + def get_generator_for_sln_file(sln_file): contents = open(sln_file, 'r').read() if '# Visual Studio 15' in contents: @@ -697,6 +762,7 @@ def get_generator_for_sln_file(sln_file): return 'Visual Studio 12' raise Exception('Unknown generator used to build solution file ' + sln_file) + def find_msbuild(sln_file): # The following logic attempts to find a Visual Studio version specific MSBuild.exe from a list of known locations. This logic # exists because it was detected that when multiple Visual Studio versions exist (VS2013 & VS2015), their MSBuild.exes might not @@ -704,13 +770,13 @@ def find_msbuild(sln_file): # Ideally would be able to do "cmake --build path/to/cmake/build/directory --config Debug|RelWithDebInfo|MinSizeRel|Release" across # all platforms, but around VS2013 era this did not work. This could be reattempted when support for VS 2015 is dropped. search_paths_vs2015 = [os.path.join(os.environ['ProgramFiles'], 'MSBuild/14.0/Bin/amd64'), - os.path.join(os.environ['ProgramFiles(x86)'], 'MSBuild/14.0/Bin/amd64'), - os.path.join(os.environ['ProgramFiles'], 'MSBuild/14.0/Bin'), - os.path.join(os.environ['ProgramFiles(x86)'], 'MSBuild/14.0/Bin')] + os.path.join(os.environ['ProgramFiles(x86)'], 'MSBuild/14.0/Bin/amd64'), + os.path.join(os.environ['ProgramFiles'], 'MSBuild/14.0/Bin'), + os.path.join(os.environ['ProgramFiles(x86)'], 'MSBuild/14.0/Bin')] search_paths_vs2013 = [os.path.join(os.environ['ProgramFiles'], 'MSBuild/12.0/Bin/amd64'), - os.path.join(os.environ['ProgramFiles(x86)'], 'MSBuild/12.0/Bin/amd64'), - os.path.join(os.environ['ProgramFiles'], 'MSBuild/12.0/Bin'), - os.path.join(os.environ['ProgramFiles(x86)'], 'MSBuild/12.0/Bin')] + os.path.join(os.environ['ProgramFiles(x86)'], 'MSBuild/12.0/Bin/amd64'), + os.path.join(os.environ['ProgramFiles'], 'MSBuild/12.0/Bin'), + os.path.join(os.environ['ProgramFiles(x86)'], 'MSBuild/12.0/Bin')] search_paths_old = [os.path.join(os.environ["WINDIR"], 'Microsoft.NET/Framework/v4.0.30319')] generator = get_generator_for_sln_file(sln_file) if VERBOSE: @@ -735,6 +801,7 @@ def find_msbuild(sln_file): print('MSBuild.exe in PATH? ' + str(which('MSBuild.exe'))) return which('MSBuild.exe') # Last fallback, try any MSBuild from PATH (might not be compatible, but best effort) + def make_build(build_root, build_type, build_target_platform='x64'): if VERBOSE: print('make_build(build_root=' + build_root + ', build_type=' + build_type + ', build_target_platform=' + build_target_platform + ')') global CPU_CORES @@ -749,11 +816,11 @@ def make_build(build_root, build_type, build_target_platform='x64'): if 'Visual Studio' in CMAKE_GENERATOR: solution_name = str(subprocess.check_output(['dir', '/b', '*.sln'], shell=True, cwd=build_root).decode('utf-8').strip()) generator_to_use = get_generator_for_sln_file(os.path.join(build_root, solution_name)) -# Disabled for now: Don't pass /maxcpucount argument to msbuild, since it looks like when building, msbuild already automatically spawns the full amount of logical -# cores the system has, and passing the number of logical cores here has been observed to give a quadratic N*N explosion on the number of spawned processes -# (e.g. on a Core i7 5960X with 16 logical cores, it would spawn 16*16=256 cl.exe processes, which would start crashing when running out of system memory) -# make = [find_msbuild(os.path.join(build_root, solution_name)), '/maxcpucount:' + str(CPU_CORES), '/t:Build', '/p:Configuration='+build_type, '/nologo', '/verbosity:minimal', solution_name] - make = [find_msbuild(os.path.join(build_root, solution_name)), '/t:Build', '/p:Configuration='+build_type, '/p:Platform='+build_target_platform, '/nologo', '/verbosity:minimal', solution_name] + # Disabled for now: Don't pass /maxcpucount argument to msbuild, since it looks like when building, msbuild already automatically spawns the full amount of logical + # cores the system has, and passing the number of logical cores here has been observed to give a quadratic N*N explosion on the number of spawned processes + # (e.g. on a Core i7 5960X with 16 logical cores, it would spawn 16*16=256 cl.exe processes, which would start crashing when running out of system memory) + # make = [find_msbuild(os.path.join(build_root, solution_name)), '/maxcpucount:' + str(CPU_CORES), '/t:Build', '/p:Configuration=' + build_type, '/nologo', '/verbosity:minimal', solution_name] + make = [find_msbuild(os.path.join(build_root, solution_name)), '/t:Build', '/p:Configuration=' + build_type, '/p:Platform=' + build_target_platform, '/nologo', '/verbosity:minimal', solution_name] else: make = ['mingw32-make', '-j' + str(CPU_CORES)] else: @@ -775,20 +842,23 @@ def make_build(build_root, build_type, build_target_platform='x64'): return True -def cmake_configure(generator, build_root, src_root, build_type, extra_cmake_args = []): + +def cmake_configure(generator, build_root, src_root, build_type, extra_cmake_args=[]): if VERBOSE: print('cmake_configure(generator=' + str(generator) + ', build_root=' + str(build_root) + ', src_root=' + str(src_root) + ', build_type=' + str(build_type) + ', extra_cmake_args=' + str(extra_cmake_args) + ')') # Configure if not os.path.isdir(build_root): os.mkdir(build_root) # Create build output directory if it doesn't yet exist. try: if generator: generator = ['-G', generator] else: generator = [] - cmdline = ['cmake'] + generator + ['-DCMAKE_BUILD_TYPE='+build_type, '-DPYTHON_EXECUTABLE='+sys.executable] + extra_cmake_args + [src_root] + cmdline = ['cmake'] + generator + ['-DCMAKE_BUILD_TYPE=' + build_type, '-DPYTHON_EXECUTABLE=' + sys.executable] + extra_cmake_args + [src_root] print('Running CMake: ' + str(cmdline)) + def quote_parens(x): if ' ' in x: return '"' + x.replace('"', '\\"') + '"' else: return x + open(os.path.join(build_root, 'recmake.' + ('bat' if WINDOWS else 'sh')), 'w').write(' '.join(map(quote_parens, cmdline))) # Create a file 'recmake.bat/sh' in the build root that user can call to manually recmake the build tree with the previous build params ret = subprocess.check_call(cmdline, cwd=build_root, env=build_env(CMAKE_GENERATOR)) if ret != 0: @@ -815,12 +885,14 @@ def cmake_configure(generator, build_root, src_root, build_type, extra_cmake_arg return True + def xcode_sdk_version(): try: return subprocess.check_output(['xcrun', '--show-sdk-version']).strip().split('.') except: return subprocess.checkplatform.mac_ver()[0].split('.') + def build_llvm_tool(tool): if VERBOSE: print('build_llvm_tool(' + str(tool) + ')') fastcomp_root = tool.installation_path() @@ -870,7 +942,7 @@ def build_llvm_tool(tool): # MacOS < 10.13 workaround for LLVM build bug https://github.com/kripken/emscripten/issues/5418: # specify HAVE_FUTIMENS=0 in the build if building with target SDK that is older than 10.13. - if OSX and (not os.environ.get('LLVM_CMAKE_ARGS') or not 'HAVE_FUTIMENS' in os.environ.get('LLVM_CMAKE_ARGS')) and xcode_sdk_version() < [10,13]: + if OSX and (not os.environ.get('LLVM_CMAKE_ARGS') or 'HAVE_FUTIMENS' not in os.environ.get('LLVM_CMAKE_ARGS')) and xcode_sdk_version() < [10, 13]: print('Passing -DHAVE_FUTIMENS=0 to LLVM CMake configure to workaround https://github.com/kripken/emscripten/issues/5418. Please update to macOS 10.13 or newer') args += ['-DHAVE_FUTIMENS=0'] @@ -881,6 +953,7 @@ def build_llvm_tool(tool): success = make_build(build_root, build_type, 'x64' if tool.bitness == 64 else 'Win32') return success + # Emscripten asm.js optimizer build scripts: def optimizer_build_root(tool): build_root = tool.installation_path().strip() @@ -889,6 +962,7 @@ def optimizer_build_root(tool): build_root = build_root + generator_prefix + '_' + str(tool.bitness) + 'bit_optimizer' return build_root + def uninstall_optimizer(tool): if VERBOSE: print('uninstall_optimizer(' + str(tool) + ')') build_root = optimizer_build_root(tool) @@ -899,10 +973,12 @@ def uninstall_optimizer(tool): except: pass + def is_optimizer_installed(tool): build_root = optimizer_build_root(tool) return os.path.exists(build_root) + def build_optimizer_tool(tool): if VERBOSE: print('build_optimizer_tool(' + str(tool) + ')') src_root = os.path.join(tool.installation_path(), 'tools', 'optimizer') @@ -929,6 +1005,7 @@ def binaryen_build_root(tool): build_root = build_root + generator_prefix + '_' + str(tool.bitness) + 'bit_binaryen' return build_root + def uninstall_binaryen(tool): if VERBOSE: print('uninstall_binaryen(' + str(tool) + ')') build_root = binaryen_build_root(tool) @@ -939,10 +1016,12 @@ def uninstall_binaryen(tool): except: pass + def is_binaryen_installed(tool): build_root = binaryen_build_root(tool) return os.path.exists(build_root) + def build_binaryen_tool(tool): if VERBOSE: print('build_binaryen_tool(' + str(tool) + ')') src_root = tool.installation_path() @@ -972,7 +1051,7 @@ def build_binaryen_tool(tool): return success -def download_and_unzip(zipfile, dest_dir, download_even_if_exists=False, filename_prefix = ''): +def download_and_unzip(zipfile, dest_dir, download_even_if_exists=False, filename_prefix=''): if VERBOSE: print('download_and_unzip(zipfile=' + zipfile + ', dest_dir=' + dest_dir + ')') if not download_even_if_exists and num_files_in_directory(dest_dir) > 0: print("The contents of file '" + zipfile + "' already exist in destination '" + dest_dir + "', skipping.") @@ -985,12 +1064,14 @@ def download_and_unzip(zipfile, dest_dir, download_even_if_exists=False, filenam else: return untargz(dst_file, dest_dir, unpack_even_if_exists=download_even_if_exists) + def to_native_path(p): if WINDOWS and not MSYS: return to_unix_path(p).replace('/', '\\') else: return to_unix_path(p) + # Finds and returns a list of the directories that need to be added to PATH for the given set of tools. def get_required_path(active_tools): path_add = [to_native_path(emsdk_path())] @@ -999,23 +1080,27 @@ def get_required_path(active_tools): path_add += [to_native_path(tool.expand_vars(tool.activated_path))] return path_add + # Returns the absolute path to the file '.emscripten' for the current user on this system. def dot_emscripten_path(): return os.path.join(emscripten_config_directory, ".emscripten") + dot_emscripten = {} + def parse_key_value(line): if not line: return ('', '') eq = line.find('=') if eq != -1: key = line[0:eq].strip() - value = line[eq+1:].strip() + value = line[eq + 1:].strip() return (key, value) else: return (key, '') + def load_dot_emscripten(): global dot_emscripten dot_emscripten = {} @@ -1033,6 +1118,7 @@ def load_dot_emscripten(): except: pass + def generate_dot_emscripten(active_tools): global emscripten_config_directory if emscripten_config_directory == emsdk_path(): @@ -1107,12 +1193,13 @@ JS_ENGINES = [NODE_JS] path_add = get_required_path(active_tools) if not WINDOWS: emsdk_env = os.path.relpath(sdk_path('emsdk_env.sh')) - if not '/' in emsdk_env: + if '/' not in emsdk_env: emsdk_env = './emsdk_env.sh' print("To conveniently access the selected set of tools from the command line, consider adding the following directories to PATH, or call 'source " + emsdk_env + "' to do this for you.") print('') print(' ' + ENVPATH_SEPARATOR.join(path_add)) + def find_msbuild_dir(): if 'ProgramFiles' in os.environ and os.environ['ProgramFiles']: program_files = os.environ['ProgramFiles'] @@ -1131,13 +1218,15 @@ def find_msbuild_dir(): else: return '' # No MSbuild installed. + def get_installed_vstool_version(installed_path): try: return open(installed_path + "/version.txt", "r").read() except: return None -class Tool: + +class Tool(object): def __init__(self, data): # Convert the dictionary representation of the tool in 'data' to members of this class for convenience. for key in data: @@ -1252,22 +1341,24 @@ class Tool: if hasattr(self, 'uses'): for tool_name in self.uses: tool = find_tool(tool_name) - if tool == None: + if tool is None: print("Manifest error: No tool by name '" + tool_name + "' found! This may indicate an internal SDK error!") return False if not tool.is_installed(): return False - if self.download_url() != None: + if self.download_url() is not None: # For e.g. fastcomp clang from git repo, the activated PATH is the directory where the compiler is built to, and installation_path is # the directory where the source tree exists. To distinguish between multiple packages sharing the same source # (clang-master-32bit, clang-master-64bit, clang-incoming-32bit and clang-incoming-64bit each share the same git repo), require # that in addition to the installation directory, each item in the activated PATH must exist. activated_path = self.expand_vars(self.activated_path).split(';') if hasattr(self, 'activated_path') else [self.installation_path()] + def each_path_exists(pathlist): for path in pathlist: if not os.path.exists(path): return False return True + content_exists = os.path.exists(self.installation_path()) and each_path_exists(activated_path) and (os.path.isfile(self.installation_path()) or num_files_in_directory(self.installation_path()) > 0) if self.id == 'vs-tool': # vs-tool is a special tool since all versions must be installed to the same dir, so dir name will not differentiate the version. @@ -1302,7 +1393,7 @@ class Tool: for cfg in activated_cfg: cfg = cfg.strip() (key, value) = parse_key_value(cfg) - if not key in dot_emscripten: + if key not in dot_emscripten: if VERBOSE: print(str(self) + ' is not active, because key="' + key + '" does not exist in .emscripten') return False @@ -1317,8 +1408,8 @@ class Tool: def is_env_active(self): envs = self.activated_environment() for env in envs: - (key, value) = parse_key_value(env) - if not key in os.environ or to_unix_path(os.environ[key]) != to_unix_path(value): + key, value = parse_key_value(env) + if key not in os.environ or to_unix_path(os.environ[key]) != to_unix_path(value): if VERBOSE: print(str(self) + ' is not active, because environment variable key="' + key + '" has value "' + str(os.getenv(key)) + '" but should have value "' + value + '"') return False @@ -1336,7 +1427,7 @@ class Tool: if WINDOWS: envs = self.activated_environment() for env in envs: - (key, value) = parse_key_value(env) + key, value = parse_key_value(env) if permanently_activate: win_delete_environment_variable(key, False) # If there is an env var for the LOCAL USER with same name, it will hide the system var, so must remove that first. @@ -1370,7 +1461,7 @@ class Tool: return None def install(self): - if self.can_be_installed() != True: + if not self.can_be_installed(): print("The tool '" + str(self) + "' is not available due to the reason: " + self.can_be_installed()) return False @@ -1378,7 +1469,7 @@ class Tool: print("Installing SDK '" + str(self) + "'..") for tool_name in self.uses: tool = find_tool(tool_name) - if tool == None: + if tool is None: print("Manifest error: No tool by name '" + tool_name + "' found! This may indicate an internal SDK error!") success = tool.install() if not success: @@ -1434,9 +1525,12 @@ class Tool: return print("Uninstalling tool '" + str(self) + "'..") if hasattr(self, 'custom_uninstall_script'): - if self.custom_uninstall_script == 'uninstall_optimizer': uninstall_optimizer(self) - elif self.custom_uninstall_script == 'uninstall_binaryen': uninstall_binaryen(self) - else: raise Exception('Unknown custom_uninstall_script directive "' + custom_uninstall_script + '"!') + if self.custom_uninstall_script == 'uninstall_optimizer': + uninstall_optimizer(self) + elif self.custom_uninstall_script == 'uninstall_binaryen': + uninstall_binaryen(self) + else: + raise Exception('Unknown custom_uninstall_script directive "' + self.custom_uninstall_script + '"!') try: print("Deleting path '" + self.installation_path() + "'") remove_tree(self.installation_path()) @@ -1467,59 +1561,70 @@ class Tool: deps += tool.recursive_dependencies() return deps + # A global registry of all known Emscripten SDK tools available in the SDK manifest. tools = [] tools_map = {} + def add_tool(tool): tool.is_sdk = False tools.append(tool) if find_tool(str(tool)): raise Exception('Duplicate tool ' + str(tool) + '! Existing:\n{' + ', '.join("%s: %s" % item for item in vars(find_tool(str(tool))).items()) + '}, New:\n{' + ', '.join("%s: %s" % item for item in vars(tool).items()) + '}') tools_map[str(tool)] = tool + # A global registry of all known SDK toolsets. sdks = [] sdks_map = {} + def add_sdk(sdk): sdk.is_sdk = True sdks.append(sdk) if find_sdk(str(sdk)): raise Exception('Duplicate sdk ' + str(sdk) + '! Existing:\n{' + ', '.join("%s: %s" % item for item in vars(find_sdk(str(sdk))).items()) + '}, New:\n{' + ', '.join("%s: %s" % item for item in vars(sdk).items()) + '}') sdks_map[str(sdk)] = sdk + # N.B. In both tools and sdks list above, we take the convention that the newest items are at the back of the list (ascending chronological order) def find_tool(name): if name in tools_map: return tools_map[name] return None + def find_sdk(name): if name in sdks_map: return sdks_map[name] return None + def is_os_64bit(): # http://stackoverflow.com/questions/2208828/detect-64bit-os-windows-in-python return platform.machine().endswith('64') + def find_latest_32bit_sdk(): for sdk in reversed(sdks): # Newest SDK is always at the end of the list. if not hasattr(sdk, 'bitness') or sdk.bitness == 32: # If no 'bitness' field, it means the SDK is universal. - if not 'nightly' in sdk.version: + if 'nightly' not in sdk.version: return sdk return None + def find_latest_64bit_sdk(): for sdk in reversed(sdks): # Newest SDK is always at the end of the list. if not hasattr(sdk, 'bitness') or sdk.bitness == 64: # If no 'bitness' field, it means the SDK is universal. - if not 'nightly' in sdk.version: + if 'nightly' not in sdk.version: return sdk return None + def find_latest_sdk(): if is_os_64bit(): return find_latest_64bit_sdk() else: return find_latest_32bit_sdk() + def find_latest_nightly_32bit_sdk(): for sdk in reversed(sdks): # Newest SDK is always at the end of the list. if not hasattr(sdk, 'bitness') or sdk.bitness == 32: # If no 'bitness' field, it means the SDK is universal. @@ -1527,6 +1632,7 @@ def find_latest_nightly_32bit_sdk(): return sdk return None + def find_latest_nightly_64bit_sdk(): for sdk in reversed(sdks): # Newest SDK is always at the end of the list. if not hasattr(sdk, 'bitness') or sdk.bitness == 64: # If no 'bitness' field, it means the SDK is universal. @@ -1534,12 +1640,14 @@ def find_latest_nightly_64bit_sdk(): return sdk return None + def find_latest_nightly_sdk(): if is_os_64bit(): return find_latest_nightly_64bit_sdk() else: return find_latest_nightly_32bit_sdk() + def find_latest_waterfall_sdk(which): waterfall_lkgr = load_waterfall_lkgr() if not waterfall_lkgr: @@ -1547,12 +1655,15 @@ def find_latest_waterfall_sdk(which): sys.exit(1) return 'sdk-%s-%s-64bit' % (which, waterfall_lkgr[0]) + def find_latest_upstream_sdk(): return find_latest_waterfall_sdk('upstream') + def find_latest_fastcomp_sdk(): return find_latest_waterfall_sdk('fastcomp') + # Finds the best-matching python tool for use. def find_used_python(): for t in reversed(tools): # Find newest tool first - those are always at the end of the list. @@ -1566,9 +1677,11 @@ def find_used_python(): return t return None + def version_key(ver): return list(map(int, re.split('[._-]', ver))) + # A sort function that is compatible with both Python 2 and Python 3 using a custom comparison function. def python_2_3_sorted(arr, cmp): if sys.version_info >= (3,): @@ -1576,6 +1689,7 @@ def python_2_3_sorted(arr, cmp): else: return sorted(arr, cmp=cmp) + def fetch_emscripten_tags(): git = GIT(must_succeed=False) @@ -1622,6 +1736,7 @@ def fetch_emscripten_tags(): if WINDOWS: return 'win' if LINUX: return 'linux' if OSX: return 'osx' + def os_name_for_emscripten_location(): if WINDOWS: return 'win' else: return 'linux' @@ -1652,9 +1767,11 @@ def fetch_emscripten_tags(): print("If you are not looking to build Emscripten from source, you can safely ignore this message.") return + def is_emsdk_sourced_from_github(): return os.path.exists(os.path.join(emsdk_path(), '.git')) + def update_emsdk(): 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) @@ -1670,6 +1787,7 @@ def update_emsdk(): print('Unsupported OS, cannot update!') fetch_emscripten_tags() + # Lists all tagged versions directly in the Git repositories. These we can pull and compile from source. def load_emscripten_tags(): try: @@ -1677,20 +1795,24 @@ def load_emscripten_tags(): except: return [] + def load_binaryen_tags(): try: return open(sdk_path('binaryen-tags.txt'), 'r').read().split('\n') except: return [] + def remove_prefix(s, prefix): if s.startswith(prefix): return s[len(prefix):] else: return s + def remove_suffix(s, suffix): - if s.endswith(suffix): return s[:len(s)-len(suffix)] + if s.endswith(suffix): return s[:len(s) - len(suffix)] else: return s + # filename should be one of: 'llvm-nightlies-32bit.txt', 'llvm-nightlies-64bit.txt', 'llvm-precompiled-tags-32bit.txt', 'llvm-precompiled-tags-64bit.txt', 'emscripten-nightlies.txt' def load_file_index_list(filename): try: @@ -1705,25 +1827,32 @@ def load_file_index_list(filename): except: return [] + def load_llvm_32bit_nightlies(): return load_file_index_list('llvm-nightlies-32bit.txt') + def load_llvm_64bit_nightlies(): return load_file_index_list('llvm-nightlies-64bit.txt') + def load_emscripten_nightlies(): return load_file_index_list('emscripten-nightlies.txt') + def load_llvm_precompiled_tags_32bit(): return load_file_index_list('llvm-tags-32bit.txt') + def load_llvm_precompiled_tags_64bit(): return load_file_index_list('llvm-tags-64bit.txt') + def download_waterfall_lkgr(): lkgr_url = 'https://storage.googleapis.com/wasm-llvm/builds/linux/lkgr.json' download_file(lkgr_url, 'upstream', download_even_if_exists=True) + def load_waterfall_lkgr(): try: text = open(sdk_path(os.path.join('upstream', 'lkgr.json')), 'r').read() @@ -1735,10 +1864,13 @@ def load_waterfall_lkgr(): print(str(e)) return [] + def is_string(s): - if (sys.version_info[0] >= 3): return isinstance(s, str) + if sys.version_info[0] >= 3: + return isinstance(s, str) return isinstance(s, basestring) + def load_sdk_manifest(): global tools, sdks try: @@ -1849,12 +1981,14 @@ def load_sdk_manifest(): else: add_sdk(sdk) + # Tests if the two given tools can be active at the same time. # Currently only a simple check for name for same tool with different versions, # possibly adds more logic in the future. def can_simultaneously_activate(tool1, tool2): return tool1.id != tool2.id + def remove_nonexisting_tools(tool_list, log_errors=True): i = 0 while i < len(tool_list): @@ -1867,6 +2001,7 @@ def remove_nonexisting_tools(tool_list, log_errors=True): i += 1 return tool_list + # Expands dependencies for each tool, and removes ones that don't exist. def process_tool_list(tools_to_activate, log_errors=True): i = 0 @@ -1875,7 +2010,7 @@ def process_tool_list(tools_to_activate, log_errors=True): tool = tools_to_activate[i] deps = tool.recursive_dependencies() tools_to_activate = tools_to_activate[:i] + deps + tools_to_activate[i:] - i += len(deps)+1 + i += len(deps) + 1 tools_to_activate = remove_nonexisting_tools(tools_to_activate, log_errors=log_errors) @@ -1894,6 +2029,7 @@ def process_tool_list(tools_to_activate, log_errors=True): i += 1 return tools_to_activate + # Reconfigure .emscripten to choose the currently activated toolset, set PATH and other environment variables. # Returns the full list of deduced tools that are now active. def set_active_tools(tools_to_activate, permanently_activate): @@ -1923,12 +2059,14 @@ def set_active_tools(tools_to_activate, permanently_activate): print('') return tools_to_activate + def currently_active_sdk(): for sdk in reversed(sdks): if sdk.is_active(): return sdk return None + def currently_active_tools(): active_tools = [] for tool in tools: @@ -1936,11 +2074,13 @@ def currently_active_tools(): active_tools += [tool] return active_tools + # http://stackoverflow.com/questions/480214/how-do-you-remove-duplicates-from-a-list-in-python-whilst-preserving-order def unique_items(seq): seen = set() seen_add = seen.add - return [ x for x in seq if x not in seen and not seen_add(x)] + return [x for x in seq if x not in seen and not seen_add(x)] + # Tests if a path is contained in the given list, but with separators normalized. def normalized_contains(lst, elem): @@ -1950,6 +2090,7 @@ def normalized_contains(lst, elem): return True return False + def to_msys_path(p): p = to_unix_path(p) new_path = re.sub(r'([a-zA-Z]):/(.*)', r'/\1/\2', p) @@ -1957,6 +2098,7 @@ def to_msys_path(p): new_path = new_path[0] + new_path[1].lower() + new_path[2:] return new_path + # Looks at the current PATH and adds and removes entries so that the PATH reflects # the set of given active tools. def adjusted_path(tools_to_activate, log_additions=False, system_path_only=False): @@ -1998,6 +2140,7 @@ def adjusted_path(tools_to_activate, log_additions=False, system_path_only=False return ((':' if MSYS else ENVPATH_SEPARATOR).join(whole_path), new_emsdk_tools) + def construct_env(tools_to_activate, permanent): global emscripten_config_directory env_string = '' @@ -2025,11 +2168,11 @@ def construct_env(tools_to_activate, permanent): env_vars_to_add += [('EMSDK', to_unix_path(emsdk_path()))] em_config_path = os.path.normpath(dot_emscripten_path()) - if not 'EM_CONFIG' in os.environ or to_unix_path(os.environ['EM_CONFIG']) != to_unix_path(em_config_path): + if 'EM_CONFIG' not in os.environ or to_unix_path(os.environ['EM_CONFIG']) != to_unix_path(em_config_path): env_vars_to_add += [('EM_CONFIG', em_config_path)] if emscripten_config_directory == emsdk_path(): em_cache_dir = sdk_path('.emscripten_cache') - if not 'EM_CACHE' in os.environ or to_unix_path(os.environ['EM_CACHE']) != to_unix_path(em_cache_dir): + if 'EM_CACHE' not in os.environ or to_unix_path(os.environ['EM_CACHE']) != to_unix_path(em_cache_dir): env_vars_to_add += [('EM_CACHE', em_cache_dir)] mkdir_p(em_cache_dir) @@ -2038,7 +2181,7 @@ def construct_env(tools_to_activate, permanent): for env in envs: (key, value) = parse_key_value(env) value = to_native_path(tool.expand_vars(value)) - if not key in os.environ or to_unix_path(os.environ[key]) != to_unix_path(value): # Don't set env. vars which are already set to the correct value. + if key not in os.environ or to_unix_path(os.environ[key]) != to_unix_path(value): # Don't set env. vars which are already set to the correct value. env_vars_to_add += [(key, value)] if len(env_vars_to_add) > 0: @@ -2057,12 +2200,14 @@ def construct_env(tools_to_activate, permanent): print('') return env_string + def silentremove(filename): try: os.remove(filename) except OSError as e: if e.errno != errno.ENOENT: raise + def main(): global emscripten_config_directory, BUILD_FOR_TESTING, ENABLE_LLVM_ASSERTIONS, TTY_OUTPUT @@ -2183,8 +2328,8 @@ def main(): which are Release for the 'master' SDK, and RelWithDebInfo for the 'incoming' SDK.''') return 1 - - # Extracts a boolean command line argument from sys.argv and returns True if it was present + + # Extracts a boolean command line argument from sys.argv and returns True if it was present def extract_bool_arg(name): old_argv = sys.argv sys.argv = list(filter(lambda a: a != name, sys.argv)) @@ -2265,7 +2410,7 @@ def main(): for tool in t: if tool.is_old and not arg_old: continue - if tool.can_be_installed() == True: + if tool.can_be_installed(): installed = '\tINSTALLED' if tool.is_installed() else '' else: installed = '\tNot available: ' + tool.can_be_installed() @@ -2332,7 +2477,8 @@ def main(): tools_to_activate = process_tool_list(tools_to_activate, log_errors=True) env_string = construct_env(tools_to_activate, len(sys.argv) >= 3 and 'perm' in sys.argv[2]) open(EMSDK_SET_ENV, 'w').write(env_string) - if LINUX or OSX: os.chmod(EMSDK_SET_ENV, 0o755) + if LINUX or OSX: + os.chmod(EMSDK_SET_ENV, 0o755) return 0 elif cmd == 'update': update_emsdk() @@ -2362,9 +2508,9 @@ def main(): tools_to_activate = currently_active_tools() for i in range(2, len(sys.argv)): tool = find_tool(sys.argv[i]) - if tool == None: + if tool is None: tool = find_sdk(sys.argv[i]) - if tool == None: + if tool is None: print("Error: No tool or SDK found by name '" + sys.argv[i] + "'.") return 1 tools_to_activate += [tool] @@ -2413,9 +2559,9 @@ def main(): return 1 for t in sys.argv[2:]: tool = find_tool(t) - if tool == None: + if tool is None: tool = find_sdk(t) - if tool == None: + if tool is None: print("Error: No tool or SDK found by name '" + t + "'.") return 1 success = tool.install() @@ -2426,7 +2572,7 @@ def main(): print("Syntax error. Call 'emsdk uninstall '. Call 'emsdk list' to obtain a list of available tools.") return 1 tool = find_tool(sys.argv[2]) - if tool == None: + if tool is None: print("Error: Tool by name '" + sys.argv[2] + "' was not found.") return 1 tool.uninstall() @@ -2434,5 +2580,6 @@ def main(): print("Unknown command '" + cmd + "' given! Type 'emsdk help' to get a list of commands.") return 1 + if __name__ == '__main__': sys.exit(main())