Successfully reported this slideshow.
Your SlideShare is downloading. ×

#PDR15 - waf, wscript and Your Pebble App

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Upcoming SlideShare
#PDR15 - Pebble Graphics
#PDR15 - Pebble Graphics
Loading in …3
×

Check these out next

1 of 68 Ad

#PDR15 - waf, wscript and Your Pebble App

Download to read offline

Learn how to take advantage of the Pebble build system by creating customized wscripts that let you concatenate JS files, automatically run linters, and internationalize your apps with Cherie Williams (Developer Evangelist).

Learn how to take advantage of the Pebble build system by creating customized wscripts that let you concatenate JS files, automatically run linters, and internationalize your apps with Cherie Williams (Developer Evangelist).

Advertisement
Advertisement

More Related Content

Slideshows for you (20)

Similar to #PDR15 - waf, wscript and Your Pebble App (20)

Advertisement

More from Pebble Technology (18)

Recently uploaded (20)

Advertisement

#PDR15 - waf, wscript and Your Pebble App

  1. 1. 2015 Pebble Developer Retreat waf, wscript & Your Pebble App Cherie Williams - Troublemaker
  2. 2. 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
  3. 3. Why modify my wscript? Making the Pebble SDK build system work for you
  4. 4. 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
  5. 5. 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
  6. 6. You can… • Add automatic testing • Profile builds or add build visualizations • Read in arbitrary text at build (eg. appinfo.json)
  7. 7. You can… • Include an external library • Build libraries for distribution …the possibilities are endless!
  8. 8. Fine Print Recipes + content from today’s talk are *not* compatible with CloudPebble
  9. 9. Pebble SDK & Fat PBW
  10. 10. 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
  11. 11. What is this “waf” thing? A brief introduction to the Pebble build system
  12. 12. 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
  13. 13. Why is Pebble using waf?
  14. 14. This guy
  15. 15. 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
  16. 16. wscript The build script behind waf
  17. 17. Basic wscript (non-Pebble) def configure(ctx): print "Configure" def build(ctx): print "Build"
  18. 18. Basic wscript $ waf configure build Setting top to : /Users/cherie/waf-demo/ default Setting out to : /Users/cherie/waf-demo/ default/build Configure 'configure' finished successfully (0.009s) Waf: Entering directory '/Users/cherie/waf-demo/default/build' Build Waf: Leaving directory '/Users/cherie/waf-demo/default/build' 'build' finished successfully (0.009s)
  19. 19. 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)
  20. 20. Standard Pebble wscript def 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
  21. 21. Why do I care about waf? Understanding how your Pebble project is built
  22. 22. wscript The build script behind waf
  23. 23. Basic wscript (non-Pebble) def configure(ctx): print "Configure" def build(ctx): print "Build"
  24. 24. 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
  25. 25. Basic wscript (non-Pebble) def configure(ctx): print "Configure" def build(ctx): print "Build"
  26. 26. Modified Basic wscript def configure(ctx): ctx.env.MESSAGE = "Hello World" def build(ctx): pass
  27. 27. 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
  28. 28. build/c4che/*.py AR = '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 = 5 SDK_VERSION_MINOR = 70 SHLIB_MARKER = None SIZE = 'arm-none-eabi-size' SONAME_ST = '-Wl,-h,%s' STLIBPATH_ST = '-L%s' STLIB_MARKER = None STLIB_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'
  29. 29. Modified Basic wscript def configure(ctx): ctx.env.MESSAGE = "Hello World" def build(ctx): ctx(rule="echo ${MESSAGE}", source='', target='')
  30. 30. 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
  31. 31. ${MESSAGE} is shorthand for ctx.env.MESSAGE
  32. 32. Modified Basic wscript $ ../Pebble/waf configure build Setting top to : /Users/cherie/waf-demo/ default Setting 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 World Waf: Leaving directory '/Users/cherie/waf-demo/default/build' 'build' finished successfully (0.030s)
  33. 33. 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')
  34. 34. 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.
  35. 35. ${SRC} and ${TGT} are shorthand for source and target
  36. 36. Pebble Project Build Let’s see how dependencies work
  37. 37. 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)
  38. 38. Node != Existing File
  39. 39. 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`)
  40. 40. 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
  41. 41. wscript Recipes https://developer.getpebble.com/build
  42. 42. Recipe #1 Add compile time flags
  43. 43. 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
  44. 44. [23/35] c: src/default.c -> build/src/default.c.18.o In 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]; ^
  45. 45. Recipe #2 Add build options & associated defines
  46. 46. Create waftools/defines.py def 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 & configure ctx.load('defines', tooldir='waftools')
  47. 47. Add to main project.c file #include <pebble.h> #if defined(NOLOG) #undef APP_LOG #define APP_LOG(...) #endif
  48. 48. Before $ pebble install --emulator aplite --logs Installing 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 --logs Installing app... App install succeeded. [22:49:34] javascript> Ready! After
  49. 49. Recipe #3 Add a linter
  50. 50. Create waftools/linter.py def 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'))
  51. 51. 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')
  52. 52. $ 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 error Waf: 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 '
  53. 53. Recipe #4 Use source code from multiple folders (2.x + 3.x)
  54. 54. 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)
  55. 55. Recipe #5 Concatenate multiple JS files
  56. 56. 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 [])
  57. 57. 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!
  58. 58. Debugging When your wscript changes go wrong
  59. 59. `pebble -v` (waf -v) for command-lines [ 6/41] c: src/concentricity.c -> build/src/concentricity.c.16.o 21: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']
  60. 60. `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 changed 21:51:50 runner_env kw={'shell': False, 'cwd': '/Users/cherie/ pebble-apps/concentricity/build', 'env': None} 21:51:50 envhash d751713988987e9331980363e24189ce []
  61. 61. 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=deps 23:01:45 deps deps for [/Users/cherie/pebble-apps/concentricity/src/ concentricity.c]: [/Users/cherie/pebble-apps/concentricity/src/ui.h]; unresolved ['pebble.h']
  62. 62. 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/
  63. 63. 2015 Pebble Developer Retreat Questions? https://developer.getpebble.com/build

×