Garmin Dev Tools

Uploaded the Garmin Dev Tools to: https://github.com/flocsy/garmin-dev-tools
If you're a CIQ developer then you might find interesting aggregation of the data collected from the SDK.

  • Maybe I should start over and try to restate my point in a way that's less "funny"

    # I find the excludeAnnotations to be counter-intuitive, so I use them more like "includeAnnotations":
    # For annotations I technically use the excludeAnnotations but with a "positive" (aka include) meaning:
    # monkey-generator generates the excludeAnnotations based on the assumption, that they will be used as include annotation,
    # so when it determines that a device has the feature `foo` it'll have the opposite excludeAnnotation:
    #   fr965.excludeAnnotations=...;no_foo;...
    # and if a device doesn't have feature `bar` then it'll have:
    #   fr230.excludeAnnotations=...;bar;...
    # So in the code you can use the "positive' or "include" annotation:
    # (:no_foo) const HAS_FOO = false;
    # (:foo) const HAS_FOO = true;

    If you don't realize that Garmin actually expects you to use annotations and excludeAnnotations in exactly the same way as you described above, you are the one who is, as you love to say, missing the point.

    If you still disagree, please:

    1) show an example of how you think Garmin expects you to do things differently / in the opposite way (i.e. show me an actual example of "an exclude annotation" in your definition). e.g. Rewrite the above example in the Garmin / exclude annotation way.

    2) explain how they can possibly force people to write things in the weird "exclude annotation" way as opposed to the "include annotation" way that you have described above (anything your script can do can also be done by hand)

    To be clear, I have been using excludeAnnotations in the same way that your monkey-generator uses them since the beginning, but I never felt the need for an additional concept such as "an include annotation", and I never thought I was using the feature in the "opposite" way to what Garmin intended. On the contrary, it seems to me I used it exactly as intended.

    I already have all the concepts I need:

    - annotations (text labels that go with MC symbols/code)

    - excludeAnnotations (a mechanism in monkey.jungle to exclude annotated code at build-time)

    You have seemingly defined "an include annotation" in opposition to "an exclude annotation" but you haven't given an example of "an exclude annotation". Since you may not feel like providing an example, I'll give it a shot. Maybe something like this:

    ## bad example

    # monkey.jungle

    # fr965 has feature foo
    fr965.excludeAnnotations = foo
    # fr230 does not have feature foo
    fr230.excludeAnnotations = no_foo

    # source.mc
    (:foo) const HAS_FOO = false;
    (:no_foo) const HAS_FOO = true;

    If you think this is how Garmin intends annotations and excludeAnnotations to be used:

    - you haven't looked at the example in the documentation

    - you haven't noticed that none of their built-in annotations are like this

    - you don't understand the intent of the excludeAnnotations mechanism at all. It is not to attach the "exclude" "kind" to a list of annotations, it is to literally specify which annotations should be excluded. Again the point is not to change the meaning of the annotations, it's simply to exclude code which has those annotations. The mechanism of including/excluding the annotations has to be separated from the annotations themselves.

    If anyone ever wrote code like the bad example above, they were not using the excludeAnnotations mechanism as intended. Sure it would "work", but it wouldn't make any sense. It would be just as nonsensical as this:

    (:release) const isDebug = true;
    (:debug) const isDebug = false;

    As an imperfect analogy, as we both know, C allows conditional compilation via macros. e.g.

    #ifdef HAS_FEATURE_FOO
    //... code for platforms which have foo
    #else
    //... code for platforms which do not have foo
    #endif

    Macros can be defined or undefined both in source code and the compiler command line. But the act of either defining or undefining a macro does not change the meaning of the macro itself.

    HAS_FEATURE_FOO means that my target has feature foo. Defining or undefined the macro only changes whether the platform actually has foo, it doesn't change the meaning of the HAS_FEATURE_FOO macro at all.

    Maybe I have a normal build system where I have to explicitly define HAS_FEATURE_FOO via a compiler flag. Or maybe I have a weird build system where HAS_FEATURE_FOO is defined by default, and I need to explicitly #undef HAS_FEATURE_FOO in a header file or something.

    Either way, the mechanism of causing HAS_FEATURE_FOO to be defined or undefined doesn't change the meaning of HAS_FEATURE_FOO. It doesn't matter whether it's defined by default and I have to explicitly undefine it, or it's undefined by default and I have to explicitly define it.

    Either way, it's just a macro, not an "include macro" or "exclude macro". And the code which *uses* the macro doesn't change even if the mechanism for defining/undefining it changes.

  • I think Garmin looks at the annotations from the monkey.jungle side, there they have excludeAnnotations. If you add:

    fr230.excludeAnnotations=...;exclude_this_annotation

    Then in your source code
    (:exclude_this_annotation) const FOO = 1; // will be excluded.
    (:whatever) const FOO = 1; // will not be excluded (by exclude_this_annotation, though we don't really know if whatever is declared...)

    To me this is awkward. I look at it from the other side, the source code.

    (:include_this_annotation_with_small_foo) const FOO = 1;
    (:include_this_annotation_with_big_foo) const FOO = 2;

  • I think Garmin looks at the annotations from the monkey.jungle side, there they have excludeAnnotations. If you add:

    fr230.excludeAnnotations=...;exclude_this_annotation

    Then in your source code
    (:exclude_this_annotation) const FOO = 1; // will be excluded.
    (:whatever) const FOO = 1; // will not be excluded (by exclude_this_annotation, though we don't really know if whatever is declared...)

    That's your assumption (about how Garmin sees it) but I think you're absolutely wrong. Just look at the Garmin example I already posted.

    [https://developer.garmin.com/connect-iq/core-topics/build-configuration/]

    The example literally starts with the source code.

    In the example, :roundVersion is for round source code and :regularVersion is for regular (non-round) source code. (The annotations are defined "positively" as you say).

    The excludeAnnotations are ofc flipped. The base qualifier excludes roundVersion and the round qualifier excludes regularVersion.

    Garmin doesn't expect you to annotate your code in terms of what will be excluded, Garmin expects you to annotate your code in terms of what will be included and to set up your excludeAnnotations in the opposite way. That's literally how the example is structured and described - this example works exactly like monkey_generator.

    So again I will say that all annotations are "include annotations" (in your parlance) and therefore "include" modifier is not necessary (not that it ever made sense in the first place, as "[an] exclude annotation" also does not make sense.)

    To me this is awkward. I look at it from the other side, the source code.

    (:include_this_annotation_with_small_foo) const FOO = 1;
    (:include_this_annotation_with_big_foo) const FOO = 2;

    Again based on the example above, Garmin sees it that way too.

    You can look at it from either direction and Garmin doesn't force you to only look at it one way.

    I think the 2 misunderstandings here are:

    - you look at the keyword "excludeAnnotations" and you think that "exclude" is a modifier for "annotations" (as in it changes the type/meaning of the annotation) instead of simply reading it as "annotations to be excluded" as garmin clearly intends.

    - you assume Garmin starts with excludeAnnotations / monkey.jungle and works its way back to the source code, while you ofc are much more sensible and start with the source code and work back to excludeAnnotations. Except I think Garmin does the exact same thing as you. Again, just look at their example: they literally start with the source code and they talk about including certain functions for certain devices.

    You don't have to agree but I said my piece. I think monkey-generator uses excludeAnnotations exactly as intended by Garmin. Certainly that's how everyone the forums has been using excludeAnnotations from the beginning and that's what the example in the doc suggests.

    The way I see it: code annotated with X is either in the build or not. The question is under what conditions is X included? The usage of excludeAnnotations doesn't change the meaning of X, it's up to us as devs to use excludeAnnotations properly to get the results we want (i.e. X is included/excluded under the conditions we want). That's exactly what you've done with monkey-generator and that's exactly what Garmin intended.

    Thank you again for the tool, and thank you for engaging.

  • I will say that the only material difference between the way you see it and the way Garmin sees it is:

    - the way you see it, all user-defined annotations should be excluded by default

    (ofc in this case, excludeAnnotations would not make sense, and Garmin would have to provide includeAnnotations instead). So if the dev uses an annotation that's not defined in monkey.jungle as in your example (:whatever), you would like that code to be excluded from the build.

    - the way Garmin sees it, all user-defined annotations should be included by default

    (ofc this is the only way excludeAnnotations makes sense) Maybe this is a clue for why Garmin uses excludeAnnotations in the first place. Is it intuitive that adding a user-defined annotation to your source code (without changing the jungle) will make that code suddenly disappear from the build? Or does it make sense that the dev has to take another step to explicitly to exclude code with that annotation? Maybe they were just going for the principle of least surprise here.

    But ofc we can't change this default behaviour at all, whether it's by creating code by hand or by using monkey-generator. So even if you and Garmin see that part differently, monkey-generator can't really change that.

    That doesn't mean that devs can't do it the way monkey-generator does it (everybody does), and that doesn't mean Garmin wanted us to do something different than monkey-generator. It's just an annoying implementation detail that changes *how* you include/exclude annotated code, and not what the annotations mean.

    Their example still starts with the source code and moves on to monkey.jungle.

    It's just annoying that if you have lots of of user-defined annotations, your excludeAnnotations lists will get very long and difficult to understand.

    I disagree that any of that stuff means that "an include annotation" and "an exclude annotation" are meaningful concepts here. And I disagree that monkey-generator is using excludeAnnotations any differently than Garmin intended. I think it's using excludeAnnotations exactly as intended.

    I do agree 100% that the excludeAnnotations mechanism is awkward. It's the first reaction of every Monkey C dev, I think. But you are using it as intended, and not in some opposite "include annotations" way.