#PDR15 - waf, wscript and Your Pebble App

68
2015 Pebble Developer Retreat waf, wscript & Your Pebble App Cherie Williams - Troublemaker

Transcript of #PDR15 - waf, wscript and Your Pebble App

Page 1: #PDR15 - waf, wscript and Your Pebble App

2015 Pebble Developer Retreat

waf, wscript & Your Pebble App

Cherie Williams - Troublemaker

Page 2: #PDR15 - waf, wscript and Your Pebble App

Agenda

•Why modify my wscript? •Pebble SDK & Fat PBW •What is this “waf” thing? •Why is Pebble using waf? •wscript •Why do I care about waf? •wscript Recipes •Debugging

Page 3: #PDR15 - waf, wscript and Your Pebble App

Why modify my wscript?Making the Pebble SDK build system work for you

Page 4: #PDR15 - waf, wscript and Your Pebble App

You can…

•Add C compiler flags

•Add custom defines for your apps (eg. #ifdef NOLOG)

•Concatenate multiple JS files or do other file manipulations at build time

Page 5: #PDR15 - waf, wscript and Your Pebble App

You can…

•Collect & build source from a non-standard project

•Add a linter (or two!)

•Run arbitrary scripts at build time to modify resources or other files

Page 6: #PDR15 - waf, wscript and Your Pebble App

You can…

•Add automatic testing

•Profile builds or add build visualizations

•Read in arbitrary text at build (eg. appinfo.json)

Page 7: #PDR15 - waf, wscript and Your Pebble App

You can…

•Include an external library

•Build libraries for distribution

…the possibilities are endless!

Page 8: #PDR15 - waf, wscript and Your Pebble App

Fine PrintRecipes + content from today’s talk are

*not* compatible with CloudPebble

Page 9: #PDR15 - waf, wscript and Your Pebble App

Pebble SDK & Fat PBW

Page 10: #PDR15 - waf, wscript and Your Pebble App

SDK: Capabilities Today

•Builds for up to 3 Pebble platforms

•Can build apps, as well as workers •Handles platform-specific resources •Packages a single PBW for distribution

aplite Pebble Classic Pebble Steel

basalt Pebble Time Pebble Time Steel

chalk Pebble Time Round

Page 11: #PDR15 - waf, wscript and Your Pebble App
Page 12: #PDR15 - waf, wscript and Your Pebble App

What is this “waf” thing?A brief introduction to the Pebble build system

Page 13: #PDR15 - waf, wscript and Your Pebble App

Introducing waf, a Python build system

•Open source, actively maintained •Active community on Google Groups •Task parallelization & dependency handling •Language agnostic, but includes C compiler support • Integrates with Eclipse, Visual Studio and Xcode • Includes framework to build & distribute custom build systems

Page 14: #PDR15 - waf, wscript and Your Pebble App

Why is Pebble using waf?

Page 15: #PDR15 - waf, wscript and Your Pebble App

This guy

Page 16: #PDR15 - waf, wscript and Your Pebble App

Why Pebble uses waf

•Efficiently handles dependencies for large, complex projects (such as Pebble firmware) •Python!! •Easy method overriding •Can package & distribute additional scripts in the SDK •Convenience modules for Logs, Node and methods for easy file substitutions

Page 17: #PDR15 - waf, wscript and Your Pebble App

wscriptThe build script behind waf

Page 18: #PDR15 - waf, wscript and Your Pebble App

Basic wscript (non-Pebble)

def configure(ctx): print "Configure"

def build(ctx): print "Build"

Page 19: #PDR15 - waf, wscript and Your Pebble App

Basic wscript

$ waf configure buildSetting top to : /Users/cherie/waf-demo/defaultSetting out to : /Users/cherie/waf-demo/default/buildConfigure'configure' finished successfully (0.009s)Waf: Entering directory '/Users/cherie/waf-demo/default/build'BuildWaf: Leaving directory '/Users/cherie/waf-demo/default/build''build' finished successfully (0.009s)

Page 20: #PDR15 - waf, wscript and Your Pebble App

Invoking waf via the pebble-tool

pebble clean waf distclean

pebble build waf configure build (-v)

pebble build (-- --other-flags) waf configure build (--other-flags)

Page 21: #PDR15 - waf, wscript and Your Pebble App

Standard Pebble wscriptdef options(ctx): ctx.load('pebble_sdk')

def configure(ctx): ctx.load('pebble_sdk')

def build(ctx): ctx.load('pebble_sdk')

build_worker = os.path.exists('worker_src') binaries = []

for p in ctx.env.TARGET_PLATFORMS: ctx.set_env(ctx.all_envs[p]) ctx.set_group(ctx.env.PLATFORM_NAME) app_elf='{}/pebble-app.elf'.format(ctx.env.BUILD_DIR) ctx.pbl_program(source=ctx.path.ant_glob('src/**/*.c'), target=app_elf)

if build_worker: worker_elf='{}/pebble-worker.elf'.format(ctx.env.BUILD_DIR) binaries.append({'platform': p, 'app_elf': app_elf, 'worker_elf': worker_elf}) ctx.pbl_worker(source=ctx.path.ant_glob('worker_src/**/*.c'), target=worker_elf) else: binaries.append({'platform': p, 'app_elf': app_elf})

ctx.set_group('bundle') ctx.pbl_bundle(binaries=binaries, js=ctx.path.ant_glob('src/js/**/*.js'))

Read in command line options

Configure environment for build

Run build

For each HW platform: •Create app binary •Create worker binary (optional)

Bundle into PBW

Page 22: #PDR15 - waf, wscript and Your Pebble App
Page 23: #PDR15 - waf, wscript and Your Pebble App
Page 24: #PDR15 - waf, wscript and Your Pebble App

Why do I care about waf?Understanding how your Pebble project is built

Page 25: #PDR15 - waf, wscript and Your Pebble App

wscriptThe build script behind waf

Page 26: #PDR15 - waf, wscript and Your Pebble App

Basic wscript (non-Pebble)

def configure(ctx): print "Configure"

def build(ctx): print "Build"

Page 27: #PDR15 - waf, wscript and Your Pebble App

Glossary

Context An object for each command executed that stores all the information necessary for the command execution

BuildContext The build context holds all the information necessary for a build

Page 28: #PDR15 - waf, wscript and Your Pebble App

Basic wscript (non-Pebble)

def configure(ctx): print "Configure"

def build(ctx): print "Build"

Page 29: #PDR15 - waf, wscript and Your Pebble App

Modified Basic wscript

def configure(ctx): ctx.env.MESSAGE = "Hello World"

def build(ctx): pass

Page 30: #PDR15 - waf, wscript and Your Pebble App

Glossary

Environment A group of settings and variables that are stored in a Context and that is cached between execution of commands

NOTE: A single Context can have many, arbitrary environments

Page 31: #PDR15 - waf, wscript and Your Pebble App

build/c4che/*.pyAR = 'arm-none-eabi-gcc-ar'ARFLAGS = 'rcs'AS = 'arm-none-eabi-gcc'BINDIR = '/usr/local/bin'BUILD_DIR = 'basalt'CC = ['arm-none-eabi-gcc']CCLNK_SRC_F = []CCLNK_TGT_F = ['-o']CC_NAME = 'gcc'CC_SRC_F = []CC_TGT_F = ['-c', '-o']CC_VERSION = ('4', '8', '4')CFLAGS = ['-std=c99', '-mcpu=cortex-m3', '-mthumb', '-ffunction-sections', '-fdata-sections', '-g', '-Os', '-D_TIME_H_', '-Wall', '-Wextra', '-Werror', '-Wno-unused-parameter', '-Wno-error=unused-function', '-Wno-error=unused-variable']CFLAGS_MACBUNDLE = ['-fPIC']CFLAGS_cshlib = ['-fPIC']CPPPATH_ST = '-I%s'DEFINES = ['RELEASE', 'PBL_PLATFORM_BASALT', 'PBL_COLOR', 'PBL_RECT', 'PBL_SDK_3']DEFINES_ST = '-D%s'DEST_BINFMT = 'elf'DEST_CPU = 'arm'DEST_OS = 'darwin'INCLUDES = ['basalt']LD = 'arm-none-eabi-ld'LIBDIR = '/usr/local/lib'LIBPATH_ST = '-L%s'LIB_ST = ‘-l%s'LINKFLAGS = ['-mcpu=cortex-m3', '-mthumb', '-Wl,--gc-sections', '-Wl,--warn-common', '-Os']

LINKFLAGS_MACBUNDLE = ['-bundle', '-undefined', 'dynamic_lookup']LINKFLAGS_cshlib = ['-shared']LINKFLAGS_cstlib = ['-Wl,-Bstatic']LINK_CC = ['arm-none-eabi-gcc']MESSAGE = ‘Hello World'PBW_BIN_DIR = 'basalt'PEBBLE_SDK = '/Users/cherie/pebble-dev/PebbleSDK-dev/Pebble/basalt'PEBBLE_SDK_COMMON = '/Users/cherie/pebble-dev/PebbleSDK-dev/Pebble/common'PLATFORM = {'PBW_BIN_DIR': 'basalt', 'TAGS': ['basalt', 'color', 'rect'], 'ADDITIONAL_TEXT_LINES_FOR_PEBBLE_H': [], 'MAX_APP_BINARY_SIZE': 65536, 'MAX_RESOURCES_SIZE': 1048576, 'MAX_APP_MEMORY_SIZE': 65536, 'MAX_WORKER_MEMORY_SIZE': 10240, 'NAME': 'basalt', 'BUILD_DIR': 'basalt', 'MAX_RESOURCES_SIZE_APPSTORE': 262144, 'DEFINES': ['PBL_PLATFORM_BASALT', 'PBL_COLOR', 'PBL_RECT']}PLATFORM_NAME = 'basalt'PREFIX = '/usr/local'RPATH_ST = '-Wl,-rpath,%s'SDK_VERSION_MAJOR = 5SDK_VERSION_MINOR = 70SHLIB_MARKER = NoneSIZE = 'arm-none-eabi-size'SONAME_ST = '-Wl,-h,%s'STLIBPATH_ST = '-L%s'STLIB_MARKER = NoneSTLIB_ST = '-l%s'TARGET_PLATFORMS = [u'basalt', u'aplite']cprogram_PATTERN = '%s'cshlib_PATTERN = 'lib%s.so'cstlib_PATTERN = 'lib%s.a'macbundle_PATTERN = '%s.bundle'

Page 32: #PDR15 - waf, wscript and Your Pebble App

Modified Basic wscript

def configure(ctx): ctx.env.MESSAGE = "Hello World"

def build(ctx): ctx(rule="echo ${MESSAGE}", source='', target='')

Page 33: #PDR15 - waf, wscript and Your Pebble App

Glossary

Task Generator An object that handles the creation of task instances, and helps simplify the creation of ordering constraints

Task An object that represents the production of something during the build (files, in general) and may be executed in sequence or in parallel

Page 34: #PDR15 - waf, wscript and Your Pebble App

${MESSAGE} is shorthand for ctx.env.MESSAGE

Page 35: #PDR15 - waf, wscript and Your Pebble App

Modified Basic wscript

$ ../Pebble/waf configure buildSetting top to : /Users/cherie/waf-demo/defaultSetting out to : /Users/cherie/waf-demo/default/build'configure' finished successfully (0.002s)Waf: Entering directory '/Users/cherie/waf-demo/default/build'[1/1] echo ${MESSAGE}:Hello WorldWaf: Leaving directory '/Users/cherie/waf-demo/default/build''build' finished successfully (0.030s)

Page 36: #PDR15 - waf, wscript and Your Pebble App

Modified Basic wscript w/Dependency

def build(ctx): ctx(rule="echo 'hello' > ${TGT}", source='', target='message.txt')

ctx(rule="cp ${SRC} ${TGT}", source='message.txt', target='copy.txt')

Page 37: #PDR15 - waf, wscript and Your Pebble App

Glossary

Build Order The sequence in which tasks must be executed.

Dependency A dependency represents the conditions by which a task can be considered up-to-date or not, and can be explicit (dependency on file inputs & outputs) or abstract (dependency on a value). waf uses dependencies to determine whether tasks need to be run (changed checksum of source files) and the build order of tasks.

Page 38: #PDR15 - waf, wscript and Your Pebble App

${SRC} and ${TGT} are shorthand for source and target

Page 39: #PDR15 - waf, wscript and Your Pebble App

Pebble Project BuildLet’s see how dependencies work

Page 40: #PDR15 - waf, wscript and Your Pebble App
Page 41: #PDR15 - waf, wscript and Your Pebble App

Glossary

Node A data structure used to represent the filesystem. Nodes may represent files or folders. File nodes are associated with signatures, which can be hashes of the file contents (source files) or task signatures (build files)

Page 42: #PDR15 - waf, wscript and Your Pebble App

Node != Existing File

Page 43: #PDR15 - waf, wscript and Your Pebble App

Glossary

Command A function defined in the wscript file that is executed when its name is given on the command-line, and can be chained with other commands

Ex: waf distclean (`pebble clean`) waf configure build (`pebble build`)

Page 44: #PDR15 - waf, wscript and Your Pebble App
Page 45: #PDR15 - waf, wscript and Your Pebble App

Agenda

•Why modify my wscript? •Pebble SDK & Fat PBW •What is this “waf” thing? •Why is Pebble using waf? •wscript •Why do I care about waf? •wscript Recipes •Debugging

Page 46: #PDR15 - waf, wscript and Your Pebble App

wscript Recipeshttps://developer.getpebble.com/build

Page 47: #PDR15 - waf, wscript and Your Pebble App

Recipe #1

Add compile time flags

Page 48: #PDR15 - waf, wscript and Your Pebble App

Create waftools/pedantic.py

def configure(ctx): ctx.env.append_value('CFLAGS', '-pedantic')

def configure(ctx): ctx.load('pebble_sdk')+ ctx.load('pedantic', tooldir='waftools')

Add to wscript

Page 49: #PDR15 - waf, wscript and Your Pebble App

[23/35] c: src/default.c -> build/src/default.c.18.oIn file included from ../src/default.c:1:0:/Users/cherie/pebble-dev/PebbleSDK-dev/Pebble/aplite/include/pebble.h:974:33: error: ISO C does not permit named variadic macros [-Werror=variadic-macros] #define APP_LOG(level, fmt, args...) \ ^/Users/cherie/pebble-dev/PebbleSDK-dev/Pebble/aplite/include/pebble.h:1121:3: error: type of bit-field 'type' is a GCC extension [-Werror=pedantic] TupleType type:8; ^/Users/cherie/pebble-dev/PebbleSDK-dev/Pebble/aplite/include/pebble.h:1132:13: error: ISO C forbids zero-size array 'data' [-Werror=pedantic] uint8_t data[0]; ^

Page 50: #PDR15 - waf, wscript and Your Pebble App

Recipe #2

Add build options & associated defines

Page 51: #PDR15 - waf, wscript and Your Pebble App

Create waftools/defines.pydef options(ctx): ctx.add_option('--no-log', action='store_true', default=False, help="Mark a build to exclude app logging output")

def configure(ctx): if ctx.options.no_log: ctx.env.append_value('DEFINES', 'NOLOG')

Add to wscript for options & configurectx.load('defines', tooldir='waftools')

Page 52: #PDR15 - waf, wscript and Your Pebble App

Add to main project.c file

#include <pebble.h>#if defined(NOLOG)#undef APP_LOG#define APP_LOG(...)#endif

Page 53: #PDR15 - waf, wscript and Your Pebble App

Before$ pebble install --emulator aplite --logsInstalling app...App install succeeded.[22:45:45] default.c:60> Done initializing, pushed window: 0x2001a5fc[22:45:50] javascript> Ready!

$ pebble build -- --no-logs…$ pebble install --emulator aplite --logsInstalling app...App install succeeded.[22:49:34] javascript> Ready!

After

Page 54: #PDR15 - waf, wscript and Your Pebble App

Recipe #3

Add a linter

Page 55: #PDR15 - waf, wscript and Your Pebble App

Create waftools/linter.pydef options(ctx): ctx.add_option('--jshint', action='store_true', help="Run JSHint on the JS files in the build")

def configure(ctx): if ctx.options.jshint: try: ctx.find_program('jshint', var='JSHINT') except ctx.errors.ConfigurationError: print "jshint was not found"

def build(ctx): if ctx.env.JSHINT: ctx(rule='${JSHINT} ${SRC}', source=ctx.path.ant_glob('src/**/*.js'))

Page 56: #PDR15 - waf, wscript and Your Pebble App

Add to wscript

def options(ctx): ctx.load('pebble_sdk')+ ctx.load('linter', tooldir='waftools')

def configure(ctx): ctx.load(‘pebble_sdk')+ ctx.load('linter', tooldir='waftools')

def build(ctx): ctx.load('pebble_sdk')+ ctx.load('linter', tooldir='waftools')

Page 57: #PDR15 - waf, wscript and Your Pebble App

$ pebble build -- --jshint

[25/36] jshint ${SRC}: src/js/another.js src/js/pebble-js-app.js../src/js/pebble-js-app.js: line 2, col 24, Missing semicolon.

1 errorWaf: Leaving directory `/Users/cherie/pebble-apps/default/build'Build failed -> task in '' failed (exit status 2): {task 4343355600: jshint ${SRC} another.js,pebble-js-app.js -> }' jshint ../src/js/another.js ../src/js/pebble-js-app.js '

Page 58: #PDR15 - waf, wscript and Your Pebble App

Recipe #4

Use source code from multiple folders (2.x + 3.x)

Page 59: #PDR15 - waf, wscript and Your Pebble App

Modify wscript def build(ctx): for p in ctx.env.TARGET_PLATFORMS:- ctx.pbl_program(source=ctx.path.ant_glob('src/**/*.c'), target=app_elf)+ ctx.pbl_program(source=ctx.path.ant_glob('src/{}/**/*.c'.format(p)), target=app_elf)

if build_worker:- ctx.pbl_worker(source=ctx.path.ant_glob('worker_src/**/*.c'), target=worker_elf)+ ctx.pbl_worker(source=ctx.path.ant_glob('worker_src/{}/' '**/*.c'.format(p)), target=worker_elf)

Page 60: #PDR15 - waf, wscript and Your Pebble App

Recipe #5

Concatenate multiple JS files

Page 61: #PDR15 - waf, wscript and Your Pebble App

Modify wscript def build(ctx): ctx.set_group('bundle')

+ js_files = ctx.path.ant_glob('src/**/*.js')+ if js_files:+ ctx(rule='cat ${SRC} > ${TGT}', source=js_files, target='pebble-js-app.js')

- ctx.pbl_bundle(binaries=binaries, js=ctx.path.ant_glob('src/js/**/*.js'))+ ctx.pbl_bundle(binaries=binaries, js='pebble-js-app.js' if js_files else [])

Page 62: #PDR15 - waf, wscript and Your Pebble App

A Word on Future Proofing

Sometimes the SDK default wscript will be updated, but by abstracting code out of wscript and into waf tools, it will be

much easier to maintain customizations!

Page 63: #PDR15 - waf, wscript and Your Pebble App

DebuggingWhen your wscript changes go wrong

Page 64: #PDR15 - waf, wscript and Your Pebble App

`pebble -v` (waf -v) for command-lines [ 6/41] c: src/concentricity.c -> build/src/concentricity.c.16.o21:27:05 runner ['arm-none-eabi-gcc', '-std=c99', '-mcpu=cortex-m3', '-mthumb', '-ffunction-sections', '-fdata-sections', '-g', '-Os', '-D_TIME_H_', '-Wall', '-Wextra', '-Werror', '-Wno-unused-parameter', '-Wno-error=unused-function', '-Wno-error=unused-variable', '-fPIE', '-I/Users/cherie/pebble-apps/pebble-dev/PebbleSDK-dev/Pebble/chalk/include', '-I/Users/cherie/pebble-dev/PebbleSDK-dev/Pebble/chalk/include', '-I/Users/cherie/pebble-apps/concentricity/build', '-I/Users/cherie/pebble-apps/concentricity', '-I/Users/cherie/pebble-apps/concentricity/build/src', '-I/Users/cherie/pebble-apps/concentricity/src', '-I/Users/cherie/pebble-apps/concentricity/build/chalk', '-I/Users/cherie/pebble-apps/concentricity/chalk', '-DRELEASE', '-DPBL_PLATFORM_CHALK', '-DPBL_COLOR', '-DPBL_ROUND', '-DPBL_SDK_3', '-D__FILE_NAME__="concentricity.c"', '../src/concentricity.c', '-c', '-o', 'src/concentricity.c.16.o']

Page 65: #PDR15 - waf, wscript and Your Pebble App

`pebble -vvv` (waf -vvv) for complete

21:51:50 preproc reading file '/Users/cherie/pebble-apps/concentricity/build/chalk/src/resource_ids.auto.h'21:51:50 deps deps for [/Users/cherie/pebble-apps/concentricity/build/chalk/appinfo.auto.c]: [/Users/cherie/pebble-apps/concentricity/build/chalk/src/resource_ids.auto.h]; unresolved ['pebble_process_info.h']21:51:50 task task {task 4344651216: c appinfo.auto.c -> appinfo.auto.c.16.o} must run as it was never run before or the task code changed21:51:50 runner_env kw={'shell': False, 'cwd': '/Users/cherie/pebble-apps/concentricity/build', 'env': None}21:51:50 envhash d751713988987e9331980363e24189ce []

Page 66: #PDR15 - waf, wscript and Your Pebble App

Zone Description

runner command-lines executed (same as -v)

deps implicit dependencies found

task_gen task creation & task generator method execution

action functions to execute for building the targets

env environment contents

envhash hashes of the environment objects

build build context operations, like filesystem access

preproc preprocessor execution

group groups & task generators

$ pebble build -- --zones=deps23:01:45 deps deps for [/Users/cherie/pebble-apps/concentricity/src/concentricity.c]: [/Users/cherie/pebble-apps/concentricity/src/ui.h]; unresolved ['pebble.h']

Page 67: #PDR15 - waf, wscript and Your Pebble App

Helpful waf Links

•Pebble Recipes •https://developer.getpebble.com/build

•GitHub Project •https://github.com/waf-project/waf

•Google Group •https://groups.google.com/forum/#!forum/waf-users

•Book •https://waf.io/book/

Page 68: #PDR15 - waf, wscript and Your Pebble App

2015 Pebble Developer Retreat

Questions?

https://developer.getpebble.com/build