Injection de N-Dependency en C – meilleur moyen que les tableaux définis par l’éditeur de liens?

Étant donné un module de bibliothèque , appelé ci-après Runner , qui réside en tant que composant réutilisable (aucune recompilation requirejse, c’est-à-dire une bibliothèque de liens statiques) dans la partition d’application de l’architecture, pas la partition principale . Notez qu’il ne contient que main() à des fins de démonstration.

Étant donné un ensemble (ordre non pertinent) d’autres modules / objects appelés Callable s, c’est-à-dire Callable1 , Callable2 et Callable3 , qui résident également en tant que composants réutilisables dans la partition d’application .

Runner a une dépendance d’exécution sur le Callable s en ce qu’il a besoin de connaître chacun de ces Callable s pour obtenir des données (accéder à une structure) ou leur demander d’effectuer une opération (appeler une fonction).

Runner ne doit pas avoir de dépendance à la compilation des Callable . Au lieu de cela, les dépendances doivent être injectées via l’éditeur de liens dans un module fictif Callables . Le concept doit être utilisable non seulement dans un environnement hébergé, mais également dans un environnement autonome . Par conséquent, les mécanismes basés sur le chargeur, tels que le chargement des objects Callable tant qu’objects partagés au moment de l’exécution, ne peuvent pas être utilisés.

Comment peut-on injecter les dépendances en utilisant l’éditeur de liens?

Ma solution de travail consiste à laisser les éléments Callable définir des pointeurs dans une section dédiée, appelée Callables , que l’éditeur de liens collecterait pour que le Runner puisse y accéder, en obtenant les informations nécessaires au moment de la liaison.

Callable.h

 #ifndef CALLABLE_H #define CALLABLE_H typedef void (*Callable)(void); #endif 

Callables.h

 #ifndef CALLABLES_H #define CALLABLES_H #include "Callable.h" extern Callable Callables_start[]; extern Callable Callables_end[]; #endif 

Runner.c

 #include "Callables.h" void Runner_run(void) { for (Callable *callables = Callables_start; callables < Callables_end; callables++) (*callables)(); } int main(void) { Runner_run(); return 0; } 

Callable1.c

 #include  #include "Callable.h" static void Callable1_call(void) { printf("Callable 1\n"); } static Callable thisCallable __atsortingbute__((section("Callables"))) = &Callable1_call; 

Callable2.c et Callable3.c ont la même apparence, à l’exception d’un message différent dans printf() .

Callables.ld

 PROVIDE(Callables_start = LOADADDR(Callables)); PROVIDE(Callables_end = Callables_start + SIZEOF(Callables)); 

Makefile

 CFLAGS+=--std=c99 callables:=Callable1 Callable2 Callable3 .PHONY: all all: Runner Runner: Callables.ld Runner.o $(addsuffix .o, $(callables)) 

Sortie

 $ make -s && ./Runner Callable 1 Callable 2 Callable 3 

La sortie montre que la solution fonctionne, mais je ne suis pas satisfait de la solution. Quelles sont les alternatives, de préférence de meilleures façons d’injecter des dépendances à l’aide de l’éditeur de liens que la solution que j’ai trouvée?

Remarque

L’environnement est GCC / ld sur x86_64 avec -ffreestanding , mais je suis très intéressé par les solutions moins spécifiques à la chaîne d’outils / plus portables que la solution que j’ai trouvée jusqu’à présent.