pebble/sdk/wscript
2025-01-27 11:38:16 -08:00

275 lines
12 KiB
Python

#
# This waf script is responsible for building the SDK which can be shipped off to users into
# tintin/build/sdk/src_wscript is the file which app developers actually run to build their apps
#
import json
import os
import waflib
from string import Template
from tools.fw_elf_obfuscate import obfuscate
COPY = "cp ${SRC} ${TGT}"
def _generate_sdk_waf(ctx):
"""
Build a custom version of waf that includes the waf plugins we need
:param bld:
:return:
"""
sdk_waftools = [tool.path_from(ctx.path.parent) for tool in ctx.path.ant_glob('waftools/*.py')]
shared_waftools = [
"tools/resources/waftools/generate_resource_ball.py",
"tools/resources/waftools/generate_pbpack.py",
"tools/resources/waftools/generate_resource_id_header.py",
"waftools/file_name_c_define.py",
"waftools/ldscript.py",
"waftools/objcopy.py",
"waftools/pebble_sdk_gcc.py",
"waftools/pebble_sdk_version.py",
"waftools/xcode_pebble.py"
]
pebble_waf_tools = []
for tool in sdk_waftools + shared_waftools:
path = ctx.path.parent.find_node(tool)
if path is None:
ctx.fatal("Trying to bundle non existent resource in pb-waf ({})".format(tool))
pebble_waf_tools.append(path)
# We cannot run this as a sub-wscript because we use a specific vendor-provided
# wscript that provides the --make-waf option and needs to be run in its own clean
# environment
def _build_waf(task):
bld = task.generator.bld
cmd_str = ('cd "{}" && python "{}" distclean configure build --make-waf --tools="{}" &&'
'cp waf "{}"'.format(waf_folder.abspath(),
task.inputs[0].abspath(),
','.join(x.abspath() for x in task.inputs[1:]),
task.outputs[0].abspath()))
try:
bld.cmd_and_log(cmd_str, quiet=waflib.Context.BOTH)
except waflib.Errors.WafError as e:
bld.to_log("out: %s" % e.stdout)
bld.to_log("err: %s" % e.stderr)
raise e
waf_folder = ctx.path.find_node('waf')
waf_light = waf_folder.find_node('waf-light')
ctx(rule=_build_waf,
source=[waf_light, ] + pebble_waf_tools,
target=waf_folder.get_bld())
def _copy_common_tools(bld, common_folder_node):
"""
Copy SDK tools into common/waftools and common/tools
:param bld:
:param common_folder_node:
:return:
"""
for tool in bld.path.ant_glob(['tools/**/*']):
bld(rule=COPY,
source=tool,
target=common_folder_node.make_node(tool.path_from(bld.path)))
shared_tools = [
"tools/binutils.py",
"tools/bitmapgen.py",
"tools/font/__init__.py",
"tools/font/fontgen.py",
"tools/generate_appinfo.py",
"tools/generate_c_byte_array.py",
"tools/mkbundle.py",
"tools/pbpack.py",
"tools/pbpack_meta_data.py",
"tools/pebble_image_routines.py",
"tools/pebble_sdk_platform.py",
"tools/png2pblpng.py",
"tools/stm32_crc.py"
]
if bld.env.INTERNAL_SDK_BUILD:
shared_tools.append("tools/pebble_sdk_platform_internal.py")
for tool in shared_tools:
bld(rule=COPY,
source=bld.path.parent.find_node(tool),
target=common_folder_node.make_node(tool))
resource_waftools = [
"tools/resources/__init__.py",
"tools/resources/find_resource_filename.py",
"tools/resources/resource_map/__init__.py",
"tools/resources/resource_map/resource_generator.py",
"tools/resources/resource_map/resource_generator_bitmap.py",
"tools/resources/resource_map/resource_generator_font.py",
"tools/resources/resource_map/resource_generator_js.py",
"tools/resources/resource_map/resource_generator_pbi.py",
"tools/resources/resource_map/resource_generator_png.py",
"tools/resources/resource_map/resource_generator_raw.py",
"tools/resources/types/__init__.py",
"tools/resources/types/resource_ball.py",
"tools/resources/types/resource_declaration.py",
"tools/resources/types/resource_definition.py",
"tools/resources/types/resource_object.py"
]
for tool in resource_waftools:
tool_node = bld.path.parent.find_node(tool)
bld(rule=COPY,
source=tool_node,
target=(common_folder_node.make_node('waftools')
.make_node(tool_node.path_from(bld.path.parent.find_node('tools')))))
def options(opt):
opt.add_option('--sdk_debug_elf', action='store_true',
help='Enable building obfuscated ELF files for SDK debugging.')
def configure(conf):
if conf.options.sdk_debug_elf:
conf.env.INCLUDE_SDK_DEBUG_ELF = True
def build(bld):
bld(rule=COPY,
source=bld.path.find_node('sdk_requirements.txt'),
target=bld.path.get_bld().make_node('requirements.txt'))
bld(rule=COPY,
source=bld.path.find_node('sdk_package.json'),
target=bld.path.get_bld().make_node('package.json'))
bld(rule=COPY,
source=bld.path.find_node('use_requirements.json'),
target=bld.path.get_bld().make_node('use_requirements.json'))
tintin_home = bld.path.parent
platform_folder_node = bld.path.get_bld().make_node(bld.env.PLATFORM_NAME)
platform_folder_node.parent.mkdir()
bld(features='subst',
source=bld.path.find_node('Doxyfile-SDK.template'),
target=platform_folder_node.make_node('Doxyfile-SDK.auto'),
TINTIN_ROOT=tintin_home.abspath(),
PLATFORM_PATH=platform_folder_node.path_from(bld.path.parent))
common_folder_node = bld.path.get_bld().make_node('common')
common_folder_node.parent.mkdir()
for sdk_file in bld.path.ant_glob(['include/*', 'pebble_app.ld.template']):
bld(rule=COPY,
source=sdk_file,
target=common_folder_node.make_node(sdk_file.path_from(bld.path)))
if not bld.env.NOJS:
js_tooling_path = os.path.dirname(bld.env.JS_TOOLING_SCRIPT.relpath())
for js_tool in ('js_tooling.js', 'generate_snapshot.js'):
bld(rule=COPY,
source=bld.path.parent.get_bld().make_node(js_tooling_path).make_node(js_tool),
target=common_folder_node.make_node('tools').make_node(js_tool),
name='copy_rocky_tooling')
template_folder_node = common_folder_node.make_node('templates')
template_folder_node.parent.mkdir()
defaults_node = bld.path.find_node('defaults')
# Check whether the default project files are valid templates:
with open(defaults_node.find_node('templates.json').abspath()) as f:
templates = json.load(f)
def _collect_check_templates_tasks(dct):
for key in dct:
val = dct[key]
if isinstance(val, basestring):
# avoid unicode, it will trip up waf's Node3 and make it 💩 all over the place
val = str(val)
template_node = defaults_node.find_node(val.split(os.path.sep))
if not template_node:
waflib.Logs.warn(
"Could not find {}, but it's defined in "
"templates.json".format(val))
continue
with open(template_node.abspath()) as tf:
try:
Template(tf.read()).substitute()
except KeyError:
pass # This is expected, no args to substitute()
except ValueError as e:
bld.fatal(
"Template error in {}:\n{}\n"
"Hint: make sure to escape dollar signs! ($ => $$)".format(
template_node.abspath(), e.message))
elif isinstance(val, dict):
_collect_check_templates_tasks(val)
_collect_check_templates_tasks(templates)
# Copy default SDK project files
for default_file in bld.path.ant_glob('defaults/**/*'):
bld(rule=COPY,
source=default_file,
target=template_folder_node.make_node(default_file.path_from(defaults_node)))
# Generate shims
# We shell out to this script because it imports the clang module, which does not run correctly
# under pypy. By running python explicitly when calling this script, we avoid the
# incompatibility with pypy and clang.
native_generator_script = (
bld.path.parent.find_node('tools/generate_native_sdk/generate_pebble_native_sdk_files.py'))
export_symbols = bld.path.parent.find_node('tools/generate_native_sdk/exported_symbols.json')
source_dir = bld.path.parent.find_node('src')
output_source_dir = source_dir.get_bld()
with open(export_symbols.abspath()) as f:
native_generator_sources = (
[source_dir.find_node(str(header)) for header in json.load(f)['files']])
native_generator_sources.append(export_symbols)
native_generator_targets = [bld.path.parent.make_node('src/fw/pebble.auto.c').get_bld(),
platform_folder_node.make_node('include/pebble.h'),
platform_folder_node.make_node('include/pebble_sdk_version.h'),
platform_folder_node.make_node('include/pebble_process_info.h'),
platform_folder_node.make_node('include/pebble_worker.h'),
platform_folder_node.make_node('include/pebble_worker_sdk_version.h')]
bld(rule="cd '{}' ; python '{}' --sdk-dir='{}' '{}' '{}' '{}' '{}' {}".
format(tintin_home.abspath(),
native_generator_script.abspath(),
platform_folder_node.abspath(),
export_symbols.abspath(),
source_dir.abspath(),
output_source_dir.abspath(),
bld.env.PLATFORM_NAME,
'--internal-sdk-build' if bld.env.INTERNAL_SDK_BUILD else ''),
name="generate_native_sdk",
source=native_generator_sources,
target=native_generator_targets)
_generate_sdk_waf(bld)
_copy_common_tools(bld, common_folder_node)
# Generate our exported font header based on the whitelist in exported_symbols.json.
# This is different than our internal header (font_resource_keys.auto.h) as it excludes
# some fonts that we don't want to export
def _generate_pebble_fonts_h(task):
with open(task.outputs[0].abspath(), 'w') as f_out:
f_out.write('#pragma once\n')
f_out.write('\n')
with open(task.inputs[0].abspath(), 'r') as f_in:
font_list = json.load(f_in)["fonts"]
for font in font_list:
f_out.write('#define FONT_KEY_{0} "RESOURCE_ID_{0}"\n'.format(font))
# Copy any font keys over to the SDK
bld(rule=_generate_pebble_fonts_h,
source=export_symbols,
target=platform_folder_node.make_node('include/pebble_fonts.h'))
# Generate obfuscated elf file for GDB debugging
if bld.env.INCLUDE_SDK_DEBUG_ELF:
def _obfuscate_elf(task):
input_elf = task.inputs[0].abspath()
output_elf = task.outputs[0].abspath()
obfuscate(input_elf, output_elf, no_text=False)
firmware_build_node = bld.path.parent.get_bld().find_or_declare('src').find_or_declare('fw')
bld(rule=_obfuscate_elf,
source=firmware_build_node.make_node('tintin_fw.elf'),
target=bld.path.get_bld().make_node('{}_sdk_debug.elf'.format(bld.env.PLATFORM_NAME)))