7 KiB
title | author | tags | |
---|---|---|---|
Tips and Tricks - Platform-specific C File Set | chrislewis |
|
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
.