mirror of
https://github.com/google/pebble.git
synced 2025-03-15 16:51:21 +00:00
276 lines
12 KiB
Text
276 lines
12 KiB
Text
|
#
|
||
|
# 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)))
|