Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Embedded C file structure suggestions [closed]

I cannot find good suggestions about file structures in typical embedded software in C. There are a number of such questions and answers here on SO, but none that covers the concerns I present, or that seems adapted to embedded systems in C.

I understand that there is no silver bullet. If that helps narrow suggestions, my typical application must fit on targets with between 8 to 32 kB flash, and a few kB RAM. Clocks in the 4 to 20 MHz range.


1. Layers

I have seen source code organized in layers, each layer having its own directory:

  • application
  • transport layer
  • hardware abstraction layer

The problem is that modules often have files in all of these layers, so separating layers in directories means that the files of a single module are scattered all over the place. Poor encapsulation.


2. Modules in directories, h files in $ROOT/includes/

One directory per module. The good thing is real encapsulation. What I am not sure how to do well is how to publish the API of a module. Open source PC application SW seems to:

  • have all source code in the module directory (all C files and all header files that are meant to be used within the module only)
  • publish the API header file outside the module directory, into $PROJ_ROOT/includes.

That way I can have -I$PROJ_ROOT/includes (or equivalent) in my compiler command, and no search paths in my #include statements.

A problem is that the API is outside the module directory, thus breaking the encapsulation. It is harder to maintain a module as stand-alone in a VCS, for example.


3. Modules with API in directories

Same as above, but with the API header file in the module directory. Proper encapsulation and easier to version control modules, but the API header file is on the same level as the other module header files, which were meant to be private. The temptation to include such a "private" header file outside the module may be too great to a future developer, and it's not visible which h file was meant to be public and which weren't.


4. Modules with API in directories, private structure in sub-dir

Put only the API header file directly in the module directory, and all other files in a sub-directory or several. This could work, but I feel that the structure is growing more and more complex, which I don't really like.


I feel that I should go for 2 or 4, but would appreciate insight greatly. How to address the related drawbacks I describe? Other alternatives?

Links to successful open source SW of this kind of size could be nice as well. Literature advice is also welcome.

like image 253
Gauthier Avatar asked Jun 17 '13 08:06

Gauthier


1 Answers

With such a limited amount of memory, the application + OS will be fairly small. I have worked on projects that are several gigabytes of source code, and the number of modules in the thousands, and building installable binaries that are in the "gigabytes" range. When you get to that size, you definitely need to have your header files, etc, in the right place.

I think the following is a fairly decent concept, however:

  1. Source files per module. Modules may be separated into larger groups by "usage" (e.g. "Base/OS", "Graphics", "Audio", "Network", "UI", "Apps", etc).
  2. Each module has a list of "exported includes" (zero to fairly large), which, when the module is being built are copied to a general "${ROOT}/includes" type directory. That provides the EXTERNAL interface, but the object files produced as the module itself may use "${module}/includes" as well, where there are private declarations and definitions, not "public" to the users of the API.

This is roughly how most large projects work. If it works for large projects, it should be fine for smaller projects too. However, if the number of source files is a dozen or two, I don't really see much point in splitting it up at all - maybe a "src" and "includes", perhaps also a "include/private" if you want to ensure that API's are clean. Keeping it simple has great advantages!

Note that the "exports" part needs to be built before the actual modules are compiled, or you'll have to ensure that there is absolutely no cross-communication between modules [or at least ensure that no "early" modules need any of the "later" modules header files - which becomes quite hard if the system is getting large].

You should also have a set of rules about how and what you expose, and during code-review check that these rules are followed.

like image 146
Mats Petersson Avatar answered Oct 20 '22 21:10

Mats Petersson