blob: c8426029c883efb2f25cc23bec968ef904ae0529 [file] [log] [blame] [edit]
import os, json, logging, zipfile, glob
import shared
from subprocess import Popen, CalledProcessError
import multiprocessing
from tools.shared import check_call
stdout = None
stderr = None
def call_process(cmd):
proc = Popen(cmd, stdout=stdout, stderr=stderr)
proc.communicate()
if proc.returncode != 0:
# Deliberately do not use CalledProcessError, see issue #2944
raise Exception('Command \'%s\' returned non-zero exit status %s' % (' '.join(cmd), proc.returncode))
CORES = int(os.environ.get('EMCC_CORES') or multiprocessing.cpu_count())
def run_commands(commands):
cores = min(len(commands), CORES)
if cores <= 1:
for command in commands:
call_process(command)
else:
pool = multiprocessing.Pool(processes=cores)
pool.map(call_process, commands, chunksize=1)
def calculate(temp_files, in_temp, stdout_, stderr_, forced=[]):
global stdout, stderr
stdout = stdout_
stderr = stderr_
# Check if we need to include some libraries that we compile. (We implement libc ourselves in js, but
# compile a malloc implementation and stdlibc++.)
def read_symbols(path, exclude=None):
symbols = map(lambda line: line.strip().split(' ')[1], open(path).readlines())
if exclude:
symbols = filter(lambda symbol: symbol not in exclude, symbols)
return set(symbols)
default_opts = []
# XXX We also need to add libc symbols that use malloc, for example strdup. It's very rare to use just them and not
# a normal malloc symbol (like free, after calling strdup), so we haven't hit this yet, but it is possible.
libc_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libc.symbols'))
libcxx_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libcxx', 'symbols'), exclude=libc_symbols)
libcxxabi_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libcxxabi', 'symbols'), exclude=libc_symbols)
gl_symbols = read_symbols(shared.path_from_root('system', 'lib', 'gl.symbols'))
compiler_rt_symbols = read_symbols(shared.path_from_root('system', 'lib', 'compiler-rt.symbols'))
pthreads_symbols = read_symbols(shared.path_from_root('system', 'lib', 'pthreads.symbols'))
# XXX we should disable EMCC_DEBUG when building libs, just like in the relooper
def build_libc(lib_filename, files, lib_opts):
o_s = []
musl_internal_includes = ['-I', shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'internal'), '-I', shared.path_from_root('system', 'lib', 'libc', 'musl', 'arch', 'js')]
commands = []
# Hide several musl warnings that produce a lot of spam to unit test build server logs.
# TODO: When updating musl the next time, feel free to recheck which of their warnings might have been fixed, and which ones of these could be cleaned up.
c_opts = ['-Wno-dangling-else', '-Wno-unknown-pragmas', '-Wno-shift-op-parentheses', '-Wno-string-plus-int', '-Wno-logical-op-parentheses', '-Wno-bitwise-op-parentheses', '-Wno-visibility', '-Wno-pointer-sign']
for src in files:
o = in_temp(os.path.basename(src) + '.o')
commands.append([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-o', o] + musl_internal_includes + default_opts + c_opts + lib_opts)
o_s.append(o)
run_commands(commands)
shared.Building.link(o_s, in_temp(lib_filename))
return in_temp(lib_filename)
def build_libcxx(src_dirname, lib_filename, files, lib_opts, has_noexcept_version=False):
o_s = []
commands = []
opts = default_opts + lib_opts
if has_noexcept_version and shared.Settings.DISABLE_EXCEPTION_CATCHING:
opts += ['-fno-exceptions']
for src in files:
o = in_temp(src + '.o')
srcfile = shared.path_from_root(src_dirname, src)
commands.append([shared.PYTHON, shared.EMXX, srcfile, '-o', o, '-std=c++11'] + opts)
o_s.append(o)
run_commands(commands)
if lib_filename.endswith('.bc'):
shared.Building.link(o_s, in_temp(lib_filename))
elif lib_filename.endswith('.a'):
shared.Building.emar('cr', in_temp(lib_filename), o_s)
else:
raise Exception('unknown suffix ' + lib_filename)
return in_temp(lib_filename)
# libc
def create_libc(libname):
logging.debug(' building libc for cache')
libc_files = [
]
musl_srcdir = shared.path_from_root('system', 'lib', 'libc', 'musl', 'src')
blacklist = set(
['ipc', 'passwd', 'thread', 'signal', 'sched', 'ipc', 'time', 'linux', 'aio', 'exit', 'legacy', 'mq', 'process', 'search', 'setjmp', 'env', 'ldso', 'conf'] + # musl modules
['memcpy.c', 'memset.c', 'memmove.c', 'getaddrinfo.c', 'getnameinfo.c', 'inet_addr.c', 'res_query.c', 'gai_strerror.c', 'proto.c', 'gethostbyaddr.c', 'gethostbyaddr_r.c', 'gethostbyname.c', 'gethostbyname2_r.c', 'gethostbyname_r.c', 'gethostbyname2.c', 'usleep.c', 'alarm.c', 'syscall.c'] + # individual files
['abs.c', 'cos.c', 'cosf.c', 'cosl.c', 'sin.c', 'sinf.c', 'sinl.c', 'tan.c', 'tanf.c', 'tanl.c', 'acos.c', 'acosf.c', 'acosl.c', 'asin.c', 'asinf.c', 'asinl.c', 'atan.c', 'atanf.c', 'atanl.c', 'atan2.c', 'atan2f.c', 'atan2l.c', 'exp.c', 'expf.c', 'expl.c', 'log.c', 'logf.c', 'logl.c', 'sqrt.c', 'sqrtf.c', 'sqrtl.c', 'fabs.c', 'fabsf.c', 'fabsl.c', 'ceil.c', 'ceilf.c', 'ceill.c', 'floor.c', 'floorf.c', 'floorl.c', 'pow.c', 'powf.c', 'powl.c', 'round.c', 'roundf.c'] # individual math files
)
# TODO: consider using more math code from musl, doing so makes box2d faster
for dirpath, dirnames, filenames in os.walk(musl_srcdir):
for f in filenames:
if f.endswith('.c'):
if f in blacklist: continue
dir_parts = os.path.split(dirpath)
cancel = False
for part in dir_parts:
if part in blacklist:
cancel = True
break
if not cancel:
libc_files.append(os.path.join(musl_srcdir, dirpath, f))
args = ['-Os']
if shared.Settings.USE_PTHREADS:
args += ['-s', 'USE_PTHREADS=1']
assert '-mt' in libname
else:
assert '-mt' not in libname
return build_libc(libname, libc_files, args)
def create_pthreads(libname):
# Add pthread files.
pthreads_files = [os.path.join('pthread', 'library_pthread.c')]
pthreads_files += [shared.path_from_root('system', 'lib', 'libc', 'musl', 'src', 'thread', x) for x in ('pthread_attr_destroy.c', 'pthread_condattr_setpshared.c', 'pthread_mutex_lock.c', 'pthread_spin_destroy.c', 'pthread_attr_get.c', 'pthread_cond_broadcast.c', 'pthread_mutex_setprioceiling.c', 'pthread_spin_init.c', 'pthread_attr_init.c', 'pthread_cond_destroy.c', 'pthread_mutex_timedlock.c', 'pthread_spin_lock.c', 'pthread_attr_setdetachstate.c', 'pthread_cond_init.c', 'pthread_mutex_trylock.c', 'pthread_spin_trylock.c', 'pthread_attr_setguardsize.c', 'pthread_cond_signal.c', 'pthread_mutex_unlock.c', 'pthread_spin_unlock.c', 'pthread_attr_setinheritsched.c', 'pthread_cond_timedwait.c', 'pthread_once.c', 'sem_destroy.c', 'pthread_attr_setschedparam.c', 'pthread_cond_wait.c', 'pthread_rwlockattr_destroy.c', 'sem_getvalue.c', 'pthread_attr_setschedpolicy.c', 'pthread_equal.c', 'pthread_rwlockattr_init.c', 'sem_init.c', 'pthread_attr_setscope.c', 'pthread_getspecific.c', 'pthread_rwlockattr_setpshared.c', 'sem_open.c', 'pthread_attr_setstack.c', 'pthread_key_create.c', 'pthread_rwlock_destroy.c', 'sem_post.c', 'pthread_attr_setstacksize.c', 'pthread_mutexattr_destroy.c', 'pthread_rwlock_init.c', 'sem_timedwait.c', 'pthread_barrierattr_destroy.c', 'pthread_mutexattr_init.c', 'pthread_rwlock_rdlock.c', 'sem_trywait.c', 'pthread_barrierattr_init.c', 'pthread_mutexattr_setprotocol.c', 'pthread_rwlock_timedrdlock.c', 'sem_unlink.c', 'pthread_barrierattr_setpshared.c', 'pthread_mutexattr_setpshared.c', 'pthread_rwlock_timedwrlock.c', 'sem_wait.c', 'pthread_barrier_destroy.c', 'pthread_mutexattr_setrobust.c', 'pthread_rwlock_tryrdlock.c', '__timedwait.c', 'pthread_barrier_init.c', 'pthread_mutexattr_settype.c', 'pthread_rwlock_trywrlock.c', 'vmlock.c', 'pthread_barrier_wait.c', 'pthread_mutex_consistent.c', 'pthread_rwlock_unlock.c', '__wait.c', 'pthread_condattr_destroy.c', 'pthread_mutex_destroy.c', 'pthread_rwlock_wrlock.c', 'pthread_condattr_init.c', 'pthread_mutex_getprioceiling.c', 'pthread_setcanceltype.c', 'pthread_condattr_setclock.c', 'pthread_mutex_init.c', 'pthread_setspecific.c')]
return build_libc(libname, pthreads_files, ['-O2', '-s', 'USE_PTHREADS=1'])
# libcxx
def create_libcxx(libname):
logging.debug('building libcxx for cache')
libcxx_files = [
'algorithm.cpp',
'condition_variable.cpp',
'future.cpp',
'iostream.cpp',
'memory.cpp',
'random.cpp',
'stdexcept.cpp',
'system_error.cpp',
'utility.cpp',
'bind.cpp',
'debug.cpp',
'hash.cpp',
'mutex.cpp',
'string.cpp',
'thread.cpp',
'valarray.cpp',
'chrono.cpp',
'exception.cpp',
'ios.cpp',
'locale.cpp',
'regex.cpp',
'strstream.cpp'
]
return build_libcxx(os.path.join('system', 'lib', 'libcxx'), libname, libcxx_files, ['-Oz', '-I' + shared.path_from_root('system', 'lib', 'libcxxabi', 'include')], has_noexcept_version=True)
# libcxxabi - just for dynamic_cast for now
def create_libcxxabi(libname):
logging.debug('building libcxxabi for cache')
libcxxabi_files = [
'abort_message.cpp',
'cxa_aux_runtime.cpp',
'cxa_default_handlers.cpp',
'cxa_demangle.cpp',
'cxa_exception_storage.cpp',
'cxa_new_delete.cpp',
'cxa_handlers.cpp',
'exception.cpp',
'stdexcept.cpp',
'typeinfo.cpp',
'private_typeinfo.cpp',
os.path.join('..', '..', 'libcxx', 'new.cpp'),
]
return build_libcxx(os.path.join('system', 'lib', 'libcxxabi', 'src'), libname, libcxxabi_files, ['-Oz', '-I' + shared.path_from_root('system', 'lib', 'libcxxabi', 'include')])
# gl
def create_gl(libname): # libname is ignored, this is just one .o file
o = in_temp('gl.o')
check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'gl.c'), '-o', o])
return o
def create_compiler_rt(libname):
srcdir = shared.path_from_root('system', 'lib', 'compiler-rt')
filenames = ['divdc3.c', 'divsc3.c', 'muldc3.c', 'mulsc3.c']
files = (os.path.join(srcdir, f) for f in filenames)
o_s = []
commands = []
for src in files:
o = in_temp(os.path.basename(src) + '.o')
commands.append([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', src), '-O2', '-o', o])
o_s.append(o)
run_commands(commands)
shared.Building.link(o_s, in_temp(libname))
return in_temp(libname)
def create_dlmalloc(out_name, clflags):
o = in_temp(out_name)
check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'dlmalloc.c'), '-o', o] + clflags)
return o
def create_dlmalloc_singlethreaded(libname):
return create_dlmalloc(libname, ['-O2'])
def create_dlmalloc_singlethreaded_tracing(libname):
return create_dlmalloc(libname, ['-O2', '--tracing'])
def create_dlmalloc_multithreaded(libname):
return create_dlmalloc(libname, ['-O2', '-s', 'USE_PTHREADS=1'])
def create_dlmalloc_multithreaded_tracing(libname):
return create_dlmalloc(libname, ['-O2', '-s', 'USE_PTHREADS=1', '--tracing'])
def create_dlmalloc_split(libname):
dlmalloc_o = in_temp('dl' + libname)
check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'dlmalloc.c'), '-o', dlmalloc_o, '-O2', '-DMSPACES', '-DONLY_MSPACES'])
split_malloc_o = in_temp('sm' + libname)
check_call([shared.PYTHON, shared.EMCC, shared.path_from_root('system', 'lib', 'split_malloc.cpp'), '-o', split_malloc_o, '-O2'])
lib = in_temp(libname)
shared.Building.link([dlmalloc_o, split_malloc_o], lib)
return lib
# Setting this in the environment will avoid checking dependencies and make building big projects a little faster
# 1 means include everything; otherwise it can be the name of a lib (libcxx, etc.)
# You can provide 1 to include everything, or a comma-separated list with the ones you want
force = os.environ.get('EMCC_FORCE_STDLIBS')
force_all = force == '1'
force = set((force.split(',') if force else []) + forced)
if force: logging.debug('forcing stdlibs: ' + str(force))
# Setting this will only use the forced libs in EMCC_FORCE_STDLIBS. This avoids spending time checking
# for unresolved symbols in your project files, which can speed up linking, but if you do not have
# the proper list of actually needed libraries, errors can occur. See below for how we must
# export all the symbols in deps_info when using this option.
only_forced = os.environ.get('EMCC_ONLY_FORCED_STDLIBS')
if only_forced:
temp_files = []
# Add in some hacks for js libraries. If a js lib depends on a symbol provided by a C library, it must be
# added to here, because our deps go only one way (each library here is checked, then we check the next
# in order - libcxx, libcxextra, etc. - and then we run the JS compiler and provide extra symbols from
# library*.js files. But we cannot then go back to the C libraries if a new dep was added!
# TODO: Move all __deps from src/library*.js to deps_info.json, and use that single source of info
# both here and in the JS compiler.
deps_info = json.loads(open(shared.path_from_root('src', 'deps_info.json')).read())
added = set()
def add_back_deps(need):
more = False
for ident, deps in deps_info.iteritems():
if ident in need.undefs and not ident in added:
added.add(ident)
more = True
for dep in deps:
need.undefs.add(dep)
shared.Settings.EXPORTED_FUNCTIONS.append('_' + dep)
if more:
add_back_deps(need) # recurse to get deps of deps
# Scan symbols
symbolses = map(lambda temp_file: shared.Building.llvm_nm(temp_file), temp_files)
if len(symbolses) == 0:
class Dummy:
defs = set()
undefs = set()
symbolses.append(Dummy())
# depend on exported functions
for export in shared.Settings.EXPORTED_FUNCTIONS:
if shared.Settings.VERBOSE: logging.debug('adding dependency on export %s' % export)
symbolses[0].undefs.add(export[1:])
for symbols in symbolses:
add_back_deps(symbols)
# If we are only doing forced stdlibs, then we don't know the actual symbols we need,
# and must assume all of deps_info must be exported. Note that this might cause
# warnings on exports that do not exist.
if only_forced:
for key, value in deps_info.iteritems():
for dep in value:
shared.Settings.EXPORTED_FUNCTIONS.append('_' + dep)
all_needed = set()
for symbols in symbolses:
all_needed.update(symbols.undefs)
for symbols in symbolses:
all_needed.difference_update(symbols.defs)
system_libs = [('libcxx', 'a', create_libcxx, libcxx_symbols, ['libcxxabi'], True),
('libcxxabi', 'bc', create_libcxxabi, libcxxabi_symbols, ['libc'], False),
('gl', 'bc', create_gl, gl_symbols, ['libc'], False),
('compiler-rt', 'bc', create_compiler_rt, compiler_rt_symbols, ['libc'], False)]
# malloc dependency is force-added, so when using pthreads, it must be force-added
# as well, since malloc needs to be thread-safe, so it depends on mutexes.
if shared.Settings.USE_PTHREADS:
system_libs += [('libc-mt', 'bc', create_libc, libc_symbols, [], False),
('pthreads', 'bc', create_pthreads, pthreads_symbols, ['libc'], False),
('dlmalloc_threadsafe', 'bc', create_dlmalloc_multithreaded, [], [], False),
('dlmalloc_threadsafe_tracing', 'bc', create_dlmalloc_multithreaded_tracing, [], [], False)]
force.add('pthreads')
if shared.Settings.EMSCRIPTEN_TRACING:
force.add('dlmalloc_threadsafe_tracing')
else:
force.add('dlmalloc_threadsafe')
else:
system_libs += [('libc', 'bc', create_libc, libc_symbols, [], False)]
if shared.Settings.EMSCRIPTEN_TRACING:
system_libs += [('dlmalloc_tracing', 'bc', create_dlmalloc_singlethreaded_tracing, [], [], False)]
force.add('dlmalloc_tracing')
else:
if shared.Settings.SPLIT_MEMORY:
system_libs += [('dlmalloc_split', 'bc', create_dlmalloc_split, [], [], False)]
force.add('dlmalloc_split')
else:
system_libs += [('dlmalloc', 'bc', create_dlmalloc_singlethreaded, [], [], False)]
force.add('dlmalloc')
# Go over libraries to figure out which we must include
def maybe_noexcept(name):
if shared.Settings.DISABLE_EXCEPTION_CATCHING:
name += '_noexcept'
return name
ret = []
has = need = None
for shortname, suffix, create, library_symbols, deps, can_noexcept in system_libs:
force_this = force_all or shortname in force
if can_noexcept: shortname = maybe_noexcept(shortname)
if force_this:
suffix = 'bc' # .a files do not always link in all their parts; don't use them when forced
name = shortname + '.' + suffix
if not force_this:
need = set()
has = set()
for symbols in symbolses:
if shared.Settings.VERBOSE: logging.debug('undefs: ' + str(symbols.undefs))
for library_symbol in library_symbols:
if library_symbol in symbols.undefs:
need.add(library_symbol)
if library_symbol in symbols.defs:
has.add(library_symbol)
for haz in has: # remove symbols that are supplied by another of the inputs
if haz in need:
need.remove(haz)
if shared.Settings.VERBOSE: logging.debug('considering %s: we need %s and have %s' % (name, str(need), str(has)))
if force_this or (len(need) > 0 and not only_forced):
# We need to build and link the library in
logging.debug('including %s' % name)
def do_create():
ret = create(name)
return ret
libfile = shared.Cache.get(name, do_create, extension=suffix)
ret.append(libfile)
force = force.union(deps)
ret.sort(key=lambda x: x.endswith('.a')) # make sure to put .a files at the end.
for actual in ret:
if os.path.basename(actual) == 'libcxxabi.bc':
# libcxxabi and libcxx *static* linking is tricky. e.g. cxa_demangle.cpp disables c++
# exceptions, but since the string methods in the headers are *weakly* linked, then
# we might have exception-supporting versions of them from elsewhere, and if libcxxabi
# is first then it would "win", breaking exception throwing from those string
# header methods. To avoid that, we link libcxxabi last.
ret = filter(lambda f: f != actual, ret) + [actual]
return ret
#---------------------------------------------------------------------------
# emscripten-ports library management (https://github.com/emscripten-ports)
#---------------------------------------------------------------------------
import ports
class Ports:
@staticmethod
def build_port(src_path, output_path, includes=[], flags=[], exclude_files=[], exclude_dirs=[]):
srcs = []
for root, dirs, files in os.walk(src_path, topdown=False):
if any((excluded in root) for excluded in exclude_dirs):
continue
for file in files:
if (file.endswith('.c') or file.endswith('.cpp')) and not any((excluded in file) for excluded in exclude_files):
srcs.append(os.path.join(root, file))
include_commands = ['-I' + src_path ]
for include in includes:
include_commands.append('-I' + include)
commands = []
objects = []
for src in srcs:
obj = src + '.o'
commands.append([shared.PYTHON, shared.EMCC, src, '-O2', '-o', obj, '-w'] + include_commands + flags)
objects.append(obj)
run_commands(commands)
shared.Building.link(objects, output_path)
@staticmethod
def run_commands(commands): # make easily available for port objects
run_commands(commands)
@staticmethod
def get_dir():
dirname = os.environ.get('EM_PORTS') or os.path.expanduser(os.path.join('~', '.emscripten_ports'))
shared.safe_ensure_dirs(dirname)
return dirname
@staticmethod
def erase():
shared.try_delete(Ports.get_dir())
@staticmethod
def get_build_dir():
return shared.Cache.get_path('ports-builds')
name_cache = set()
@staticmethod
def fetch_project(name, url, subdir):
fullname = os.path.join(Ports.get_dir(), name)
if name not in Ports.name_cache: # only mention each port once in log
logging.debug('including port: ' + name)
logging.debug(' (at ' + fullname + ')')
Ports.name_cache.add(name)
class State:
retrieved = False
unpacked = False
def retrieve():
# if EMCC_LOCAL_PORTS is set, we use a local directory as our ports. This is useful
# for testing. This env var should be in format
# name=dir|tag,name=dir|tag
# e.g.
# sdl2=/home/username/dev/ports/SDL2|SDL2-master
# so you could run
# EMCC_LOCAL_PORTS="sdl2=/home/alon/Dev/ports/SDL2|SDL2-master" ./tests/runner.py browser.test_sdl2_mouse
# note that tag **must** be the tag in sdl.py, it is where we store to (not where we load from, we just load the local dir)
local_ports = os.environ.get('EMCC_LOCAL_PORTS')
if local_ports:
local_ports = map(lambda pair: pair.split('='), local_ports.split(','))
for local in local_ports:
if name == local[0]:
path, subdir = local[1].split('|')
logging.warning('grabbing local port: ' + name + ' from ' + path + ', into ' + subdir)
# zip up the directory, so it looks the same as if we downloaded a zip from the remote server
z = zipfile.ZipFile(fullname + '.zip', 'w')
def add_dir(p):
for f in os.listdir(p):
full = os.path.join(p, f)
if os.path.isdir(full):
add_dir(full)
else:
if not f.startswith('.'): # ignore hidden files, including .git/ etc.
z.write(full, os.path.join(subdir, os.path.relpath(full, path)))
add_dir(path)
z.close()
State.retrieved = True
return
# retrieve from remote server
logging.warning('retrieving port: ' + name + ' from ' + url)
import urllib2
f = urllib2.urlopen(url)
data = f.read()
open(fullname + '.zip', 'wb').write(data)
State.retrieved = True
def check_tag():
z = zipfile.ZipFile(fullname + '.zip', 'r')
names = z.namelist()
if not (names[0].startswith(subdir + '/') or names[0].startswith(subdir + '\\')):
# current zip file is old, force a retrieve
return False
return True
def unpack():
logging.warning('unpacking port: ' + name)
shared.safe_ensure_dirs(fullname)
z = zipfile.ZipFile(fullname + '.zip', 'r')
try:
cwd = os.getcwd()
os.chdir(fullname)
z.extractall()
finally:
os.chdir(cwd)
State.unpacked = True
# main logic
if not os.path.exists(fullname + '.zip'):
retrieve()
if not os.path.exists(fullname):
unpack()
if not check_tag():
logging.warning('local copy of port is not correct, retrieving from remote server')
shared.try_delete(fullname)
shared.try_delete(fullname + '.zip')
retrieve()
unpack()
if State.unpacked:
# we unpacked a new version, clear the build in the cache
Ports.clear_project_build(name)
@staticmethod
def build_project(name, subdir, configure, generated_libs, post_create=None):
def create():
logging.warning('building port: ' + name + '...')
port_build_dir = Ports.get_build_dir()
shared.safe_ensure_dirs(port_build_dir)
libs = shared.Building.build_library(name, port_build_dir, None, generated_libs, source_dir=os.path.join(Ports.get_dir(), name, subdir), copy_project=True,
configure=configure, make=['make', '-j' + str(CORES)])
assert len(libs) == 1
if post_create: post_create()
return libs[0]
return shared.Cache.get(name, create)
@staticmethod
def clear_project_build(name):
shared.try_delete(os.path.join(Ports.get_build_dir(), name))
shared.try_delete(shared.Cache.get_path(name + '.bc'))
def get_ports(settings):
ret = []
ok = False
try:
process_dependencies(settings)
for port in ports.ports:
ret += port.get(Ports, settings, shared)
ok = True
finally:
if not ok:
logging.error('a problem occurred when using an emscripten-ports library. try to run emcc --clear-cache --clear-ports and then run this command again')
ret.reverse()
return ret
def process_dependencies(settings):
for port in reversed(ports.ports):
if hasattr(port, "process_dependencies"):
port.process_dependencies(settings)
def process_args(args, settings):
process_dependencies(settings)
for port in ports.ports:
args = port.process_args(Ports, args, settings, shared)
return args
def show_ports():
print 'Available ports:'
for port in ports.ports:
print ' ', port.show()