What is project.yml for?

Just a general question. I created a project based on the hardwaretimer example, and a file called project.yml magically appeared. It looked interesting so I decided to research it but I have not been able to find any documentation about what the file is for. I’ve seen a few examples pertaining to specific hardware, and something about “conditional compilation” which looks like it may be useful. It also mentions in the comments that it can be used to control the way Python and C modules are compiled. That could be very useful for me as I am currently wrestling with this functionality.
Is there anywhere that explains what this file is and what it can be used for?
Thanks.

Hello @mogplus8,

the reason you didn’t find any documentation is that you have stumbled into a still experimental feature of Zerynth :slight_smile:
But if you are brave enough to bear with a surely changing API, here is some more info.

project.yml contains a config section where something akin to C macros can be defined. Let’s take for example a:

# project.yml
config:
    FEATURE_A: 42
    FEATURE_B: 1

the macros above are injected both in Python and C code. In C, they can be used as usual with a:

#if defined(FEATURE_B)
    //add code for feature B
#endif

We use this in Zerynth codebase to enable/disable memory intensive features like for example TLS sockets. If you don’t need them, you can save tons of memory by simply disabling the ZERYNTH_SSL macro in your project.yml

Since Python does not have a C-like preprocessor, we added one for the sake of testing its usage and we found it to be a nice feature. The implementation is a bit hacky, it was aimed at getting the functionality up and running fast without much care for usability.
This said, here is how you can use macros in Python:

def features():
#-if FEATURE_A==42
    print("A")
#-else
    ##-if FEATURE_B==1
    print("B")
    ##-else
    print("No features :(")
    ##-endif
#-endif

Preprocessor directives start with #- and can be nested by adding and additional # for each level.
Valid directives are if,else,endif and the expressions are evaluated by substituting the macro with the value in project.yml; valid operators are >=,<=,==,!=,>,<. Expressions can be negated by prefixing them with !.

There is plenty of room for improvement:

  • better syntax
  • more powerful expressions
  • availability of the macro in Python code, not only in preprocessor expressions (you can’t use FEATURE_A as a constant in code, yet)

They are all coming in the next months, stay tuned. In the meanwhile you can stick to the above syntax, should be enough for some initial tests.

Thanks for the explanation @Giacomo, very interesting new features! I sometimes use a similar technique for testing by just using Python syntax, i.e. define a variable (i.e. FEATURE_A = 1), then use straight Pyrhon IF statements in the code to test it. I guess you could also put the variable definitions in a separate module and import it, too, then just remove the “import” statement to disable all the testing code. The danger with doing testing in this way of course (as I discovered as a young Cobol programmer on IBM mainframes, back in the '70s) is that when the testing code is removed it may subtly change the production code and introduce new errors. So caution is required!

What I was really hoping was that this feature may be used to modify the compilation parameters by, for instance, adding extra include libraries.

My favourite IDE for C development, PlatformIO, has a similar feature in its platformio.ini file, where many different options can be specified giving very fine control of the whole compilation and uplink process. One nice feature is that the board can be specified there, so when a project is opened the correct board is already selected. I created a new project and discovered some items in the .yml file that indicates that you may have similar ideas already!

The reason I’m interested in a feature like this is that I would like to access the control registers of the board I am programming for, in my case an Arduino Due. I would like to include all the “instance_***.h” and “component_***.h” headers that contain all the definitions for the register addresses and values that can be set in the registers for the Due and, ideally, address them in the Python code. That might be a bit too hard (as Python doesn’t really have a C style pointer), so putting them all in a C module would be nearly as good as it’s so easy to interface to C modules from Zerynth. But you already knew that. :slight_smile:

Yes, we are gradually adding the possibility to use ztc using device and vm parameters specified in project.yml; some commands are already there (check ztc project), they will be documented and explained in a few releases.

About adding gcc switches, libraries included, that is a nice addition and I am putting it in our todo list right away.

Woohoo!!! That’s great to hear!

:slight_smile:

Actually @Giacomo, just while I have your attention, since you mentioned it, a) how do I disable ZERYNTH_SSL, is it just a matter of setting it to “false” or zero?, and b) what else can I disable?
Thanks.