---
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

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

In 
[the last Tips and Tricks blog post](/blog/2015/05/13/tips-and-tricks-transparent-images/) 
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](/sdk/migration-guide/#backwards-compatibility) 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.

```c
#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:

```text
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:

```python
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.

```text
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:

```text
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()`](https://waf.io/book/#_general_usage). This is shown in the code
snipped below, with unchanged lines ommitted for brevity:

```python
# 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:

```js
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*](/guides/app-resources/platform-specific/) 
  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`]({{site.links.examples_org}}/multi-platform-wscript).