Adding Assert and C preprocessor macros to Monkey C

Hi folks,

Test.Assert hasn't worked for years in CIQ, which is a bit frustrating. And it appears to be impossible to add debugging System.println messages that can be easily removed in the release code. So, I've made an initial stab at adding support for using a C preprocessor, which also comes with macros, include files, etc.

I can't post my idea here since the forum doesn't seem to work. So have a look here: https://mcba1.phys.unsw.edu.au/~mcba/gcc-monkey-c.html

  • You can totally and easily do it:

    (:debug) function log(msg as String) as Void {System.println(msg);}

    (:release) function log(msg as String) as Void {}

    If you want to even spare the unnecessary function calls to log(), then you can use Prettier Monkey C and the :inline annotation.

    You can also up-vote this feature request: forums.garmin.com/.../feature-request-add-pre-processor-with-inline-functions-to-monkey-c but back then there wasn't anything like Prettier Monkey C, that exists now and frankly does much more than what I asked for

  • Looking through the previous discussions on this issue, it wasn't clear to me that Prettier Monkey C would completely eliminate the memory used by msg. In my case my App memory usage dropped by 2kB by completely eliminating the debugging logs. Personally, I like the flexibility and certainty of using the C preprocessor.

  • Yes, it does eliminate the string if it was only used to pass it to log() And it does lot more optimizations. Give it a try, you'll be surprised how much more it can shrink your app's memory footprint.

  • One thing you want to keep in mind is you want to retain the source code that's actually sent to the compiler, probably for each device you compile for.  Otherwise, the stack trace in ERA reports could be confusing

  • Indeed. I always keep the last release's modified source (the output of Prettier Monkey C) until next release (when it becomes useless, as ERA always only reports the latest version)

    When there's a report in ERA I first need to look up the device in the generated monkey.jungle and then go to that directory to look for the source code.

    However I don't think it's usually that complicated. In my case I generate the jungle file with a script, and each device also has a constants.mc file (generated by my script using data from compiler and simulator JSON files) so each device has a different set of source files. When you don't do this, then IMHO you'll only have 1 set of optimized source files

  • You could always source control the generated files (assuming that you are already source-controlling your project). While there's obviously pros and cons to doing so, I've definitely seen this practice in a professional context. (Ime, typically files which are generated on every build are not source-controlled, whereas files which are generated on demand tend to be source-controlled, but ofc there's no hard and fast rules here. It depends on the nature of the input and output files, too. Obviously compiler output files are rarely, if ever, source controlled, but if source files are being generated, that's often a good candidate for source control.)

  • Yes, I added the generated monkey.jungle and the source files like constants to git, but not the source files generated by Prettier Monkey C (though it might make sense to save them too, as upgrading the plugin usually makes different source code)

    My reasoning is: the files I save are enough for me or someone else to reproduce the build later (in case I'd lose the output of Prettier) but I don't save files that are generated during the build itself.

  • not the source files generated by Prettier Monkey C (though it might make sense to save them too, as upgrading the plugin usually makes different source code)
    reproduce the build later

    If I'm understanding this correctly, then to have a fully reproducible build, the Prettier version should be pinned on a per-project basis (in a source-controlled file). I thought there was some discussion on a way to do this in the Prettier thread? Maybe by installing prettier (the actual cmd line tool, not the VS Code extension) as a local dependency, as mentioned in the project page, so you can control the version with npm / package.json / package-lock.json?

    Or you could just source-control the output of Prettier like you said.

  • [package.json specifies the dependency version(s) you want, package-lock.json specifies the dependency version you actually have, for any given build/project version.]

  • If you want to even spare the unnecessary function calls to log(), then you can use Prettier Monkey C and the :inline annotation.

    Just my 5¢: What I ended up doing is wrapping those "log" statements like `if (debug) { log(xxx) }`, with debug being a `const debug = true` or `false`, depending on the build config - not the best from readability perspective, but other than that, it works really great: from what I observe, it results in complete elimination of the corresponding code when compiled with stock Monkey C compiler.

    Overall, I'm new to Garmin apps development, but I'm quite impressed with ability to employ custom annotations to generate *different* variants of the code. While I used C-preprocessor to quite an extent in the past, I feel like I can achieve quite a few important things with just with annotations here.