mirror of https://github.com/google/pebble
				
				
				
			
		
			
				
	
	
		
			276 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			276 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)))
 |