pebble/devsite/source/_posts/2015-05-19-tips-and-tricks-platform-specific-c-file-sets.md
2025-02-24 18:58:29 -08:00

7 KiB

title author tags
Tips and Tricks - Platform-specific C File Set chrislewis
Beautiful Code

In the last Tips and Tricks blog post we looked at drawing transparent images on both the Aplite and Basalt platforms.

This time around, we will look at a wscript modification that can allow you to build a Pebble project when you have two completely separate sets of C source files; one set for Aplite, and another for Basalt.

Note: This technique can be applied only to local SDK projects, where access to wscript is available. This means that it cannot be used in CloudPebble projects.

Update 05/20/15: There was an error in the JS code sample given at the end of this post, which has now been corrected.

The Preprocessor Approach

In the 3.0 Migration Guide we recommend using preprocessor directives such as PBL_PLATFORM_APLITE and PBL_PLATFORM_BASALT to mark code to be compiled only on that particular platform. This helps avoid the need to maintain two separate projects for one app, which is especially convenient when migrating a 2.x app to the Basalt platform.

#ifdef PBL_PLATFORM_APLITE
  // Aligns under the status bar
  layer_set_frame(s_layer, GRect(0, 0, 144, 68));
#elif PBL_PLATFORM_BASALT
  // Preserve alignment to status bar on Aplite
  layer_set_frame(s_layer, GRect(0, STATUS_BAR_LAYER_HEIGHT, 144, 68));
#endif

This is a good solution for small blocks of conditional code, but some developers may find that complicated conditional code can soon become more #ifdef...#elif...#endif than actual code itself!

The Modified Wscript Approach

In these situations you may find it preferable to use a different approach. Instead of modifying your app code to use preprocessor statements whenever a platform-specific value is needed, you can modify your project's wscript file to limit each compilation pass to a certain folder of source files.

By default, you will probably have a project with this file structure:

my_project
  resources
    images
      banner~bw.png
      banner~color.png
  src
    main.c
    util.h
    util.c
  appinfo.json
  wscript

In this scenario, the wscript dictates that any .c files found in src will be compiled for both platforms.

To use a different set of source files for each platform during compilation, modify the lines with the ** wildcard (within the for loop) to point to a folder within src where the platform- specific files are then located:

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)
    
    # MODIFY THIS LINE!
    # E.g.: When 'p' == 'aplite', look in 'src/aplite/'
    ctx.pbl_program(source=ctx.path.ant_glob('src/{}/**/*.c'.format(p)), 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})
        
        # MODIFY THIS LINE!
        # Also modify this line to look for platform-specific C files in `worker_src`
        ctx.pbl_worker(source=ctx.path.ant_glob('worker_src/{}/**/*.c'.format(p)), target=worker_elf)

    else:
        binaries.append({'platform': p, 'app_elf': app_elf})

With this newly modified wscript, we must re-organise our src folder to match the new search pattern. This allows us to maintain two separate sets of source files, each free of any excessive #ifdef pollution.

my_project
  resources
    images
      banner~bw.png
      banner~color.png
  src
    aplite
      main.c      
      util.h
      util.c
    basalt
      main.c      
      util.h
      util.c
  appinfo.json
  wscript

Sharing Files Between Platforms

Using the modified wscript approach as shown above still requires any files that are used on both platforms to be included twice: in the respective folder. You may wish to reduce this clutter by moving any platform-agnostic files that both platforms use to a common folder inside src.

You project might now look like this:

my_project
  resources
    images
      banner~bw.png
      banner~color.png
  src
    aplite
      main.c
    basalt
      main.c
    common
      util.h
      util.c
  appinfo.json
  wscript

To tell the SDK to look in this extra folder during compilation of each platform, further modify the two lines calling ctx.pbl_program() to include the common folder in the array of paths passed to ant_glob(). This is shown in the code snipped below, with unchanged lines ommitted for brevity:

# Additionally modified to include the 'common' folder
ctx.pbl_program(source=ctx.path.ant_glob(['src/{}/**/*.c'.format(p), 'src/common/**/*.c']), target=app_elf)

/* Other code */

if build_worker:

    # Also modify this line to look for common files in '/worker_src/common/'
    ctx.pbl_worker(source=ctx.path.ant_glob(['worker_src/{}/**/*.c'.format(p), 'worker_src/common/**/*.c']), target=worker_elf)

else:
    
    /* Other code */

Important Notes

While this new wscript allows us to keep our source files for each platform separated entirely, there are a couple of important limitations to take into account when using this method (without any further modification):

  • There can still be only one JavaScript file, in src/js/pebble-js-app.js. You can simulate two JS files using a platform check:
Pebble.addEventListener('ready', function() {
  if(Pebble.getActiveWatchInfo && Pebble.getActiveWatchInfo().platform === 'basalt') {
    // This is the Basalt platform
    console.log('PebbleKit JS ready on Basalt!');
  } else {
    // This is the Aplite platform
    console.log('PebbleKit JS ready on Aplite!');
  }
});  
  • Each binary can be bundled with only the app resources required for that specific platform. To learn how to package app resources with only a certain platform, read the Platform-specific Resources guide.

Conclusion

With this modification to a Pebble project's wscript, developers now have two options when it comes to diverging their app code for Aplite- and Basalt- specific features without the need to maintain two completely separate projects.

You can see a simple example project that ses all these techniques over at pebble-examples/multi-platform-wscript.