Компиляция файла C с параметрами /c и /MD, а затем связывание файлов .lib

У меня есть файл C, который использует 3-4 внешние библиотеки. Он создан с использованием cl.exe и link.exe(MSVC).

Сценарий сборки показывает, что процесс создания исполняемого файла состоит из двух этапов:

  • Используйте параметр '/c' с cl.exe, чтобы получить файл .o. С этим также дается куча других флагов, но меня интересует /MD. MSDN говорит:

Заставляет приложение использовать версию библиотеки времени выполнения, специфичную для многопоточности и DLL. Определяет _MT и _DLL и заставляет компилятор поместить имя библиотеки MSVCRT.lib в файл .obj.

Какой смысл давать /MD с cl, когда мы только компилируем, а не связываем?

  • После этого link.exe используется для генерации exe. Для компоновки указано несколько файлов .lib (например, ole32.lib, advapi32.lib, user32.lib и т. д., а также другие файлы, не относящиеся к MSVC). Мой вопрос в том, что файлы .lib не используются для статической компоновки? Если да, то почему окончательный exe-файл весит всего около 500 КБ? Ни одна из .lib не является библиотекой импорта.

    Если нет, то использует ли link статическое или динамическое связывание по умолчанию? Имеет ли здесь какой-либо эффект /MD, указанный вместе с cl?


person Cygnus    schedule 17.06.2014    source источник


Ответы (1)


Первоначальная библиотека времени выполнения C никогда не предполагалась для поддержки программ, построенных из нескольких модулей. Он содержит глобальные переменные, такие как errno и stdout, и функции с неявным глобальным состоянием, такие как strtok() и malloc(). Вы можете связать DLL с их собственной копией CRT, но это накладывает довольно драконовские требования на то, как вы проектируете интерфейс DLL. Вы должны быть очень осторожны, чтобы никогда не зависеть от состояния CRT. Неправильный подход приводит к тому, что практически невозможно диагностировать неправильное поведение во время выполнения.

Обходной путь для этого — всегда иметь только одну копию CRT в вашем процессе. Это то, что делает /MD, вы в конечном итоге получаете зависимость от версии CRT, которая хранится в DLL. Общий для всех модулей. Как и msvcr120.dll, используемый VS2013.

Компилятор должен знать это, чтобы правильно использовать эту версию DLL. Простым примером является errno, это глобальная переменная с /MT, но макрокомандируется к вызову функции с /MD, так что только одна глобальная переменная внутри DLL всегда используется для отслеживания последнего известного значения. Макрос _DLL будет определен, если действует параметр /MD, используемый в файлах .h компилятора.

Еще один побочный эффект заключается в том, что компилятор автоматически вставляет директиву ссылки (эквивалентную комментарию #pragma) либо для msvcrt.lib, либо для libcmt.lib. Разработано, чтобы помочь вам избежать ошибок и исключить необходимость явного указания ссылки на библиотеку CRT. Неправильный подход приводит к тому, что очень трудно диагностировать сообщения об ошибках компоновщика. Мало чем отличается от того, что вы получаете, когда пытаетесь связать файлы .obj или .lib, которые были созданы с несоответствием /MT и /MD. Что, конечно, не может работать должным образом, вы не можете зависеть от обоих.

Ни один из .libs не является библиотекой импорта.

Те, что вы перечислили по имени, ole32.lib, advapi32.lib, user32.lib, на самом деле являются библиотеками импорта. Это стандартные библиотеки DLL операционной системы. Во время выполнения ваша программа будет загружать соответствующие библиотеки DLL, легко видимые из отладчика. Для VS вы увидите это в окне вывода. Возможно, следует отметить, что эти библиотеки DLL на самом деле используют другую CRT, чем ваша программа, они привязываются к c:\windows\system32\msvcrt.dll. Winapi был тщательно разработан, чтобы никогда не создавать проблемы.

ссылка использует статическую или динамическую ссылку по умолчанию

По умолчанию нет, это зависит от .lib, на который вы ссылаетесь. Различайте библиотеки статических ссылок и библиотеки импорта. Библиотека импорта создается при создании библиотеки DLL. Это небольшой файл, который не содержит кода, только имена экспортируемых функций в DLL, поэтому компоновщик знает, что нужно поместить запись в таблицу импорта программы. Зависимость от DLL разрешается, а импортированные функции связываются загрузчиком при запуске программы.

person Hans Passant    schedule 17.06.2014