Monkey.jungle - sourcePath for product suddenly ignored

I have my monkey.jungle set up like this:

project.manifest = manifest.xml

base.sourcePath = source

fr645.sourcePath = $(fr645.sourcePath);source-fr645
fr645m.sourcePath = $(fr645m.sourcePath);source-fr645

In source I have a .mc file containing this callback function:

myFunc() { qout("base source"); }

In source-fr645 I have another .mc file with an overwritten version:

myFunc() { qout("fr645 source"); }

Running a configuration for fr645 the console always shows:

base source

Strange thing is: Until spring it all worked like a charm. Now I needed to update to 2022 Eclipse version where I also installed the newest ConnectIQ SDKs. I re-opened my workspace, got some new warnings (the newer IDE seems to apply stricter rules in some cases) - and suddenly the code in my product folders is not called anymore. This applies to every product/configuration.

Any help would be highly appreciated since I'm stuck. I read all the docs and, more important, didn't change the monkey.jungle or the code.

  • Just of out of curiosity: when the code was working, how were you able to avoid duplicate symbol errors during compilation? Did you also use exclude annotations?

    What happens if you put a syntax error in one of the files under source-fr645? Does the build fail?

  • Good questions. Yes, syntax errors in the product files get detected. Duplicate symbols never were a problem - I understand that that is exactly the point (if I have a function in a product code it overrides the basic version). I use this to work with a basic setting of screen offsets for fields and modify them for various watch models.

  • I'm not exactly sure how that would work, unless you take steps to exclude specific base files or symbols from fr645.

    Given two symbols with the same name, how would the compiler know which one takes precedence? Sure, you could say that it should use the symbol that was found in the source file that appears last in the list of folders, but what if you have the same symbol twice in the same folder?

    e.g. What if you have myFunc() twice in source/foo.mc or twice in source-fr645/foo.mc?

    I tried a really simple test as follows:

    monkey.jungle:

    base.sourcePath = source
    fr645.sourcePath = $(fr645.sourcePath);source-fr645

    source/base.mc:

    function foo() {
       return "base";
    }

    source-fr645/override.mc:

    function foo() {
      return "fr645";
    }

    As expected, the compiler gave me the following error when I built for fr645:

    ERROR: ... Redefinition of 'foo' in '$'. Previous definition at ...

    That's why I was asking how it worked before. I would probably need to see more details about your project. I guess the tough part is you have no way to demonstrate that it used to work, unless you are using Windows and you have a restore point from before Eclipse was upgraded. (But then again who knows if all the relevant files are even covered by the System Restore.)

    If it was working before, perhaps it was a bug that has been fixed. However, I went back to SDK 4.0.6 and the build still fails the same way.

  • Yes, syntax errors in the product files get detected.

    So that proves that the source path actually isn't ignored.

    The real question is how is your project structured such that:

    - you were able to "override" symbols without the use of exclude annotations and without running into duplicate symbol errors

    - why is the compiler now choosing to use the base symbols (still without errors)

  • Right - or, how can I use annotations to achieve the former behaviour?

  • how can I use annotations to achieve the former behaviour?

    You can do something like the following, but I'm still curious how you're finding yourself in your current situation. If there's some bug or quirk in your app, it might interfere with anything else you try to do here.

    As far as I know, code symbols can't be simply overridden in the same way that resources can, hence the duplicate symbol errors. But maybe I'm missing something here.

    e.g. Suppose I have 3 "versions" of code: base, fr245 family and fr645 family.

    monkey.jungle:

    base.excludeAnnotations = fr645_fam;fr245_fam
    fr245.excludeAnnotations = default;fr645_fam
    fr245m.excludeAnnotations = default;fr645_fam
    fr645.excludeAnnotations = default;fr245_fam
    fr645m.excludeAnnotations = default;fr245_fam

    (Note that the device-specific excludeAnnotations are written so they do *not* preserve their default values, because you don't want them to receive the value of base.excludeAnnotations.)

    data field view (I will set a different label for each family)

    import Toybox.Activity;
    import Toybox.Lang;
    import Toybox.Time;
    import Toybox.WatchUi;
    
    class TestDataFieldView extends WatchUi.SimpleDataField {
    
        (:default) function getLabel() { return "default"; }
        (:fr645_fam) function getLabel() { return "fr645_fam"; }
        (:fr245_fam) function getLabel() { return "fr245_fam"; }
    
        // Set the label of the data field here.
        function initialize() {
            SimpleDataField.initialize();
            label = getLabel();
        }
    
        function compute(info as Activity.Info) as Numeric or Duration or String or Null {
            return 0.0;
    
        }
    
    }

  • A different way of doing things would be to cleanly split the code into folders:

    - shared source

    - non-645 / default source

    - 645 source

    e.g.

    monkey.jungle:

    base.source = source;source-default
    fr645.source = source;source-645
    fr645m.source = source;source-645

    This would be a lot simpler than exclude annotations, especially if you start supporting differences between additional "families"

    - source = source that everyone wants

    - source-default = source that only non-overridden devices want

    Might not be feasible depending on how your code is structured, unless you want to duplicate code or make extensive use of class inheritance. (Both of which may use more memory than the alternative.)

  • The splitting into folders is what I was actually doing. To make things more understandable I have restructured the folders like this:

    - source (contains all the common code)

    - source-default

    - source-products

            - source-vivoactive-hr (one of many prooducts)

    There is a set of global vars with (dummy) screen coordinates, i.e. 

    var offset_X_altitude = 0;
    var offset_Y_altitude = 0;
    var offset_X_a2 = 0;

    in the main module under source.

    There is also a callback function under source-default

    function setDeviceParameters(dc) {
          qout("setDeviceParameters global");
    }

    which does actually nothing except a debug output.

    The same function is in each of the product directories, i.e.

    function setDeviceParameters(dc) {

          qout("setDeviceParameters VIVOACTIVE_HR");

          offset_X_altitude = 106;
          offset_Y_altitude = 24;
          offset_X_a2 = 147;
    }

    where it is supposed to override the default coordinates.

    Monkey.jungle says this now:

    base.sourcePath = source;source-default

    vivoactive_hr.sourcePath = source;source-products/source-vivoactive_hr

    This works now!