Замена функции CRT MSVC частной реализацией - PullRequest
2 голосов
/ 22 марта 2019

У меня есть встроенный проект IoT, который я хотел бы сначала разработать частично с использованием таких инструментов для ПК, как VisualStudio. В моем встроенном проекте есть только флэш-память для файловой системы, и я бы хотел перенаправить fopen fread и т. Д. На мою собственную частную реализацию в Windows. Но то, с чем я сталкиваюсь, это неспособность моей частной библиотеки CRT иметь приоритет над встроенной CRT (например, встроенное поведение, управляемое /MD переключателем компилятора).

У меня есть простое решение для трех проектов.

Project 1 - это исполняемый файл теста. Он имеет одну строку main:

int main()
{
    test();
}

Проекты 2 и 3 являются статическими библиотеками. Проект 2 имеет:

#include <string.h>
#include <stdio.h>

void test()
{
    printf("%s\n", strchr("x", 'x'));
}

Проект 3 имеет:

char * strchr(const char * s, int c)  // exact signature of MSVC
{
    return "overridden";
}

Я ожидаю, что результат будет overridden, но вместо этого

x

Но если я добавлю это в Проект 1:

printf("%s\n", strchr("y", 'y'));

Выход будет

overridden
overridden

Первый из test() в библиотеке, второй из исполняемого файла main() напрямую.

Есть предложения?

Ответы [ 2 ]

1 голос
/ 23 марта 2019

Если проблема вызвана использованием CRT только в статической библиотеке, и компоновщик находит библиотеку экспорта MSVCRT DLL до того, как обнаружит статическую библиотеку CRT, то можно обойти принудительную ссылку на частную CRT в исполняемых исходных файлах. .

Пример кода соответствия выше, помещен в main как глобальный:

static char * (*p_strchr)(const char *, int) = strchr;

Это менее чем идеально, но надежно изменяет порядок поиска компоновщика.

Дополнительные выводы

Могут быть комбинации (которые я не совсем понимаю), когда компоновщик выдаст ошибку компоновщика LNK1169 «один или несколько кратно определенных символов» (более одного определения). Например, он может сказать, что fopen определен более одного раза, и если вы измените порядок приватных и MS-библиотек в командной строке, то он может сказать, что fread определен более одного раза. Возможно, это вызвано тем, что библиотека MSVC имеет подпись экспорта DLL, а закрытая библиотека является символом импорта. Поведение трудно определить, так как оно не содержит ошибок во всех переопределяемых функциях.

Если возможно переключить все частные библиотеки на /MT переключатель компилятора (использовать статический CRT), то проблема LNK1169 решена.

1 голос
/ 22 марта 2019

Компоновщик разрешает символы на основе первого совпадения - приоритет для отдельно связанных файлов .obj, а затем файлов .lib в порядке, указанном для компоновщика командной строки. Таким образом, вы обычно можете переопределить символ библиотеки, просто связывая свою собственную замену. Я никогда не пробовал это с MSVC, и это довольно жестокий подход.

Альтернативное решение, которое не зависит от конкретного поведения компоновщика, заключается в использовании препроцессора для замены стандартных символов вашими собственными альтернативами. Например:

#if defined _WIN32
    #define fopen test_fopen
    FILE* test_fopen( const char * filename, const char * mode ) ;
#endif

добавьте другие необходимые макросы и объявления в файл заголовка с именем testlib.h, например, затем используйте «принудительное включение» (/FI testlib.h в MSVC), чтобы незаметно включить интерфейс теста везде . Затем, при сборке в Windows, все вызовы fopen будут заменены на test_fopen, вместо этого вызывая ваши функции замены.

...