SterlingPeet / fprime-arduino

A platform support library allowing fprime to be run on a limited number of Arduino compatible devices.
1 stars 2 forks source link

Code Organization #4

Open SterlingPeet opened 3 years ago

SterlingPeet commented 3 years ago

I am trying to avoid having paths (such is in cmake files) the include structures that look like fprime-arduino/fprime-arduino, but I am seeing how this leads to some odd namespace concerns. In general, I prefer not to have wildly different C++ namespaces from paths, however the namespace collisions are happening in the cmake build cache structure. Currently, I am thinking that I want to have a main folder in the root directory of the repo named Arduino and use that namespace for most of the things that would directly parallel F Prime components. For ATmega specific components, they could be placed in a different folder called ATmega.

For example, we could have an Arduino component in Arduino/Svc/ArduinoTime that gets included in cmake as fprime-arduino/Arduino/Svc/ArduinoTime. An ATmega component could be in ATmega/Drv/UartDriver because it uses the low level api instead of the Arduino functions.

It does seem that ArduinoOs still needs to exist as such, because it is coupled with F Prime's Os and shouldn't get mashed in together within the build cache. Or, does this work as Arduino/Os, assuming the Arduino folder already needs to exist?

On the other hand, maybe I am failing to correctly grasp the pattern for setting up a library? @LeStarch, thoughts?

LeStarch commented 2 years ago

I'll do my best to document my thinking on this. Keep in mind F´ libraries haven't been developed by many developers and, as such, are based almost entirely in my perspective....all that to say, we may be able to do better. @SterlingPeet, I know you already are aware of much of this...but this is mostly for others who stumble on here. I will have a follow-up comment with less general explanation that answers your specific question.

F´ libraries can exist anywhere (as a git submodules, folders unpacked to /tmp, /opt, ..., or copied wholesale into a repo). In order to make design files within properly include within in a project's topologies, these libraries need a root folder. This also almost always the root of the Github repo and in your case is fprime-arduino.

However, this can easily yield a problem: collisions. If in a library a user were to define a component that conflicts with F´ or another library (e.g. library-root/Svc/ActiveLogger conflicts with fprime/Svc/ActiveLogger then this component could not be used because the build system cannot predict which component to use. This violates the rule within the autocoder/build system that a component cannot be declared in multiple locations with the same root-relative path.

An easy fix for this is use "namespace" folders. If a library is required to define at least one folder at root inside which all of its components are defined then collisions will be reduced. In the example above, library-root/Svc/ActiveLogger becomes library-root/my-library-namespace/Svc/ActiveLogger and thus would not collide with Svc/ActiveLogger.

Is it the perfect solution? No. Are there other solutions? No. However, it does prevent collisions when a namespace folder is chosen carefully....and it allows users to create new components while still organizing them much like the F´ code (Svc, Drv, Os, etc).

Choosing a namespace folder will be discussed in the next comment as it is the real question being asked here.

LeStarch commented 2 years ago

How to choose a good namespace folder? I almost always use the name of the library itself. This is primarily for several reasons:

  1. When the namespace folder is identical to the git repository name, then the likelihood of collisions drop because checking out two or more git repositories of the same name would collide on the filesystem and force users to rethink the code they were including.
  2. Python modules often follow a similar pattern as you import them and the Python module structure requires it to be a folder with __init__.py. Thus this pattern was familiar to me.

Where this model breaks down is exactly what you are running into. You want to provide two packages: Arduino and ATMega in the same library. With the above name spacing scheme, you'll get a superfluous folder that just holds the two above.

You could use Arduino and ATMega but this will prevent extension libraries should a user wish to provide additional Arduino components following the same structure. Perhaps this isn't a "real" concern in practice since these aren't F´ standard folders. We do see users creating new Svc components that replace stock components, for example, but I don't know how often users will want to create more Arduino or ATMega components.

As for specifically what to do, I see two options:

  1. Do what you proposed and use Arduino and ATMega for both the design and C++ namespace. Extenders will be forced to choose unique component names.
  2. Pretend like you have two libraries fprime-aruino (using c++ namespace Arduino) and fprime-atmega using C++ namespace ATMega

I'd love to hear your opinions on this, as I don't know the right answer. Option 2 seems best (gut instict) as the namespace folders are more restricted (tied to the library name), but it comes at the cost of a divergence between the C++ class namespaces and the folder containing the components.