Issue
I'm implementing a small system in C for a microcontroller. That system has multiple sensors. Inspired by Linux kernel I would like to create sensors-core module and separated sensors for each type of sensor.
When implementing a new module in kernel, there's a macro module_init
. That macro takes a pointer of a structure and stores it in the predefined memory section. At the kernel start, all init functions from all modules are called, one by one, based on that memory section with function pointers.
I'm trying to do something similar with my sensors and sensor-core modules. Let's say my sensors-core module has an array of pointers. Each sensor creates its own configuration structure. I would like to write a macro which would copy pointer of such structure and place it in the array in sensors-core module - all at the compilation time.
sensors-core.h:
struct sensor_config {
void (*init)(void) init;
...
};
sensors-core.c:
#include "sensors-core.h"
struct sensor_config *sensors[SENSORS_MAX_NUM];
sensor.c
#include "sensors-core.h"
void Init(void)
{
...
}
struct sensor_config config = {
.init = Init
};
SENSOR_INIT(config);
- How can I write such macro? Is it possible? Would it be compiler specific or can I do that so it the code will be portable?
- Can preprocessor take care of how many times the SENSOR_INIT() macro is used and dynamically (at the compilation time) adjust sensors array size? I know that array is a waste of memory. In Linux kernel, after initialization, the memory section containing list of pointers is freed up for other use. At this moment I don't care about that, that would be next step.
I found something similar but not exactly the solution I'm looking for. Plugin system for statically linked modules in C?
Here we can add attribute to a function to be called before main
.
Solution
Kernel is not a uC. module_init
takes a function, not a struct, and it might be a good idea to rewrite your interface for that. Kernel loads a specially prepared file and parses it and from it finds the proper function to call.
How can I write such macro?
Put a pointer to the variable inside a section.
#define CONCAT(a, b) a##b
#define XCONCAT(a, b) CONCAT(a, b)
#define SENSOR_INIT(x) \
__attribute__((__section__("sensors"))) \
__attribute__((__used__)) \
const struct sensor_config *const CONCAT(sensor, __LINE__) = &x;
Then How do you get the start and end addresses of a custom ELF section? iterate over pointers in the section and call.
The elements seem to be constant, you could be just storing the elemenst in the section.
#define SENSOR_SECTION \
__attribute__((__section__("sensors"))) \
__attribute__((__used__))
SENSOR_SECTION
struct sensor_config config = { stuff; }
Would it be compiler specific
Very yes.
or can I do that so it the code will be portable?
No.
You can use an external utility as part of the build process to generate the array initialization. For example, do #define SENSOR_INIT(x) /*nothing*/
and then traverse all source files with an external program (awk
, Perl, Python) to find all SENSOR_INIT(config);
statements, and from that generate sensors-core.c
files that has references to all structures from all files.
Can preprocessor take care of how many times the SENSOR_INIT() macro is used and dynamically (at the compilation time) adjust sensors array size?
No.
Answered By - KamilCuk Answer Checked By - Clifford M. (WPSolving Volunteer)