mirror of
https://github.com/google/pebble.git
synced 2025-03-15 00:31:21 +00:00
197 lines
6.9 KiB
Python
197 lines
6.9 KiB
Python
# Copyright 2024 Google LLC
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""
|
|
Waftool that wraps the 'cprogram' feature and extends it with
|
|
Emscripten-specific variables, examples:
|
|
|
|
bld.program(source=sources,
|
|
target=target,
|
|
emx_pre_js_files=[], # list of nodes used with --pre-js
|
|
emx_post_js_files=[], # list of nodes used with --post-js
|
|
emx_exported_functions=node, # node to use with EXPORTED_FUNCTIONS
|
|
emx_other_settings=[], # list of -s settings
|
|
emx_embed_files=[pbpack], # list of nodes used with --embed-file
|
|
)
|
|
|
|
Also adds these optional env variables:
|
|
|
|
bld.env.EMX_PRE_JS_FILES = []
|
|
bld.env.EMX_POST_JS_FILES = []
|
|
bld.env.EMX_EXPORTED_FUNCTIONS = []
|
|
bld.env.EMX_OTHER_SETTINGS = []
|
|
bld.env.EMX_EMBED_FILES = []
|
|
bld.env.EMCC_DEBUG = 2
|
|
bld.env.EMCC_CORES = 1
|
|
|
|
"""
|
|
|
|
import os
|
|
from waflib import Logs, Task, TaskGen
|
|
|
|
|
|
# Insipred on https://github.com/waf-project/waf/blob/4ff5b8b7a74dd2ad23600ed7af6a505b90235387/playground/strip/strip.py
|
|
def wrap_cprogram_task_class():
|
|
classname = 'cprogram'
|
|
orig_cls = Task.classes[classname]
|
|
emx_cls = type(classname, (orig_cls,), {
|
|
'run_str': '${CC} ${CFLAGS} ${DEFINES_ST:DEFINES} ${CPPPATH_ST:INCPATHS} ${SRC} -o ${TGT[0].abspath()} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${EMCC_SETTINGS}',
|
|
'ext_out': ['.js'],
|
|
# *waf* env vars that affect the output and thus should trigger a rebuild.
|
|
# This is by no means a complete list, but just the stuff we use today.
|
|
'vars': [
|
|
'EMCC_DEBUG',
|
|
'EMCC_CORES',
|
|
'EMCC_SETTINGS',
|
|
'LINKDEPS'
|
|
],
|
|
'color': 'ORANGE',
|
|
})
|
|
wrapper_cls = type(classname, (emx_cls,), {})
|
|
|
|
def init(self, *k, **kw):
|
|
Task.Task.__init__(self, *k, **kw)
|
|
# Set relevant OS environment variables:
|
|
self.env.env = {}
|
|
self.env.env.update(os.environ)
|
|
for key in ['EMCC_DEBUG', 'EMCC_CORES', 'EM_CACHE']:
|
|
if self.env[key]: # If not explicitely set, empty list is returned
|
|
self.env.env[key] = str(self.env[key])
|
|
emx_cls.__init__ = init
|
|
|
|
def run(self):
|
|
if self.env.CC != 'emcc':
|
|
return orig_cls.run(self)
|
|
return emx_cls.run(self)
|
|
wrapper_cls.run = run
|
|
|
|
|
|
cache_primer_node_by_cache_path = {}
|
|
|
|
|
|
def add_cache_primer_node_if_needed(bld, env):
|
|
def get_cache_path(env):
|
|
return env.EM_CACHE if env.EM_CACHE else '~/.emscripten_cache'
|
|
|
|
cache_path = get_cache_path(env)
|
|
existing_primer_node = \
|
|
cache_primer_node_by_cache_path.get(cache_path, None)
|
|
if existing_primer_node:
|
|
return existing_primer_node
|
|
# Build a tiny "hello world" C program to prime the caches:
|
|
primer_node = bld.path.get_bld().make_node('emscripten-cache-primer.js')
|
|
source_node = bld.path.find_node('waftools/emscripten-cache-primer-main.c')
|
|
primer_env = env.derive().detach()
|
|
# Force -O2, this will cause optimizer.exe (part of cached files) to be
|
|
# compiled:
|
|
primer_env['CFLAGS'] = filter(
|
|
lambda flag: flag not in ['-O0', '-O1', '-O3', '-Oz', '-Os'],
|
|
primer_env['CFLAGS']
|
|
)
|
|
primer_env['CFLAGS'].append('-O2')
|
|
bld.program(
|
|
source=[source_node],
|
|
target=primer_node,
|
|
env=primer_env)
|
|
cache_primer_node_by_cache_path[cache_path] = primer_node
|
|
return primer_node
|
|
|
|
|
|
@TaskGen.feature('cprogram')
|
|
@TaskGen.after_method('apply_link')
|
|
def process_emscripten_cprogram_link_args(self):
|
|
task = self.link_task
|
|
task.env.EMCC_SETTINGS = []
|
|
|
|
def add_emcc_settings(*args):
|
|
for val_or_node in args:
|
|
if isinstance(val_or_node, basestring):
|
|
val = val_or_node
|
|
else:
|
|
val = val_or_node.abspath()
|
|
task.dep_nodes.append(val_or_node)
|
|
task.env.EMCC_SETTINGS.append(val)
|
|
|
|
def get_rule_and_env_values(var_name):
|
|
# Rule values first:
|
|
vals = getattr(self, var_name.lower(), [])
|
|
# Add env values to the end:
|
|
vals.extend(getattr(self.env, var_name.upper()))
|
|
return vals
|
|
|
|
def get_single_rule_or_env_value(var_name):
|
|
val = getattr(self, var_name.lower(), None)
|
|
if val:
|
|
return val
|
|
return getattr(self.env, var_name.upper(), None)
|
|
|
|
for node in get_rule_and_env_values('emx_pre_js_files'):
|
|
add_emcc_settings('--pre-js', node)
|
|
for node in get_rule_and_env_values('emx_post_js_files'):
|
|
add_emcc_settings('--post-js', node)
|
|
|
|
transform_js_node_and_args = \
|
|
get_single_rule_or_env_value('emx_transform_js_node_and_args')
|
|
if transform_js_node_and_args:
|
|
add_emcc_settings('--js-transform', *transform_js_node_and_args)
|
|
|
|
exported_functions = get_single_rule_or_env_value('emx_exported_functions')
|
|
if exported_functions:
|
|
exported_func_path = self.emx_exported_functions.abspath()
|
|
add_emcc_settings(
|
|
'-s', 'EXPORTED_FUNCTIONS=@{}'.format(exported_func_path))
|
|
task.dep_nodes.append(self.emx_exported_functions)
|
|
|
|
for node in get_rule_and_env_values('emx_embed_files'):
|
|
add_emcc_settings('--embed-file', node)
|
|
|
|
for s in get_rule_and_env_values('emx_other_settings'):
|
|
add_emcc_settings('-s', s)
|
|
|
|
# Emscripten implicitely regenerates caches (libc.bc, dlmalloc.bc,
|
|
# struct_info.compiled.json and optimizer.exe) as needed.
|
|
# When running multiple instantiations of emcc in parallel, this is
|
|
# problematic because they will each race to generate the caches,
|
|
# using the same locations for writing/using/executing them.
|
|
# See also https://github.com/kripken/emscripten/issues/4151
|
|
|
|
if self.env.CC == 'emcc':
|
|
primer_node = add_cache_primer_node_if_needed(self.bld, self.env)
|
|
if task.outputs[0] != primer_node:
|
|
task.dep_nodes.append(primer_node)
|
|
|
|
|
|
def build(bld):
|
|
wrap_cprogram_task_class()
|
|
|
|
|
|
def configure(conf):
|
|
conf.find_program('emcc', errmsg='emscripten is not installed')
|
|
conf.find_program('em-config', var='EM-CONFIG')
|
|
|
|
conf.env.EMSCRIPTEN_ROOT = conf.cmd_and_log([
|
|
'em-config', 'EMSCRIPTEN_ROOT'
|
|
]).rstrip()
|
|
Logs.pprint(
|
|
'YELLOW', 'Emscripten path is {}'.format(conf.env.EMSCRIPTEN_ROOT))
|
|
conf.env.CC = 'emcc'
|
|
conf.env.LINK_CC = 'emcc'
|
|
conf.env.AR = 'emar'
|
|
|
|
# Don't look at the host system headers:
|
|
conf.env.CFLAGS.extend([
|
|
'-nostdinc',
|
|
'-Xclang', '-nobuiltininc',
|
|
'-Xclang', '-nostdsysteminc'
|
|
])
|