Инъекция N-зависимостей в C – лучше, чем линеарные массивы?

Учитывая библиотечный модуль , в следующем называется Runner , который находится в качестве повторно используемого компонента (не требуется перекомпиляции, то есть статическая библиотека ссылок) в разделе приложения архитектуры, а не в главном разделе . Обратите внимание, что он содержит только main() для демонстрационных целей.

Учитывая набор (не относящийся к делу) других модhive / объектов, называемых Callable s, то есть Callable1 , Callable2 и Callable3 , которые также находятся в качестве компонентов многократного использования в разделе приложения .

Runner есть зависимость времени выполнения от Callable s в том, что Runner должен знать каждый из этих Callable s, чтобы получить данные от них (получить доступ к структуре) или выполнить операцию (вызвать функцию).

Runner не должен зависеть от Callable с Callable s. Вместо этого зависимости должны быть введены через компоновщик в фиктивный модуль Callables . Концепция должна использоваться не только в размещенной среде, но и в автономной среде . Следовательно, механизмы загрузки, такие как загрузка Callable s в качестве общих объектов во время выполнения, не могут использоваться.

Как можно вводить зависимости с помощью компоновщика?

Мое рабочее решение заключается в том, чтобы позволить Callable s определять указатели в выделенном разделе, в этом случае называемом Callables , который Callables компоновки собирал, чтобы Runner мог получить к нему доступ, получая необходимую информацию во время ссылки.

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 __attribute__((section("Callables"))) = &Callable1_call; 

Callable2.c и Callable3.c выглядят одинаково, за исключением другого сообщения в 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)) 

Выход

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

Результат показывает, что решение работает, но я не удовлетворен решением. Каковы альтернативные, предпочтительнее лучшие способы встраивания зависимостей с помощью компоновщика, чем найденное мной решение?

Заметка

Окружающая среда – GCC / ld на x86_64 с -ffreestanding , но меня очень интересуют решения, которые менее ориентированы на инструментальные средства или более переносимы, чем решение, которое я нашел до сих пор.