2013-09-05 16:42:27 +03:00
#!/usr/bin/env python
2015-03-31 15:44:34 +02:00
from __future__ import print_function
2015-04-12 17:04:46 +03:00
import sys, optparse, subprocess, os, os.path, errno, zipfile, string, json, platform, shutil, tarfile, tempfile, multiprocessing, re, stat
2015-03-31 15:44:34 +02:00
if sys.version_info >= (3,):
from urllib.parse import urljoin
from urllib.request import urlopen
from urllib.error import HTTPError
else:
from urlparse import urljoin
from urllib2 import urlopen, HTTPError
2013-09-05 16:42:27 +03:00
2013-09-05 16:54:15 +03:00
# 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.
2013-09-05 16:42:27 +03:00
EMSDK_DEV = bool(os.getenv('EMSDK_DEV')) if os.getenv('EMSDK_DEV') != None else False
2013-09-05 16:54:15 +03:00
2014-07-03 13:43:37 +03:00
if EMSDK_DEV:
2015-03-31 15:44:34 +02:00
print('EMSDK_DEV active.')
2013-09-05 16:42:27 +03:00
emsdk_master_server = 'http://clb.demon.fi/emscripten_dev/'
else:
2013-09-30 13:40:08 +03:00
emsdk_master_server = 'https://s3.amazonaws.com/mozilla-games/emscripten/'
2013-09-30 14:02:58 +03:00
2015-03-31 15:44:34 +02:00
emsdk_packages_url = urljoin(emsdk_master_server, 'packages/')
2013-09-30 14:02:58 +03:00
2013-09-05 16:42:27 +03:00
emscripten_git_repo = 'git@github.com:kripken/emscripten.git'
WINDOWS = False
if os.name == 'nt':
WINDOWS = True
ENVPATH_SEPARATOR = ';'
LINUX = False
if platform.system() == 'Linux':
LINUX = True
ENVPATH_SEPARATOR = ':'
OSX = False
if platform.mac_ver()[0] != '':
OSX = True
ENVPATH_SEPARATOR = ':'
2015-04-08 15:52:36 +03:00
CPU_CORES = max(multiprocessing.cpu_count()-1, 1) # Don't saturate all cores to not steal the whole system, but be aggressive.
2015-04-08 17:14:33 +03:00
CMAKE_BUILD_TYPE_OVERRIDE = None
2015-01-23 16:21:21 +02:00
emscripten_config_directory = os.path.expanduser("~/")
2014-11-18 15:24:32 +02:00
EMSDK_SET_ENV = 'emsdk_set_env.bat' if WINDOWS else 'emsdk_set_env.sh'
2015-01-12 17:58:16 +02:00
CMAKE_GENERATOR = 'Unix Makefiles'
if WINDOWS:
build_with_visualstudio = True
if build_with_visualstudio:
CMAKE_GENERATOR = 'Visual Studio 12'
else:
CMAKE_GENERATOR += 'MinGW Makefiles'
2015-04-12 17:04:46 +03:00
# Removes a directory tree even if it was readonly, and doesn't throw exception on failure.
def remove_tree(d):
try:
def remove_readonly_and_try_again(func, path, exc_info):
if not (os.stat(path).st_mode & stat.S_IWRITE):
os.chmod(path, stat.S_IWRITE)
func(path)
else:
raise
shutil.rmtree(d, onerror=remove_readonly_and_try_again)
except:
pass
2014-04-24 00:57:59 +03:00
def win_get_environment_variable(key, system=True):
2014-07-03 17:56:57 +03:00
prev_path = os.environ['PATH']
2014-04-24 00:57:59 +03:00
try:
2014-07-03 17:56:57 +03:00
py = find_used_python()
if py:
py_path = to_native_path(py.expand_vars(py.activated_path))
os.environ['PATH'] = os.environ['PATH'] + ';' + py_path
import win32api, win32con
2014-04-24 00:57:59 +03:00
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.
folder = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER, 'Environment')
value = str(win32api.RegQueryValueEx(folder, key)[0])
2015-03-31 15:44:34 +02:00
except Exception as e:
2014-04-24 00:57:59 +03:00
if e[0] != 2: # 'The system cannot find the file specified.'
2015-03-31 15:44:34 +02:00
print('Failed to read environment variable ' + key + ':', file=sys.stderr)
print(str(e), file=sys.stderr)
2014-04-24 00:57:59 +03:00
win32api.RegCloseKey(folder)
2014-07-03 17:56:57 +03:00
os.environ['PATH'] = prev_path
2014-04-24 00:57:59 +03:00
return None
win32api.RegCloseKey(folder)
2014-07-03 17:56:57 +03:00
os.environ['PATH'] = prev_path
2014-04-24 00:57:59 +03:00
return value
def win_environment_variable_exists(key, system=True):
value = win_get_environment_variable(key, system)
return value != None and len(value) > 0
def win_get_active_environment_variable(key):
value = win_get_environment_variable(key, False)
if value != None:
return value
return win_get_environment_variable(key, True)
def win_set_environment_variable(key, value, system=True):
2015-04-08 16:07:17 +03:00
# print('set ' + str(key) + '=' + str(value) + ', in system=' + str(system), file=sys.stderr)
2014-04-24 00:57:59 +03:00
previous_value = win_get_environment_variable(key, system)
if previous_value == value:
return # No need to elevate UAC for nothing to set the same value, skip.
if not value:
try:
if system:
value = subprocess.call(['REG', 'DELETE', 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment', '/V', key, '/f'], stdout=subprocess.PIPE)
else:
value = subprocess.call(['REG', 'DELETE', 'HKCU\\Environment', '/V', key, '/f'], stdout=subprocess.PIPE)
2015-03-31 15:44:34 +02:00
except Exception as e:
2014-04-24 00:57:59 +03:00
return
return
try:
if system:
cmd = ['bin/elevate.exe', 'SETX', '/M']
else:
cmd = ['SETX']
retcode = subprocess.call(cmd + [key, value], stdout=subprocess.PIPE)
if retcode is not 0:
2015-03-31 15:44:34 +02:00
print('ERROR! Failed to set environment variable ' + key + '=' + value + '. You may need to set it manually.', file=sys.stderr)
except Exception as e:
print('ERROR! Failed to set environment variable ' + key + '=' + value + ':', file=sys.stderr)
print(str(e), file=sys.stderr)
print('You may need to set it manually.', file=sys.stderr)
2014-04-24 00:57:59 +03:00
def win_delete_environment_variable(key, system=True):
win_set_environment_variable(key, None, system)
2013-09-05 16:42:27 +03:00
# Returns the absolute pathname to the given path inside the Emscripten SDK.
2013-11-13 19:25:57 +02:00
def sdk_path(path):
if os.path.isabs(path):
return path
else:
return to_unix_path(os.path.join(os.path.dirname(os.path.realpath(__file__)), path))
2013-09-05 16:42:27 +03:00
def emsdk_path(): return to_unix_path(os.path.dirname(os.path.realpath(__file__)))
2013-09-05 19:15:32 +03:00
# 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')
2013-09-05 19:29:34 +03:00
open(filename, 'wb').write(text)
2013-09-05 19:15:32 +03:00
# 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')
2013-09-05 19:29:34 +03:00
open(filename, 'wb').write(text)
2013-09-05 19:15:32 +03:00
2013-10-28 13:14:21 +02:00
# Removes a single file, suppressing exceptions on failure.
def rmfile(filename):
try:
os.remove(filename)
except:
pass
2013-09-05 19:15:32 +03:00
def fix_lineendings(filename):
if WINDOWS:
file_to_crlf(filename)
else:
file_to_lf(filename)
2013-09-05 16:42:27 +03:00
# http://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python
def mkdir_p(path):
if os.path.exists(path):
return
try:
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(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):
process = subprocess.Popen(cmd, cwd=cwd, env=os.environ.copy())
process.communicate()
if process.returncode != 0:
2015-03-31 15:44:34 +02:00
print(str(cmd) + ' failed with error code ' + str(process.returncode) + '!')
2013-09-05 16:42:27 +03:00
return process.returncode
# http://pythonicprose.blogspot.fi/2009/10/python-extract-targz-archive.html
2013-09-30 14:16:46 +03:00
def untargz(source_filename, dest_dir, unpack_even_if_exists=False):
if not unpack_even_if_exists and num_files_in_directory(dest_dir) > 0:
2015-03-31 15:44:34 +02:00
print("File '" + source_filename + "' has already been unpacked, skipping.")
2013-09-05 16:42:27 +03:00
return True
2015-03-31 15:44:34 +02:00
print("Unpacking '" + source_filename + "' to '" + dest_dir + "'")
2013-09-05 16:42:27 +03:00
mkdir_p(dest_dir)
run(['tar', '-xvf', sdk_path(source_filename), '--strip', '1'], cwd=dest_dir)
#tfile = tarfile.open(source_filename, 'r:gz')
#tfile.extractall(dest_dir)
return True
# http://stackoverflow.com/questions/12886768/simple-way-to-unzip-file-in-python-on-all-oses
2013-09-30 14:27:20 +03:00
def unzip(source_filename, dest_dir, unpack_even_if_exists=False):
2013-09-30 14:16:46 +03:00
if not unpack_even_if_exists and num_files_in_directory(dest_dir) > 0:
2015-03-31 15:44:34 +02:00
print("File '" + source_filename + "' has already been unpacked, skipping.")
2013-09-05 16:42:27 +03:00
return True
2015-03-31 15:44:34 +02:00
print("Unpacking '" + source_filename + "' to '" + dest_dir + "'")
2013-09-05 16:42:27 +03:00
mkdir_p(dest_dir)
2013-10-28 17:49:40 +02:00
common_subdir = None
2013-11-19 15:26:45 +02:00
try:
with zipfile.ZipFile(source_filename) as zf:
# Implement '--strip 1' behavior to unzipping by testing if all the files in the zip reside in a common subdirectory, and if so,
# we move the output tree at the end of uncompression step.
for member in zf.infolist():
words = member.filename.split('/')
if len(words) > 1: # If there is a directory component?
if common_subdir == None:
common_subdir = words[0]
elif common_subdir != words[0]:
common_subdir = ''
break
unzip_to_dir = dest_dir
if common_subdir:
unzip_to_dir = os.path.join('/'.join(dest_dir.split('/')[:-1]), 'unzip_temp')
# Now do the actual decompress.
for member in zf.infolist():
# Path traversal defense copied from
# http://hg.python.org/cpython/file/tip/Lib/http/server.py#l789
words = member.filename.split('/')
path = unzip_to_dir
for word in words[:-1]:
drive, word = os.path.splitdrive(word)
head, word = os.path.split(word)
if word in (os.curdir, os.pardir, ''): continue
path = os.path.join(path, word)
zf.extract(member, unzip_to_dir)
if common_subdir:
try:
if os.path.exists(dest_dir):
2015-04-12 17:04:46 +03:00
remove_tree(dest_dir)
2013-11-19 15:26:45 +02:00
except:
pass
shutil.copytree(os.path.join(unzip_to_dir, common_subdir), dest_dir)
try:
2015-04-12 17:04:46 +03:00
remove_tree(unzip_to_dir)
2013-11-19 15:26:45 +02:00
except:
pass
2015-03-31 15:44:34 +02:00
except zipfile.BadZipfile as e:
print("Unzipping file '" + source_filename + "' failed due to reason: " + str(e) + "! Removing the corrupted zip file.")
2013-11-19 15:26:45 +02:00
rmfile(source_filename)
return False
2015-03-31 15:44:34 +02:00
except Exception as e:
print("Unzipping file '" + source_filename + "' failed due to reason: " + str(e))
2013-11-19 15:26:45 +02:00
return False
2013-10-28 17:49:40 +02:00
2013-09-05 16:42:27 +03:00
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):
if path == '.':
return True
last_slash = max(path.rfind('/'), path.rfind('\\'))
last_dot = path.rfind('.')
no_suffix = last_dot < last_slash or last_dot == -1
if no_suffix:
return True
suffix = path[last_dot:]
if suffix == '.exe' or suffix == '.zip': # Very simple logic for the only file suffixes used by emsdk downloader. Other suffixes, like 'clang-3.2' are treated as dirs.
return False
else:
return True
2013-09-30 14:27:20 +03:00
# On success, returns the filename on the disk pointing to the destination file that was produced
# On failure, returns None.
2013-09-05 16:42:27 +03:00
def download_file(url, dstpath, download_even_if_exists=False):
file_name = url.split('/')[-1]
if path_points_to_directory(dstpath):
file_name = os.path.join(dstpath, file_name)
else:
file_name = dstpath
2013-09-30 14:27:20 +03:00
2013-11-13 19:25:57 +02:00
# Treat all relative destination paths as relative to the SDK root directory, not the current working directory.
file_name = sdk_path(file_name)
2013-09-05 16:42:27 +03:00
if os.path.exists(file_name) and not download_even_if_exists:
2015-03-31 15:44:34 +02:00
print("File '" + file_name + "' already downloaded, skipping.")
2013-09-30 14:27:20 +03:00
return file_name
2013-09-05 16:52:01 +03:00
try:
2015-03-31 15:44:34 +02:00
u = urlopen(url)
2013-09-05 16:52:01 +03:00
mkdir_p(os.path.dirname(file_name))
2013-11-19 15:26:45 +02:00
with open(file_name, 'wb') as f:
meta = u.info()
file_size = int(meta.getheaders("Content-Length")[0])
2015-03-31 15:44:34 +02:00
print("Downloading: %s from %s Bytes: %s" % (file_name, url, file_size))
2013-11-19 15:26:45 +02:00
file_size_dl = 0
block_sz = 8192
while True:
buffer = u.read(block_sz)
if not buffer:
break
file_size_dl += len(buffer)
f.write(buffer)
status = r"%10d [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size)
status = status + chr(8)*(len(status)+1)
2015-03-31 15:44:34 +02:00
print(status, end=' ')
except HTTPError as e:
print("HTTP error with URL '" + url + "': " + str(e))
2013-11-19 15:26:45 +02:00
rmfile(file_name)
return None
2015-03-31 15:44:34 +02:00
except Exception as e:
print("Error downloading URL '" + url + "': " + str(e))
2013-11-19 15:26:45 +02:00
rmfile(file_name)
2013-09-30 14:27:20 +03:00
return None
return file_name
2013-09-05 16:42:27 +03:00
2013-09-05 19:15:32 +03:00
def download_text_file(url, dstpath, download_even_if_exists=False):
2013-09-30 14:27:20 +03:00
filename = download_file(url, dstpath, download_even_if_exists)
fix_lineendings(os.path.join(emsdk_path(), filename))
2013-09-05 19:15:32 +03:00
2013-09-05 16:42:27 +03:00
def run_get_output(cmd, cwd=None):
2015-03-31 16:40:12 +02:00
process = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, env=os.environ.copy(), universal_newlines=True)
2013-09-05 16:42:27 +03:00
(stdout, stderr) = process.communicate()
return (process.returncode, stdout, stderr)
2014-07-28 20:22:48 +03:00
# Finds the given executable 'program' in PATH. Operates like the Unix tool 'which'.
def which(program):
def is_exe(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
fpath, fname = os.path.split(program)
if fpath:
if is_exe(program):
return program
else:
for path in os.environ["PATH"].split(os.pathsep):
path = path.strip('"')
exe_file = os.path.join(path, program)
if is_exe(exe_file):
return exe_file
if WINDOWS and not '.' in fname:
if is_exe(exe_file + '.exe'):
return exe_file + '.exe'
if is_exe(exe_file + '.cmd'):
return exe_file + '.cmd'
if is_exe(exe_file + '.bat'):
return exe_file + '.bat'
return None
2014-09-07 05:43:14 -04:00
# 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):
# The order in the following is important, and specifies the preferred order of using the git tools.
# Primarily use git from emsdk if installed. If not, use system git.
gits = ['git/1.9.4/bin/git.exe', which('git')]
for git in gits:
try:
(ret, stdout, stderr) = run_get_output([git, '--version'])
if ret == 0:
return git
except:
pass
if must_succeed:
2013-09-05 16:42:27 +03:00
if WINDOWS:
2015-03-31 15:44:34 +02:00
print("ERROR: git executable was not found. Please install it by typing 'emsdk install git-1.9.4', or alternatively by installing it manually from http://git-scm.com/downloads . If you install git manually, remember to add it to PATH")
2014-09-07 05:43:14 -04:00
elif OSX:
2015-03-31 15:44:34 +02:00
print("ERROR: git executable was not found. Please install git for this operation! This can be done from http://git-scm.com/ , or by installing XCode and then the XCode Command Line Tools (see http://stackoverflow.com/questions/9329243/xcode-4-4-command-line-tools )")
2014-09-07 05:43:14 -04:00
elif LINUX:
2015-03-31 15:44:34 +02:00
print("ERROR: git executable was not found. Please install git for this operation! This can be probably be done using your package manager, see http://git-scm.com/book/en/Getting-Started-Installing-Git")
2014-09-07 05:43:14 -04:00
else:
2015-03-31 15:44:34 +02:00
print("ERROR: git executable was not found. Please install git for this operation!")
2013-09-05 16:42:27 +03:00
sys.exit(1)
2014-09-07 05:43:14 -04:00
return '' # Not found
2013-09-05 16:42:27 +03:00
def git_repo_version(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 os.path.isdir(os.path.join(dstpath, '.git')):
2015-03-31 15:44:34 +02:00
print("Repository '" + url + "' already cloned to directory '" + dstpath + "', skipping.")
2013-09-05 16:42:27 +03:00
return True
mkdir_p(dstpath)
return run([GIT(), 'clone', url, dstpath]) == 0
def git_checkout_and_pull(repo_path, branch):
run([GIT(), 'fetch', 'origin'], repo_path)
try:
2015-03-31 15:44:34 +02:00
print("Fetching latest changes to the branch '" + branch + "' for '" + repo_path + "'...")
2013-09-05 16:42:27 +03:00
run([GIT(), 'fetch', 'origin'], repo_path)
# run([GIT, 'checkout', '-b', branch, '--track', 'origin/'+branch], repo_path)
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.
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
except:
2015-03-31 15:44:34 +02:00
print('git operation failed!')
2013-09-05 16:42:27 +03:00
return False
2015-03-31 15:44:34 +02:00
print("Successfully updated and checked out branch '" + branch + "' on repository '" + repo_path + "'")
print("Current repository version: " + git_repo_version(repo_path))
2013-09-05 16:42:27 +03:00
return True
def git_clone_checkout_and_pull(url, dstpath, branch):
success = git_clone(url, dstpath)
if not success:
return False
success = git_checkout_and_pull(dstpath, branch)
return success
2015-04-08 17:14:33 +03:00
# 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
if CMAKE_BUILD_TYPE_OVERRIDE:
return CMAKE_BUILD_TYPE_OVERRIDE
else:
return tool.cmake_build_type
2014-07-03 23:38:51 +03:00
# The root directory of the build.
def fastcomp_build_dir(tool):
2015-01-12 17:58:16 +02:00
generator_suffix = ''
if CMAKE_GENERATOR == 'Visual Studio 10': generator_suffix = '_vs2010'
elif CMAKE_GENERATOR == 'Visual Studio 11': generator_suffix = '_vs2012'
elif CMAKE_GENERATOR == 'Visual Studio 12': generator_suffix = '_vs2013'
elif CMAKE_GENERATOR == 'MinGW Makefiles': generator_suffix = '_mingw'
2014-07-03 23:38:51 +03:00
2015-01-12 17:58:16 +02:00
bitness_suffix = '_32' if tool.bitness == 32 else '_64'
2015-04-09 18:26:01 -07:00
build_dir = 'build_' + tool.git_branch.replace(os.sep, '-') + generator_suffix + bitness_suffix
2014-07-03 23:38:51 +03:00
return build_dir
# The directory where the binaries are produced.
def fastcomp_build_bin_dir(tool):
build_dir = fastcomp_build_dir(tool)
2015-01-12 17:58:16 +02:00
if WINDOWS and 'Visual Studio' in CMAKE_GENERATOR:
2015-04-08 17:14:33 +03:00
old_llvm_bin_dir = os.path.join(build_dir, 'bin\\' + decide_cmake_build_type(tool))
new_llvm_bin_dir = os.path.join(build_dir, decide_cmake_build_type(tool) + '\\bin')
2015-01-13 13:33:13 +02:00
if os.path.exists(os.path.join(tool.install_path, new_llvm_bin_dir)):
return new_llvm_bin_dir
if os.path.exists(os.path.join(tool.install_path, old_llvm_bin_dir)): return old_llvm_bin_dir
return new_llvm_bin_dir
2014-07-03 23:38:51 +03:00
else:
return os.path.join(build_dir, 'bin')
2014-12-19 17:57:01 -05:00
make_env = os.environ.copy()
def find_msbuild(sln_file):
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'),]
search_paths_old = [os.path.join(os.environ["WINDIR"], 'Microsoft.NET/Framework/v4.0.30319')]
contents = open(sln_file, 'r').read()
if '# Visual Studio Express 2013' in contents or '# Visual Studio 2013' in contents:
search_paths = search_paths_vs2013 + search_paths_old
make_env['VCTargetsPath'] = os.path.join(os.environ['ProgramFiles(x86)'], 'MSBuild/Microsoft.Cpp/v4.0/V120')
else:
search_paths = search_paths_old + search_paths_vs2013
for path in search_paths:
p = os.path.join(path, 'MSBuild.exe')
if os.path.isfile(p): return p
def make_build(build_root, build_type):
2015-04-08 15:52:36 +03:00
global CPU_CORES
if CPU_CORES > 1:
2015-04-08 16:07:17 +03:00
print('Performing a parallel build with ' + str(CPU_CORES) + ' cores.')
2014-07-08 11:07:19 +03:00
else:
2015-03-31 15:44:34 +02:00
print('Performing a singlethreaded build.')
2014-07-03 23:38:51 +03:00
if WINDOWS:
2015-01-12 17:58:16 +02:00
if 'Visual Studio' in CMAKE_GENERATOR:
2014-12-19 17:57:01 -05:00
solution_name = subprocess.check_output(['dir', '/b', '*.sln'], shell=True, cwd=build_root).strip()
2015-04-09 16:00:55 +03:00
# 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, '/nologo', '/verbosity:minimal', solution_name]
2014-07-03 23:38:51 +03:00
else:
2015-04-08 15:52:36 +03:00
make = ['mingw32-make', '-j' + str(CPU_CORES)]
2014-07-03 23:38:51 +03:00
else:
2015-04-08 15:52:36 +03:00
make = ['make', '-j' + str(CPU_CORES)]
2014-07-03 23:38:51 +03:00
2014-12-19 17:16:19 -05:00
# Build
2014-07-03 23:38:51 +03:00
try:
2015-03-31 15:44:34 +02:00
print('Running build: ' + str(make))
2014-12-19 17:57:01 -05:00
ret = subprocess.check_call(make, cwd=build_root, env=make_env)
2014-07-03 23:38:51 +03:00
if ret != 0:
2015-03-31 15:44:34 +02:00
print('Build failed with exit code ' + ret + '!', file=sys.stderr)
print('Working directory: ' + build_root, file=sys.stderr)
2014-07-03 23:38:51 +03:00
return False
2015-03-31 15:44:34 +02:00
except Exception as e:
print('Build failed due to exception!', file=sys.stderr)
print('Working directory: ' + build_root, file=sys.stderr)
print(str(e), file=sys.stderr)
2014-07-03 23:38:51 +03:00
return False
2014-12-19 17:16:19 -05:00
return True
2014-12-19 17:57:01 -05:00
def cmake_configure(generator, build_root, src_root, build_type, extra_cmake_args = []):
2014-12-19 17:16:19 -05:00
# Configure
if not os.path.isdir(build_root): os.mkdir(build_root) # Create build output directory if it doesn't yet exist.
2014-07-03 23:38:51 +03:00
try:
2014-12-19 17:57:01 -05:00
if generator: generator = ['-G', generator]
else: generator = []
2015-04-23 10:58:47 +03:00
cmdline = ['cmake'] + generator + ['-DCMAKE_BUILD_TYPE='+build_type, '-DPYTHON_EXECUTABLE='+sys.executable] + extra_cmake_args + [src_root]
2015-03-31 15:44:34 +02:00
print('Running CMake: ' + str(cmdline))
2014-12-19 17:16:19 -05:00
ret = subprocess.check_call(cmdline, cwd=build_root)
2014-07-03 23:38:51 +03:00
if ret != 0:
2015-03-31 15:44:34 +02:00
print('CMake invocation failed with exit code ' + ret + '!', file=sys.stderr)
print('Working directory: ' + build_root, file=sys.stderr)
2015-03-17 14:27:03 +02:00
return False
2015-03-31 15:44:34 +02:00
except OSError as e:
2015-03-17 14:27:03 +02:00
if e.errno == errno.ENOENT:
2015-03-31 15:44:34 +02:00
print(str(e), file=sys.stderr)
print('Could not run CMake, perhaps it has not been installed?', file=sys.stderr)
2015-03-17 14:27:03 +02:00
if WINDOWS:
2015-03-31 15:44:34 +02:00
print('Installing this package requires CMake. Get it from http://www.cmake.org/', file=sys.stderr)
2015-03-17 14:27:03 +02:00
elif LINUX:
2015-03-31 15:44:34 +02:00
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)
2015-03-17 14:27:03 +02:00
elif OSX:
2015-03-31 15:44:34 +02:00
print('Installing this package requires CMake. Get it via a OSX package manager (Homebrew: "brew install cmake", or MacPorts: "sudo port install cmake"), or from http://www.cmake.org/', file=sys.stderr)
2014-07-03 23:38:51 +03:00
return False
2015-03-17 14:27:03 +02:00
raise
2015-03-31 15:44:34 +02:00
except Exception as e:
print('CMake invocation failed due to exception!', file=sys.stderr)
print('Working directory: ' + build_root, file=sys.stderr)
print(str(e), file=sys.stderr)
2014-07-03 23:38:51 +03:00
return False
2014-12-19 17:16:19 -05:00
2014-07-03 23:38:51 +03:00
return True
2014-12-19 17:16:19 -05:00
def build_fastcomp_tool(tool):
fastcomp_root = tool.installation_path()
fastcomp_src_root = os.path.join(fastcomp_root, 'src')
2015-03-18 14:22:48 +02:00
success = git_clone_checkout_and_pull(tool.url, fastcomp_src_root, tool.git_branch)
if not success: return False
2014-12-19 17:16:19 -05:00
clang_root = os.path.join(fastcomp_src_root, 'tools/clang')
2015-03-18 14:22:48 +02:00
success = git_clone_checkout_and_pull(tool.clang_url, clang_root, tool.git_branch)
if not success: return False
2015-01-12 17:58:16 +02:00
cmake_generator = CMAKE_GENERATOR
if 'Visual Studio' in CMAKE_GENERATOR and tool.bitness == 64:
cmake_generator += ' Win64'
2014-12-19 17:16:19 -05:00
build_dir = fastcomp_build_dir(tool)
build_root = os.path.join(fastcomp_root, build_dir)
2015-04-08 17:14:33 +03:00
build_type = decide_cmake_build_type(tool)
2014-12-19 17:57:01 -05:00
2014-12-19 17:16:19 -05:00
# Configure
2015-01-12 17:58:16 +02:00
success = cmake_configure(cmake_generator, build_root, fastcomp_src_root, build_type, ['-DLLVM_TARGETS_TO_BUILD=X86;JSBackend',
2014-12-19 17:16:19 -05:00
'-DLLVM_INCLUDE_EXAMPLES=OFF', '-DLLVM_INCLUDE_TESTS=OFF', '-DCLANG_INCLUDE_EXAMPLES=OFF', '-DCLANG_INCLUDE_TESTS=OFF'])
if not success: return False
2014-12-19 17:57:01 -05:00
# Make
success = make_build(build_root, build_type)
return success
2015-04-12 17:04:46 +03:00
def optimizer_build_root(tool):
build_root = tool.installation_path().strip()
if build_root.endswith('/') or build_root.endswith('\\'): build_root = build_root[:-1]
build_root = build_root + '_' + str(tool.bitness) + 'bit_optimizer'
return build_root
def uninstall_optimizer(tool):
build_root = optimizer_build_root(tool)
print("Deleting path '" + build_root + "'")
remove_tree(build_root)
os.remove(build_root)
def is_optimizer_installed(tool):
build_root = optimizer_build_root(tool)
return os.path.exists(build_root)
2014-12-19 17:57:01 -05:00
def build_optimizer_tool(tool):
src_root = os.path.join(tool.installation_path(), 'tools', 'optimizer')
2015-04-12 17:04:46 +03:00
build_root = optimizer_build_root(tool)
2015-04-08 17:14:33 +03:00
build_type = decide_cmake_build_type(tool)
2014-12-19 17:57:01 -05:00
# Configure
success = cmake_configure(None, build_root, src_root, build_type)
if not success: return False
# Make
success = make_build(build_root, build_type)
2014-12-19 17:16:19 -05:00
return success
2014-07-03 23:38:51 +03:00
2013-09-30 14:02:58 +03:00
def download_and_unzip(zipfile, dest_dir, download_even_if_exists=False):
if not download_even_if_exists and num_files_in_directory(dest_dir) > 0:
2015-03-31 15:44:34 +02:00
print("The contents of file '" + zipfile + "' already exist in destination '" + dest_dir + "', skipping.")
2013-09-30 14:02:58 +03:00
return True
2015-03-31 15:44:34 +02:00
dst_file = download_file(urljoin(emsdk_packages_url, zipfile), 'zips/', download_even_if_exists)
2013-09-30 14:27:20 +03:00
if not dst_file:
2013-09-05 16:42:27 +03:00
return False
if zipfile.endswith('.zip'):
2013-09-30 14:27:20 +03:00
return unzip(dst_file, dest_dir, unpack_even_if_exists=download_even_if_exists)
2013-09-05 16:42:27 +03:00
else:
2013-09-30 14:27:20 +03:00
return untargz(dst_file, dest_dir, unpack_even_if_exists=download_even_if_exists)
2013-09-05 16:42:27 +03:00
def to_unix_path(p):
return p.replace('\\', '/')
2014-07-03 15:14:45 +03:00
def to_native_path(p):
if WINDOWS:
return to_unix_path(p).replace('/', '\\')
else:
return to_unix_path(p)
2013-09-05 16:42:27 +03:00
# 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):
2014-07-03 15:14:45 +03:00
path_add = [to_native_path(emsdk_path())]
2013-09-05 16:42:27 +03:00
for tool in active_tools:
if hasattr(tool, 'activated_path'):
2014-07-03 15:14:45 +03:00
path_add += [to_native_path(tool.expand_vars(tool.activated_path))]
2013-09-05 16:42:27 +03:00
return path_add
# Returns the absolute path to the file '.emscripten' for the current user on this system.
def dot_emscripten_path():
2015-01-23 16:21:21 +02:00
return os.path.join(emscripten_config_directory, ".emscripten")
2013-09-05 16:42:27 +03:00
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()
return (key, value)
else:
return (key, '')
def load_dot_emscripten():
global dot_emscripten
dot_emscripten = {}
lines = []
try:
lines = open(dot_emscripten_path(), "r").read().split('\n')
except:
pass
for line in lines:
try:
(key, value) = parse_key_value(line)
if value != '':
dot_emscripten[key] = value
2015-04-08 16:07:17 +03:00
# print("Got '" + key + "' = '" + value + "'")
2013-09-05 16:42:27 +03:00
except:
pass
2013-11-17 14:33:02 +02:00
def generate_dot_emscripten(active_tools):
2015-01-23 16:21:21 +02:00
global emscripten_config_directory
if emscripten_config_directory == emsdk_path():
temp_dir = sdk_path('.tmp')
mkdir_p(temp_dir)
else:
temp_dir = tempfile.gettempdir().replace('\\', '/')
2013-09-05 16:42:27 +03:00
cfg = 'import os\n'
2014-07-07 15:04:48 +03:00
cfg += '''SPIDERMONKEY_ENGINE = ''
NODE_JS = 'node'
'''
2013-09-05 16:42:27 +03:00
for tool in active_tools:
tool_cfg = tool.activated_config()
if tool_cfg:
2014-12-19 17:57:01 -05:00
tool_cfg = tool_cfg.replace(';', '\n')
2013-09-05 16:42:27 +03:00
cfg += tool_cfg + '\n'
2014-03-14 13:43:25 +02:00
cfg += '''V8_ENGINE = ''
2013-11-13 18:38:34 +02:00
TEMP_DIR = ''' + "'" + temp_dir + "'" + '''
2013-09-05 16:42:27 +03:00
COMPILER_ENGINE = NODE_JS
JS_ENGINES = [NODE_JS]
'''
with open(dot_emscripten_path(), "w") as text_file: text_file.write(cfg)
# Clear old cached emscripten content.
try:
2015-04-12 17:04:46 +03:00
remove_tree(os.path.join(emscripten_config_directory, ".emscripten_cache"))
2015-01-23 16:21:21 +02:00
os.remove(os.path.join(emscripten_config_directory, ".emscripten_sanity"))
os.remove(os.path.join(emscripten_config_directory, ".emscripten_cache__last_clear"))
2013-09-05 16:42:27 +03:00
except:
pass
2015-03-31 15:44:34 +02:00
print("The Emscripten configuration file " + os.path.normpath(dot_emscripten_path()) + " has been rewritten with the following contents:")
print('')
print(cfg.strip())
print('')
2013-09-05 16:42:27 +03:00
path_add = get_required_path(active_tools)
2014-07-03 13:43:37 +03:00
if not WINDOWS:
2014-07-07 15:08:32 +03:00
emsdk_env = os.path.relpath(sdk_path('emsdk_env.sh'))
if not '/' in emsdk_env:
emsdk_env = './emsdk_env.sh'
2015-03-31 15:44:34 +02:00
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))
2013-09-05 16:42:27 +03:00
2013-11-08 13:53:07 +02:00
def find_msbuild_dir():
2013-11-22 11:16:31 +02:00
if 'ProgramFiles' in os.environ and os.environ['ProgramFiles']:
program_files = os.environ['ProgramFiles']
else:
2013-11-08 13:53:07 +02:00
program_files = 'C:/Program Files'
2013-11-22 11:16:31 +02:00
if 'ProgramFiles(x86)' in os.environ and os.environ['ProgramFiles(x86)']:
program_files_x86 = os.environ['ProgramFiles(x86)']
else:
2013-11-08 13:53:07 +02:00
program_files_x86 = 'C:/Program Files (x86)'
MSBUILDX86_DIR = os.path.join(program_files_x86, "MSBuild/Microsoft.Cpp/v4.0/Platforms")
MSBUILD_DIR = os.path.join(program_files, "MSBuild/Microsoft.Cpp/v4.0/Platforms")
if os.path.exists(MSBUILDX86_DIR):
return MSBUILDX86_DIR
elif os.path.exists(MSBUILD_DIR):
return MSBUILD_DIR
else:
return '' # No MSbuild installed.
2013-09-05 16:42:27 +03:00
def get_installed_vstool_version(installed_path):
try:
return open(installed_path + "/version.txt", "r").read()
except:
return None
class Tool:
def __init__(self, data):
# Convert the dictionary representation of the tool in 'data' to members of this class for convenience.
for key in data:
2015-03-31 22:31:45 +02:00
if sys.version_info < (3,) and isinstance(data[key], unicode):
2015-01-26 11:39:36 +02:00
setattr(self, key, data[key].encode('Latin-1'))
else:
setattr(self, key, data[key])
2013-09-05 16:42:27 +03:00
def __str__(self):
s = self.id + '-' + self.version
if hasattr(self, 'bitness'):
s += '-' + str(self.bitness) + 'bit'
return s
2014-04-24 00:57:59 +03:00
def expand_vars(self, str):
if WINDOWS and '%MSBuildPlatformsDir%' in str:
str = str.replace('%MSBuildPlatformsDir%', find_msbuild_dir())
2015-04-08 17:14:33 +03:00
if '%cmake_build_type_on_win%' in str:
str = str.replace('%cmake_build_type_on_win%', (decide_cmake_build_type(self) + '/') if WINDOWS else '')
2014-04-24 00:57:59 +03:00
if '%installation_dir%' in str:
str = str.replace('%installation_dir%', sdk_path(self.installation_dir()))
str = str.replace('%.exe%', '.exe' if WINDOWS else '')
2014-07-03 23:38:51 +03:00
if '%fastcomp_build_dir%' in str:
str = str.replace('%fastcomp_build_dir%', fastcomp_build_dir(self))
if '%fastcomp_build_bin_dir%' in str:
str = str.replace('%fastcomp_build_bin_dir%', fastcomp_build_bin_dir(self))
2014-04-24 00:57:59 +03:00
return str
2013-09-05 16:42:27 +03:00
# Specifies the target path where this tool will be installed to. This could either be a directory or a filename (e.g. in case of node.js)
def installation_path(self):
if WINDOWS and hasattr(self, 'windows_install_path'):
2014-04-24 00:57:59 +03:00
pth = self.expand_vars(self.windows_install_path)
2013-11-13 19:25:57 +02:00
return sdk_path(pth)
2014-07-03 23:38:51 +03:00
if hasattr(self, 'install_path'):
pth = self.expand_vars(self.install_path)
return sdk_path(pth)
2013-09-05 16:42:27 +03:00
p = self.version
2015-04-12 17:04:46 +03:00
if hasattr(self, 'bitness') and (not hasattr(self, 'append_bitness') or self.append_bitness):
2013-09-05 16:42:27 +03:00
p += '_' + str(self.bitness) + 'bit'
2013-11-13 19:25:57 +02:00
return sdk_path(os.path.join(self.id, p))
2013-09-05 16:42:27 +03:00
# Specifies the target directory this tool will be installed to.
def installation_dir(self):
dir = self.installation_path()
if path_points_to_directory(dir):
return dir
else:
return os.path.dirname(dir)
# Returns the configuration item that needs to be added to .emscripten to make this Tool active for the current user.
def activated_config(self):
if hasattr(self, 'activated_cfg'):
2014-07-03 23:38:51 +03:00
return to_unix_path(self.expand_vars(self.activated_cfg))
2014-04-24 00:57:59 +03:00
else:
return ''
def activated_environment(self):
if hasattr(self, 'activated_env'):
return self.expand_vars(self.activated_env)
2013-09-05 16:42:27 +03:00
else:
return ''
def compatible_with_this_os(self):
if hasattr(self, 'os'):
2013-10-28 13:29:57 +02:00
if self.os == 'all':
return True
2013-09-05 16:42:27 +03:00
if (WINDOWS and 'win' in self.os) or (LINUX and 'linux' in self.os) or (OSX and 'osx' in self.os):
return True
else:
return False
2013-10-28 13:29:57 +02:00
else:
if not hasattr(self, 'osx_url') and not hasattr(self, 'windows_url') and not hasattr(self, 'unix_url'):
return True
2013-09-05 16:42:27 +03:00
if OSX and hasattr(self, 'osx_url'):
return True
if WINDOWS and (hasattr(self, 'windows_url') or hasattr(self, 'windows_install_path')):
return True
2014-07-07 13:52:45 +03:00
if (LINUX or OSX) and hasattr(self, 'unix_url'):
2013-09-05 16:42:27 +03:00
return True
return hasattr(self, 'url')
def is_installed(self):
# If this tool/sdk depends on other tools, require that all dependencies are installed for this tool to count as being installed.
if hasattr(self, 'uses'):
for tool_name in self.uses:
tool = find_tool(tool_name)
if tool == None:
2015-03-31 15:44:34 +02:00
print("Manifest error: No tool by name '" + tool_name + "' found! This may indicate an internal SDK error!")
2013-09-05 16:42:27 +03:00
return False
if not tool.is_installed():
return False
if self.download_url() != None:
2014-11-18 19:02:12 +02:00
# 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)
2013-09-05 16:42:27 +03:00
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.
return content_exists and get_installed_vstool_version(self.installation_path()) == self.version
2015-04-12 17:04:46 +03:00
elif hasattr(self, 'custom_is_installed_script') and self.custom_is_installed_script == 'is_optimizer_installed':
return is_optimizer_installed(self)
2013-09-05 16:42:27 +03:00
else:
return content_exists
else:
return True # This tool does not contain downloadable elements, so it is installed by default.
def is_active(self):
if not self.is_installed():
return False
if self.id == 'vs-tool':
return True # vs-tool is a special tool since all versions must be installed to the same dir, which means that if this tool is installed, it is also active.
# All dependencies of this tool must be active as well.
deps = self.dependencies()
for tool in deps:
if not tool.is_active():
return False
activated_cfg = self.activated_config()
if activated_cfg == '':
return len(deps) > 0
2014-04-24 00:57:59 +03:00
2014-12-19 17:57:01 -05:00
activated_cfg = activated_cfg.split(';')
for cfg in activated_cfg:
cfg = cfg.strip()
(key, value) = parse_key_value(cfg)
2015-04-08 16:07:17 +03:00
# print('activated cfg ' + key + ', value: ' + value)
2014-12-19 17:57:01 -05:00
# if dot_emscripten.has_key(key):
2015-04-08 16:07:17 +03:00
# print('dot_emscripten ' + dot_emscripten[key])
2015-03-31 15:44:34 +02:00
if key in dot_emscripten and dot_emscripten[key] != value:
2014-12-19 17:57:01 -05:00
return False
return True
2013-09-05 16:42:27 +03:00
2014-07-03 14:45:49 +03:00
# Returns true if the system environment variables requires by this tool are currently active.
def is_env_active(self):
if hasattr(self, 'activated_env'):
(key, value) = parse_key_value(self.activated_environment())
2014-07-03 17:38:23 +03:00
if not key in os.environ or to_unix_path(os.environ[key]) != to_unix_path(value):
2014-07-03 14:45:49 +03:00
return False
# if WINDOWS:
# env_var = win_get_active_environment_variable(key)
# if env_var != value:
# return False
if hasattr(self, 'activated_path'):
path = self.expand_vars(self.activated_path).replace('\\', '/')
2014-07-03 17:38:23 +03:00
path = path.split(ENVPATH_SEPARATOR)
for p in path:
path_items = os.environ['PATH'].replace('\\', '/').split(ENVPATH_SEPARATOR)
if not normalized_contains(path_items, p):
return False
2014-07-03 14:45:49 +03:00
return True
2014-07-03 13:43:37 +03:00
def win_activate_env_vars(self, permanently_activate):
2014-04-24 00:57:59 +03:00
if WINDOWS and hasattr(self, 'activated_env'):
(key, value) = parse_key_value(self.activated_environment())
2014-07-03 13:43:37 +03:00
if permanently_activate:
2014-04-24 00:57:59 +03:00
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.
2014-07-03 13:43:37 +03:00
win_set_environment_variable(key, value, permanently_activate)
2014-04-24 00:57:59 +03:00
2013-09-05 16:42:27 +03:00
# If this tool can be installed on this system, this function returns True.
# Otherwise, this function returns a string that describes the reason why this tool is not available.
def can_be_installed(self):
if self.id == 'vs-tool':
2013-11-08 13:53:07 +02:00
msbuild_dir = find_msbuild_dir()
if len(msbuild_dir) > 0:
2013-09-05 16:42:27 +03:00
return True
else:
2015-02-15 19:52:54 +02:00
return "Visual Studio 2010 was not found!"
2013-09-05 16:42:27 +03:00
else:
return True
def download_url(self):
if WINDOWS and hasattr(self, 'windows_url'):
return self.windows_url
elif OSX and hasattr(self, 'osx_url'):
return self.osx_url
elif (OSX or LINUX) and hasattr(self, 'unix_url'):
return self.unix_url
elif hasattr(self, 'url'):
return self.url
else:
return None
def install(self):
if self.can_be_installed() != True:
2015-03-31 15:44:34 +02:00
print("The tool '" + str(self) + "' is not available due to the reason: " + self.can_be_installed())
2013-09-05 16:42:27 +03:00
return False
if self.id == 'sdk':
2015-04-12 17:13:15 +03:00
print("Installing SDK '" + str(self) + "'..")
2013-09-05 16:42:27 +03:00
for tool_name in self.uses:
tool = find_tool(tool_name)
if tool == None:
2015-03-31 15:44:34 +02:00
print("Manifest error: No tool by name '" + tool_name + "' found! This may indicate an internal SDK error!")
2013-09-05 16:42:27 +03:00
success = tool.install()
if not success:
return False
2015-04-12 17:13:15 +03:00
print("Done installing SDK '" + str(self) + "'.")
2013-10-28 13:29:57 +02:00
return True
2013-09-05 16:42:27 +03:00
else:
2015-04-12 17:13:15 +03:00
print("Installing tool '" + str(self) + "'..")
2013-09-05 16:42:27 +03:00
url = self.download_url()
2014-07-03 23:38:51 +03:00
if hasattr(self, 'custom_install_script') and self.custom_install_script == 'build_fastcomp':
success = build_fastcomp_tool(self)
elif hasattr(self, 'git_branch'):
2013-09-05 16:42:27 +03:00
success = git_clone_checkout_and_pull(url, self.installation_path(), self.git_branch)
2014-12-19 17:57:01 -05:00
if success:
if hasattr(self, 'custom_install_script') and self.custom_install_script == 'build_optimizer':
success = build_optimizer_tool(self)
2013-09-05 16:42:27 +03:00
elif url.endswith('zip') or url.endswith('.tar') or url.endswith('.gz'):
2013-11-21 15:39:04 +02:00
download_even_if_exists = (self.id == 'vs-tool')
success = download_and_unzip(url, self.installation_path(), download_even_if_exists)
2013-09-05 16:42:27 +03:00
else:
2015-03-31 15:44:34 +02:00
dst_file = download_file(urljoin(emsdk_packages_url, self.download_url()), self.installation_path())
2013-09-30 14:27:20 +03:00
if dst_file:
success = True
else:
success = False
2013-09-05 16:42:27 +03:00
if not success:
2015-03-31 15:44:34 +02:00
print("Installation failed!")
2013-09-05 16:42:27 +03:00
return False
2015-04-12 17:13:15 +03:00
print("Done installing tool '" + str(self) + "'.")
2013-09-05 16:42:27 +03:00
2013-10-28 13:14:21 +02:00
# Sanity check that the installation succeeded, and if so, remove unneeded leftover installation files.
if self.is_installed():
self.cleanup_temp_install_files()
else:
2015-03-31 15:44:34 +02:00
print("Warning: The installation of '" + str(self) + "' seems to have failed, but no error was detected. Either something went wrong with the installation, or this may indicate an internal emsdk error.")
2013-09-05 16:42:27 +03:00
return True
2013-10-28 13:14:21 +02:00
def cleanup_temp_install_files(self):
url = self.download_url()
if url.endswith('zip') or url.endswith('.tar') or url.endswith('.gz'):
file_name = url.split('/')[-1]
tempzipfile = os.path.join('zips/', file_name)
rmfile(tempzipfile)
2013-09-05 16:42:27 +03:00
def uninstall(self):
2015-04-12 17:04:46 +03:00
if not self.is_installed():
2015-03-31 15:44:34 +02:00
print("Tool '" + str(self) + "' was not installed. No need to uninstall.")
2013-09-05 16:42:27 +03:00
return
2015-03-31 15:44:34 +02:00
print("Uninstalling tool '" + str(self) + "'..")
2015-04-12 17:04:46 +03:00
if hasattr(self, 'custom_uninstall_script') and self.custom_uninstall_script == 'uninstall_optimizer':
try:
uninstall_optimizer(self)
except:
pass
2013-09-05 16:42:27 +03:00
try:
2015-03-31 15:44:34 +02:00
print("Deleting path '" + self.installation_path() + "'")
2015-04-12 17:04:46 +03:00
remove_tree(self.installation_path())
2013-09-05 16:42:27 +03:00
os.remove(self.installation_path())
except:
pass
2015-04-12 17:13:15 +03:00
print("Done uninstalling '" + str(self) + "'.")
2013-09-05 16:42:27 +03:00
def dependencies(self):
if not hasattr(self, 'uses'):
return []
deps = []
for tool_name in self.uses:
tool = find_tool(tool_name)
if tool:
deps += [tool]
return deps
def recursive_dependencies(self):
if not hasattr(self, 'uses'):
return []
deps = []
for tool_name in self.uses:
tool = find_tool(tool_name)
if tool:
deps += [tool]
deps += tool.recursive_dependencies()
return deps
# A global registry of all known Emscripten SDK tools available in the SDK manifest.
tools = []
# A global registry of all known SDK toolsets.
sdks = []
# 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):
for tool in tools:
if str(tool) == name:
return tool
return None
def find_sdk(name):
for sdk in sdks:
if str(sdk) == name:
return sdk
return None
2013-10-15 17:48:04 +03:00
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.
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.
return sdk
return None
2013-09-05 16:42:27 +03:00
def find_latest_sdk():
2013-10-15 17:48:04 +03:00
if is_os_64bit():
return find_latest_64bit_sdk()
else:
return find_latest_32bit_sdk()
2013-09-05 16:42:27 +03:00
2014-07-03 17:56:57 +03:00
# 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.
if t.id == 'python' and t.is_installed() and t.is_active() and t.is_env_active():
return t
for t in reversed(tools):
if t.id == 'python' and t.is_installed() and t.is_active():
return t
for t in reversed(tools):
if t.id == 'python' and t.is_installed():
return t
return None
2013-09-05 16:42:27 +03:00
def update_emsdk():
2013-09-05 19:57:06 +03:00
if WINDOWS:
2015-03-31 15:44:34 +02:00
download_and_unzip(urljoin(emsdk_packages_url, 'emsdk_windows_update.zip'), emsdk_path(), download_even_if_exists=True)
2013-10-28 13:15:29 +02:00
rmfile('zips/emsdk_windows_update.zip')
2014-07-07 15:15:43 +03:00
elif OSX or LINUX:
2015-03-31 15:44:34 +02:00
download_and_unzip(urljoin(emsdk_packages_url, 'emsdk_unix_update.tar.gz'), emsdk_path(), download_even_if_exists=True)
2014-07-07 15:15:43 +03:00
rmfile('zips/emsdk_unix_update.tar.gz')
2013-09-05 19:57:06 +03:00
else:
2015-03-31 15:44:34 +02:00
print('Unsupported OS, cannot update!')
2013-09-30 14:02:58 +03:00
2013-09-05 16:42:27 +03:00
def load_sdk_manifest():
global tools
try:
manifest = json.loads(open(sdk_path("emsdk_manifest.json"), "r").read())
2015-03-31 15:44:34 +02:00
except Exception as e:
print('Error parsing emsdk_manifest.json!')
print(str(e))
2013-09-05 16:42:27 +03:00
return
for tool in manifest['tools']:
t = Tool(tool)
if t.compatible_with_this_os():
2014-04-24 13:10:04 +03:00
if not hasattr(t, 'is_old'):
t.is_old = False
2013-09-05 16:42:27 +03:00
tools.append(t)
for sdk_str in manifest['sdks']:
sdk = Tool(sdk_str)
sdk.id = "sdk"
if sdk.compatible_with_this_os():
2014-04-24 13:10:04 +03:00
if not hasattr(sdk, 'is_old'):
sdk.is_old = False
2013-09-05 16:42:27 +03:00
sdks.append(sdk)
2013-11-17 14:33:02 +02:00
# 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
2014-07-03 13:43:37 +03:00
def remove_nonexisting_tools(tool_list, log_errors=True):
i = 0
while i < len(tool_list):
tool = tool_list[i]
if not tool.is_installed():
if log_errors:
2015-03-31 15:44:34 +02:00
print("The SDK/tool '" + str(tool) + "' cannot be activated since it is not installed! Skipping this tool...")
2014-07-03 13:43:37 +03:00
tool_list.pop(i)
continue
i += 1
return tool_list
2014-07-03 14:09:45 +03:00
# Expands dependencies for each tool, and removes ones that don't exist.
def process_tool_list(tools_to_activate, log_errors=True):
2013-11-17 14:33:02 +02:00
i = 0
# Gather dependencies for each tool
while i < len(tools_to_activate):
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
2014-07-03 14:09:45 +03:00
tools_to_activate = remove_nonexisting_tools(tools_to_activate, log_errors=log_errors)
2013-11-17 14:33:02 +02:00
# Remove conflicting tools
i = 0
while i < len(tools_to_activate):
j = 0
while j < i:
secondary_tool = tools_to_activate[j]
primary_tool = tools_to_activate[i]
if not can_simultaneously_activate(primary_tool, secondary_tool):
tools_to_activate.pop(j)
j -= 1
i -= 1
j += 1
i += 1
2014-07-03 14:09:45 +03:00
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):
tools_to_activate = process_tool_list(tools_to_activate, log_errors=True)
2013-11-17 14:33:02 +02:00
generate_dot_emscripten(tools_to_activate)
2013-09-05 16:42:27 +03:00
2014-07-03 14:09:45 +03:00
# Construct a .bat script that will be invoked to set env. vars and PATH
if WINDOWS:
env_string = construct_env(tools_to_activate, False)
2014-11-18 15:24:32 +02:00
open(EMSDK_SET_ENV, 'w').write(env_string)
2014-07-03 14:09:45 +03:00
2014-04-24 13:10:04 +03:00
# Apply environment variables to global all users section.
2014-07-03 13:43:37 +03:00
if WINDOWS and permanently_activate:
2014-04-24 13:10:04 +03:00
# Individual env. vars
2014-04-24 00:57:59 +03:00
for tool in tools_to_activate:
2014-07-03 13:43:37 +03:00
tool.win_activate_env_vars(permanently_activate=True)
2014-04-24 00:57:59 +03:00
2014-04-24 13:10:04 +03:00
# PATH variable
2014-07-03 13:43:37 +03:00
newpath, added_items = adjusted_path(tools_to_activate)
if newpath != os.environ['PATH']: # Are there any actual changes?
if len(newpath) < 1024:
win_set_environment_variable('PATH', newpath, system=True)
else:
2015-03-31 15:44:34 +02:00
print('ERROR! The new PATH is more than 1024 characters long! A PATH this long cannot be set via command line: please add the PATHs specified above to system PATH manually via Control Panel.', file=sys.stderr)
2014-07-03 14:09:45 +03:00
return tools_to_activate
2014-04-24 13:10:04 +03:00
2013-09-05 16:42:27 +03:00
def currently_active_sdk():
for sdk in reversed(sdks):
if sdk.is_active():
return sdk
return None
2013-09-10 17:18:04 +03:00
def currently_active_tools():
active_tools = []
for tool in tools:
if tool.is_active():
active_tools += [tool]
return active_tools
2014-04-24 13:10:04 +03:00
# 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)]
2014-07-03 17:38:23 +03:00
# Tests if a path is contained in the given list, but with separators normalized.
def normalized_contains(lst, elem):
elem = to_unix_path(elem)
for e in lst:
if elem == to_unix_path(e):
return True
return False
2014-04-24 13:10:04 +03:00
# Looks at the current PATH and adds and removes entries so that the PATH reflects
# the set of given active tools.
2014-07-03 13:43:37 +03:00
def adjusted_path(tools_to_activate, log_additions=False):
2013-09-10 17:18:04 +03:00
# These directories should be added to PATH
path_add = get_required_path(tools_to_activate)
# These already exist.
2014-07-03 15:14:45 +03:00
existing_path = os.environ['PATH'].split(ENVPATH_SEPARATOR)
emsdk_root_path = to_unix_path(emsdk_path())
existing_emsdk_tools = [item for item in existing_path if to_unix_path(item).startswith(emsdk_root_path)]
new_emsdk_tools = [item for item in path_add if not normalized_contains(existing_emsdk_tools, item)]
2014-07-03 13:43:37 +03:00
# Existing non-emsdk tools
2014-07-03 15:14:45 +03:00
existing_path = [item for item in existing_path if not to_unix_path(item).startswith(emsdk_root_path)]
new_path = [item for item in path_add if not normalized_contains(existing_path, item)]
2015-04-12 17:52:13 +03:00
return (ENVPATH_SEPARATOR.join(unique_items(new_path + existing_path)), new_emsdk_tools)
2013-09-10 17:18:04 +03:00
def construct_env_windows(tools_to_activate, permanent):
2015-01-23 16:21:21 +02:00
global emscripten_config_directory
2014-04-24 13:10:04 +03:00
env_string = ''
2014-07-03 13:43:37 +03:00
newpath, added_path = adjusted_path(tools_to_activate)
2014-07-03 14:09:45 +03:00
2013-09-10 17:18:04 +03:00
# Dont permanently add to PATH, since this will break the whole system if there are more than 1024 chars in PATH.
# (SETX truncates to set only 1024 chars)
# if permanent:
2015-04-08 16:07:17 +03:00
# print('SETX PATH "' + newpath + '"')
2013-09-10 17:18:04 +03:00
# else:
2014-07-03 13:43:37 +03:00
if os.environ['PATH'] != newpath: # Don't bother setting the path if there are no changes.
env_string += 'SET PATH=' + newpath + '\n'
if len(added_path) > 0:
2015-03-31 15:44:34 +02:00
print('Adding directories to PATH:')
2014-07-03 13:43:37 +03:00
for item in added_path:
2015-03-31 15:44:34 +02:00
print('PATH += ' + item)
print('')
2014-07-03 13:43:37 +03:00
env_vars_to_add = []
2015-01-23 16:21:21 +02:00
em_config_path = os.path.normpath(os.path.join(emscripten_config_directory, '.emscripten'))
if not 'EM_CONFIG' 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):
env_vars_to_add += [('EM_CACHE', em_cache_dir)]
mkdir_p(em_cache_dir)
2013-09-10 17:18:04 +03:00
for tool in tools_to_activate:
if hasattr(tool, 'activated_env'):
(key, value) = parse_key_value(tool.activated_env)
2014-07-03 15:14:45 +03:00
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.
2014-07-03 13:43:37 +03:00
env_vars_to_add += [(key, value)]
if len(env_vars_to_add) > 0:
2015-03-31 15:44:34 +02:00
print('Setting environment variables:')
2014-07-03 13:43:37 +03:00
for key, value in env_vars_to_add:
2013-09-10 17:18:04 +03:00
if permanent:
2014-04-24 13:10:04 +03:00
env_string += 'SETX ' + key + ' "' + value + '"\n'
2013-09-10 17:18:04 +03:00
else:
2014-04-24 13:10:04 +03:00
env_string += 'SET ' + key + '=' + value + '\n'
2015-03-31 15:44:34 +02:00
print(key + ' = ' + value)
print('')
2014-04-24 13:10:04 +03:00
return env_string
2013-09-10 17:18:04 +03:00
2014-07-03 18:50:00 +03:00
def construct_env_unix(tools_to_activate):
env_string = ''
newpath, added_path = adjusted_path(tools_to_activate)
if os.environ['PATH'] != newpath: # Don't bother setting the path if there are no changes.
2014-11-19 17:25:38 +02:00
env_string += 'export PATH="' + newpath + '"\n'
2014-07-03 18:50:00 +03:00
if len(added_path) > 0:
2015-03-31 15:44:34 +02:00
print('Adding directories to PATH:')
2014-07-03 18:50:00 +03:00
for item in added_path:
2015-03-31 15:44:34 +02:00
print('PATH += ' + item)
print('')
2014-07-03 18:50:00 +03:00
env_vars_to_add = []
for tool in tools_to_activate:
if hasattr(tool, 'activated_env'):
(key, value) = parse_key_value(tool.activated_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.
env_vars_to_add += [(key, value)]
if len(env_vars_to_add) > 0:
2015-03-31 15:44:34 +02:00
print('Setting environment variables:')
2014-07-03 18:50:00 +03:00
for key, value in env_vars_to_add:
2014-11-19 17:26:38 +02:00
env_string += 'export ' + key + '="' + value + '"\n'
2015-03-31 15:44:34 +02:00
print(key + ' = ' + value)
print('')
2014-07-03 18:50:00 +03:00
return env_string
2013-09-10 17:18:04 +03:00
def construct_env(tools_to_activate, permanent):
if WINDOWS:
2014-04-24 13:10:04 +03:00
return construct_env_windows(tools_to_activate, permanent)
2014-07-03 18:50:00 +03:00
else:
return construct_env_unix(tools_to_activate)
2013-09-10 17:18:04 +03:00
2014-11-18 15:24:32 +02:00
def silentremove(filename):
try:
os.remove(filename)
2015-03-31 15:44:34 +02:00
except OSError as e:
2014-11-18 15:24:32 +02:00
if e.errno != errno.ENOENT: raise
2013-09-05 16:42:27 +03:00
def main():
2015-01-23 16:21:21 +02:00
global emscripten_config_directory
2013-09-05 16:42:27 +03:00
load_dot_emscripten()
load_sdk_manifest()
2014-04-24 00:57:59 +03:00
2013-09-05 16:42:27 +03:00
if len(sys.argv) <= 1 or sys.argv[1] == 'help':
if len(sys.argv) <= 1:
2015-03-31 15:44:34 +02:00
print(' emsdk: No command given. Please call one of the following:')
2013-09-05 16:42:27 +03:00
else:
2015-03-31 15:44:34 +02:00
print(' emsdk: Available commands:')
2013-09-05 16:42:27 +03:00
2015-03-31 15:44:34 +02:00
print('''
2014-04-24 13:10:04 +03:00
emsdk list [--old] - Lists all available SDKs and tools and their
current installation status. With the --old
2015-04-08 17:14:33 +03:00
parameter, also historical versions are
shown.
2013-09-05 16:42:27 +03:00
emsdk update - Fetches a list of updates from the net (but
does not install them)
2015-04-08 17:14:33 +03:00
emsdk install [-j<num>] [--build=type] <tool/sdk>
2015-04-08 15:52:36 +03:00
- Downloads and installs the given tool or SDK.
An optional -j<num> specifier can be used to
specify the number of cores to use when
building the tool. (default: use one less
than the # of detected cores)
2015-04-08 17:14:33 +03:00
emsdk uninstall <tool/sdk> - Removes the given tool or SDK from disk.''')
2013-09-05 16:42:27 +03:00
if WINDOWS:
2015-03-31 15:44:34 +02:00
print('''
2015-04-08 17:14:33 +03:00
emsdk activate [--global] [--embedded] [--build=type] <tool/sdk>
2015-01-23 16:21:21 +02:00
2015-04-08 17:14:33 +03:00
- Activates the given tool or SDK in the
environment of the current shell. If the
--global option is passed, the registration
is done globally to all users in the system
2015-01-23 16:21:21 +02:00
environment. If the --embedded option is
passed, all Emcripten configuration files as
well as the temp, cache and ports directories
are located inside the Emscripten SDK
2015-04-08 17:14:33 +03:00
directory rather than the user home
directory.
2014-09-17 10:09:18 +03:00
2014-04-24 13:10:04 +03:00
emcmdprompt.bat - Spawns a new command prompt window with the
2015-03-31 15:44:34 +02:00
Emscripten environment active.''')
2014-09-17 10:09:18 +03:00
else:
2015-04-08 17:14:33 +03:00
print(''' emsdk activate [--embedded] [--build=type] <tool/sdk>
2015-01-23 16:21:21 +02:00
- Activates the given tool or SDK in the
environment of the current shell. If the
--embedded option is passed, all Emcripten
configuration files as well as the temp, cache
and ports directories are located inside the
Emscripten SDK directory rather than the user
2015-03-31 15:44:34 +02:00
home directory.''')
2014-04-24 13:10:04 +03:00
2015-04-08 17:14:33 +03:00
print('''
Both commands 'install' and 'activate' accept an optional parameter
'--build=type', which can be used to override what kind of installation
or activation to perform. Possible values for type are Debug, Release,
MinSizeRel or RelWithDebInfo. Note: When overriding a custom build type,
be sure to match the same --build= option to both 'install' and
'activate' commands and the invocation of 'emsdk_env', or otherwise
these commands will default to operating on the default build types,
which are Release for the 'master' SDK, and RelWithDebInfo for the
'incoming' SDK.''')
2013-09-05 16:42:27 +03:00
return 1
cmd = sys.argv[1]
2013-10-15 17:51:44 +03:00
2015-04-08 17:14:33 +03:00
# Process global args
for i in range(2, len(sys.argv)):
if sys.argv[i].startswith('--build='):
build_type = re.match(r'^--build=(.+)$', sys.argv[i])
if build_type:
global CMAKE_BUILD_TYPE_OVERRIDE
build_type = build_type.group(1)
build_types = ['Debug', 'MinSizeRel', 'RelWithDebInfo', 'Release']
try:
2015-04-10 14:40:54 +03:00
build_type_index = [x.lower() for x in build_types].index(build_type.lower())
2015-04-08 17:14:33 +03:00
CMAKE_BUILD_TYPE_OVERRIDE = build_types[build_type_index]
sys.argv[i] = ''
except:
print('Unknown CMake build type "' + build_type + '" specified! Please specify one of ' + str(build_types), file=sys.stderr)
return 1
else:
print("Invalid command line parameter " + sys.argv[i] + ' specified!', file=sys.stderr)
return 1
sys.argv = [x for x in sys.argv if not len(x) == 0]
2015-04-08 15:39:01 +03:00
# Replace meta-packages with the real package names.
if (cmd == 'update' or cmd == 'install' or cmd == 'activate'):
for i in range(2, len(sys.argv)):
if sys.argv[i] == 'latest':
sys.argv[i] = str(find_latest_sdk())
elif sys.argv[i] == 'latest-32bit':
sys.argv[i] = str(find_latest_32bit_sdk())
elif sys.argv[i] == 'latest-64bit':
sys.argv[i] = str(find_latest_64bit_sdk())
2013-10-15 17:51:44 +03:00
2013-09-05 16:42:27 +03:00
if cmd == 'list':
2015-03-31 15:44:34 +02:00
print('')
2014-04-24 13:10:04 +03:00
show_old = len(sys.argv) >= 3 and sys.argv[2] == '--old'
2014-07-03 14:45:49 +03:00
has_partially_active_tools = False
2013-09-05 16:42:27 +03:00
if len(tools) > 0:
2015-03-31 15:44:34 +02:00
print('The following individual tools exist:')
2013-09-05 16:42:27 +03:00
for tool in tools:
2014-04-24 13:10:04 +03:00
if tool.is_old and not show_old:
continue
2013-09-05 16:42:27 +03:00
if tool.can_be_installed() == True:
installed = '\tINSTALLED' if tool.is_installed() else ''
else:
installed = '\tNot available: ' + tool.can_be_installed()
2014-07-03 14:45:49 +03:00
tool_is_active = tool.is_active()
tool_is_env_active = tool_is_active and tool.is_env_active()
if tool_is_env_active: active = ' * '
elif tool_is_active:
active = '(*)'
has_partially_active_tools = True
else: active = ' '
2015-03-31 15:44:34 +02:00
print(' ' + active + ' {0: <25}'.format(str(tool)) + installed)
print('')
2013-09-05 16:42:27 +03:00
else:
2015-03-31 15:44:34 +02:00
print("There are no tools available. Run 'emsdk update' to fetch the latest set of tools.")
print('')
2013-09-05 16:42:27 +03:00
if len(sdks) > 0:
2015-03-31 15:44:34 +02:00
print('The following Emscripten SDK versions are available:')
2013-09-05 16:42:27 +03:00
for sdk in sdks:
2014-04-24 13:17:02 +03:00
if sdk.is_old and not show_old:
continue
2013-09-05 16:42:27 +03:00
installed = '\tINSTALLED' if sdk.is_installed() else ''
active = '*' if sdk.is_active() else ' '
2015-03-31 15:44:34 +02:00
print(' ' + active + ' {0: <25}'.format(str(sdk)) + installed)
print('')
print('Items marked with * are activated for the current user.')
2014-07-03 14:45:49 +03:00
if has_partially_active_tools:
2014-07-03 18:50:00 +03:00
env_cmd = 'emsdk_env.bat' if WINDOWS else 'source ./emsdk_env.sh'
2015-03-31 15:44:34 +02:00
print('Items marked with (*) are selected for use, but your current shell environment is not configured to use them. Type "' + env_cmd + '" to set up your current shell to use them, or call "emsdk activate --global <name_of_sdk>" to permanently activate them.')
2014-04-24 13:17:02 +03:00
if not show_old:
2015-03-31 15:44:34 +02:00
print('')
print("To access the historical archived versions, type 'emsdk list --old'")
2013-09-05 16:42:27 +03:00
2013-09-10 17:18:04 +03:00
return 0
elif cmd == 'construct_env':
2015-01-23 16:21:21 +02:00
# If .emscripten exists, we are configuring as embedded inside the emsdk directory.
if os.path.exists(os.path.join(emsdk_path(), '.emscripten')):
emscripten_config_directory = emsdk_path()
2014-11-18 15:24:32 +02:00
silentremove(EMSDK_SET_ENV) # Clean up old temp file up front, in case of failure later before we get to write out the new one.
2013-09-10 17:18:04 +03:00
tools_to_activate = currently_active_tools()
2014-07-03 14:45:49 +03:00
tools_to_activate = process_tool_list(tools_to_activate, log_errors=True)
2014-07-03 13:43:37 +03:00
env_string = construct_env(tools_to_activate, len(sys.argv) >= 3 and 'perm' in sys.argv[2])
2014-11-18 15:24:32 +02:00
open(EMSDK_SET_ENV, 'w').write(env_string)
2015-03-31 15:44:34 +02:00
if LINUX or OSX: os.chmod(EMSDK_SET_ENV, 0o755)
2013-09-05 16:42:27 +03:00
return 0
elif cmd == 'update':
update_emsdk()
2014-11-18 15:24:32 +02:00
silentremove(sdk_path(EMSDK_SET_ENV)) # Clean up litter after old emsdk update which may have left this temp file around.
2013-09-05 16:42:27 +03:00
return 0
elif cmd == 'activate':
2014-07-03 13:43:37 +03:00
permanently_activate = '--global' in sys.argv
if permanently_activate:
2015-03-31 15:44:34 +02:00
print('Registering active Emscripten environment globally for all users.')
print('')
2015-01-23 16:21:21 +02:00
embed_activation_to_sdk_dir = '--embedded' in sys.argv
if embed_activation_to_sdk_dir:
# Activating the emsdk tools locally relative to Emscripten SDK directory.
emscripten_config_directory = emsdk_path()
2015-03-31 15:44:34 +02:00
print('Writing .emscripten configuration file to Emscripten SDK directory ' + emscripten_config_directory)
2015-01-23 16:21:21 +02:00
else:
2015-03-31 15:44:34 +02:00
print('Writing .emscripten configuration file to user home directory ' + emscripten_config_directory)
2015-01-23 16:21:21 +02:00
# Remove .emscripten from emsdk dir, since its presence is used to detect whether emsdk is activate in embedded mode or not.
try:
os.remove(os.path.join(emsdk_path(), ".emscripten"))
except:
pass
2015-03-31 15:44:34 +02:00
sys.argv = [x for x in sys.argv if not x.startswith('--')]
2013-11-20 13:09:51 +02:00
# If called without arguments, activate latest versions of all tools
2013-09-05 16:42:27 +03:00
if len(sys.argv) <= 2:
2013-11-20 13:09:51 +02:00
tools_to_activate = list(tools)
2014-07-03 13:43:37 +03:00
tools_to_activate = remove_nonexisting_tools(tools_to_activate, log_errors=False)
2013-11-20 13:09:51 +02:00
else:
tools_to_activate = currently_active_tools()
for i in range(2, len(sys.argv)):
tool = find_tool(sys.argv[i])
if tool == None:
tool = find_sdk(sys.argv[i])
if tool == None:
2015-03-31 15:44:34 +02:00
print("Error: No tool or SDK found by name '" + sys.argv[i] + "'.")
2013-11-20 13:09:51 +02:00
return 1
tools_to_activate += [tool]
2014-07-03 14:09:45 +03:00
tools_to_activate = set_active_tools(tools_to_activate, permanently_activate=permanently_activate)
2014-09-17 10:09:18 +03:00
if WINDOWS and not permanently_activate:
2015-03-31 15:44:34 +02:00
print('To permanently register this environment globally to all users in Windows Registry, rerun the command with the option --global.')
2013-09-05 16:42:27 +03:00
return 0
elif cmd == 'install':
2015-04-08 15:52:36 +03:00
# Process args
for i in range(2, len(sys.argv)):
if sys.argv[i].startswith('-j'):
multicore = re.match(r'^-j(\d+)$', sys.argv[i])
if multicore:
global CPU_CORES
CPU_CORES = int(multicore.group(1))
sys.argv[i] = ''
else:
2015-04-08 16:07:17 +03:00
print("Invalid command line parameter " + sys.argv[i] + ' specified!', file=sys.stderr)
2015-04-08 15:52:36 +03:00
return 1
2015-04-08 16:16:44 +03:00
sys.argv = [x for x in sys.argv if not len(x) == 0]
2013-09-05 16:42:27 +03:00
if len(sys.argv) <= 2:
2015-03-31 15:44:34 +02:00
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.")
2013-09-05 16:42:27 +03:00
return 1
tool = find_tool(sys.argv[2])
if tool == None:
tool = find_sdk(sys.argv[2])
if tool == None:
2015-03-31 15:44:34 +02:00
print("Error: No tool or SDK found by name '" + sys.argv[2] + "'.")
2013-09-05 16:42:27 +03:00
return 1
2015-03-17 16:03:43 -07:00
success = tool.install()
if not success:
return 1
2013-09-05 16:42:27 +03:00
elif cmd == 'uninstall':
if len(sys.argv) <= 2:
2015-03-31 15:44:34 +02:00
print("Syntax error. Call 'emsdk uninstall <tool name>'. Call 'emsdk list' to obtain a list of available tools.")
2013-09-05 16:42:27 +03:00
return 1
tool = find_tool(sys.argv[2])
if tool == None:
2015-03-31 15:44:34 +02:00
print("Error: Tool by name '" + sys.argv[2] + "' was not found.")
2013-09-05 16:42:27 +03:00
return 1
tool.uninstall()
else:
2015-03-31 15:44:34 +02:00
print("Unknown command '" + cmd + "' given! Type 'emsdk help' to get a list of commands.")
2013-09-05 16:42:27 +03:00
return 1
if __name__ == '__main__':
sys.exit(main())