Нет необходимости полагаться на поддержку компоновщика или управление компоновкой IDE.Полностью переносимое решение - определить реализации A и B с разными именами символов, а затем использовать условно определенные макросы для выбора требуемой реализации.
Пример:
#if defined USE_IMPLEMENTATION_A
#define doSomething implementationA_doSomething
#elif defined USE_IMPLEMENTATION_B
#define doSomething implementationB_doSomething
#else
#error API implementation not defined
#endif
int implementationA_doSomething( void ) ;
int implementationB_doSomething( void ) ;
Таким образом, обаРеализация A и B всегда будет компилироваться, но только выбранный API будет использоваться с использованием макроса doSomething
, а не имени функции для конкретной реализации.
Я не знаю, насколько умным является ILINK, норазмещая реализации в отдельных единицах перевода (например, в файлах .c), компоновщик должен иметь возможность удалять из ссылки неиспользуемые функции.Если нет, то, конечно, это произойдет, если вы поместите объектный код в библиотеку статических ссылок (.lib или .a).
Чтобы решить вопрос о поддержании двух файлов реализации, которые идентичны, за исключением пространства именВ качестве префикса вы можете создать отдельный фиктивный заголовочный файл с такими прототипами, как:
int NAMESPACE_doSomething( void ) ;
, а затем выполнить шаг перед сборкой, используя инструмент, такой как sed , для генерации заголовков прототипов реализации.например:
sed -i 's/NAMESPACE/api_a/g' api_dummy.h > api_a.h
sed -i 's/NAMESPACE/api_b/g' api_dummy.h > api_b.h
Затем у вас есть файл api.h, который содержит (фрагмент):
#if defined USE_IMPLEMENTATION_A
#define doSomething api_a_doSomething
#elif defined USE_IMPLEMENTATION_B
#define doSomething api_b_doSomething
#else
#error API implementation not defined
#endif
#include api_a.h
#include api_b.h
Вы можете дополнительно написать генератор кода для генерации api.h изсписок имен функций.Это не будет слишком сложно для вашего предпочтительного языка сценариев или даже C. Вы можете написать такой генератор, который будет принимать аргументы командной строки:
generate_api <input> <output> <namespace1> <namespace2> ... <namespaceN>
и затем вызывать его:
generate_api functions.txt api.h api_a api_b
Youможет даже использовать текст NAMESPACE_
в заголовке фиктивного элемента для генерации списка имен функций для <input>
, так что весь набор заголовков API может быть сгенерирован из одного фиктивного заголовка.