Инъекция N-зависимостей в C - лучший способ, чем массивы, определенные линкерами?
Учитывая модуль библиотеки, в следующем называется Runner
, который находится как компонент многократного использования (перекомпиляция не требуется, то есть статическая библиотека ссылок) в разделе приложения архитектуры, а не в основном разделе. Обратите внимание, что он содержит только main()
для демонстрационных целей.
Данный набор (не относящийся к порядку) других модулей / объектов называется Callable
с, т.е. Callable1
, Callable2
а также Callable3
, которые также находятся как многократно используемые компоненты в разделе приложения.
Runner
имеет зависимость во время выполнения от Callable
в этом Runner
должен знать каждый из этих Callable
s для того, чтобы получить данные из них (получить доступ к структуре) или заставить их выполнить операцию (вызвать функцию).
Runner
не должно зависеть от компиляции Callable
s. Вместо этого зависимости должны быть введены через компоновщик в фиктивный модуль Callables
, Концепция должна быть применима не только в размещенной среде, но и в автономной среде. Таким образом, механизмы на основе загрузчика, такие как загрузка Callable
s как общие объекты во время выполнения не могут быть использованы.
Как можно ввести зависимости с помощью компоновщика?
Мое рабочее решение, позволяя Callable
определить указатели в выделенном разделе, в данном случае с именем 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 <stdio.h>
#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
, но я очень заинтересован в решениях, которые менее специфичны для инструментария / более портативны, чем решение, которое я нашел до сих пор.