Все компоненты в вашем приложении должны иметь одинаковое время выполнения. Если это не так, вы сталкиваетесь со странными проблемами, такими как утверждение операторов delete.
Это одинаково на всех платформах. Это не то, что изобрела Microsoft.
Вы можете обойти эту проблему «только одного времени выполнения», зная, где время выполнения может сдерживаться.
Это в основном в тех случаях, когда вы выделяете память в одном модуле и освобождаете ее в другом.
a.dll
dllexport void* createBla() { return malloc( 100 ); }
b.dll
void consumeBla() { void* p = createBla(); free( p ); }
Когда a.dll и b.dll связаны с разными значениями времени восстановления, происходит сбой, поскольку функции времени выполнения реализуют свою собственную кучу.
Вы можете легко избежать этой проблемы, предоставив функцию destroyBla, которая должна вызываться для освобождения памяти.
Есть несколько моментов, когда вы можете столкнуться с проблемами во время выполнения, но большинства можно избежать, обернув эти конструкции.
Для справки:
- не выделять / освобождать память / объекты через границы модуля
- не используйте сложные объекты в вашем интерфейсе DLL. (например, std :: string, ...)
- не используйте сложные механизмы C ++ через границы dll. (typeinfo, исключения C ++, ...)
- ...
Но это не проблема с манифестами.
Манифест содержит информацию о версии среды выполнения, используемой модулем, и встраивается в двоичный файл (exe / dll) компоновщиком. Когда приложение загружено и его зависимости должны быть разрешены, загрузчик просматривает информацию о манифесте, встроенную в exe-файл, и использует соответствующую версию библиотек времени выполнения из папки WinSxS. Вы не можете просто скопировать среду выполнения или другие модули в папку WinSxS. Вы должны установить среду выполнения, предлагаемую Microsoft. Существуют пакеты MSI, поставляемые Microsoft, которые могут выполняться при установке программного обеспечения на компьютере тестового / конечного пользователя.
Так что устанавливайте среду выполнения перед использованием приложения, и вы не получите ошибку «отсутствует зависимость».
(обновлено до вопроса «Как Linux избегает использования файлов манифеста»)
Что такое файл манифеста?
Файлы манифеста были введены для размещения информации о неоднозначности рядом с существующей библиотекой исполняемых / динамических ссылок или непосредственно встроены в этот файл.
Это делается путем указания конкретной версии библиотек, которые должны быть загружены при запуске приложения / загрузки зависимостей.
(Есть несколько других вещей, которые вы можете сделать с файлами манифеста, например, некоторые метаданные могут быть помещены сюда)
Почему это сделано?
Версия не является частью имени DLL по историческим причинам. Таким образом, «comctl32.dll» назван так во всех версиях. (Таким образом, comctl32 под Win2k отличается от такового в XP или Vista). Чтобы указать, какую версию вы действительно хотите (и проверяли), поместите информацию о версии в файл «appname.exe.manifest» (или вставьте этот файл / информацию).
Почему это было сделано таким образом?
Многие программы установили свои dll в каталог system32 в systemrootdir. Это было сделано для того, чтобы можно было легко развертывать исправления в общих библиотеках для всех зависимых приложений. А в дни ограниченной памяти разделяемые библиотеки уменьшали объем памяти, когда несколько приложений использовали одни и те же библиотеки.
Эта концепция была нарушена многими программистами, когда они установили все свои библиотеки в этот каталог; иногда перезаписывают новые версии общих библиотек более старыми. Иногда библиотеки бесшумно изменяли свое поведение, так что зависали зависимые приложения.
Это привело к подходу «Распределить все библиотеки в каталоге приложения».
Почему это было плохо?
Когда появились ошибки, все dll, разбросанные по нескольким каталогам, должны были быть обновлены. (gdiplus.dll) В других случаях это было невозможно даже (компоненты Windows)
Манифест подход
Этот подход решает все проблемы, описанные выше. Вы можете установить dll в центральном месте, где программист может не вмешиваться. Здесь DLL могут быть обновлены (путем обновления DLL в папке WinSxS), и загрузчик загружает «правильный» DLL. (сопоставление версий выполняется загрузчиком dll).
Почему в Linux нет этого механизма?
У меня есть несколько догадок. (Это на самом деле просто гадание ...)
- Большинство вещей с открытым исходным кодом, поэтому перекомпиляция для исправления не является проблемой для целевой аудитории
- Поскольку существует только одна «среда выполнения» (среда выполнения gcc), проблема с разделением среды выполнения / границами библиотеки не возникает так часто
- Многие компоненты используют C на уровне интерфейса, где эти проблемы просто не возникают, если все сделано правильно
- Версия библиотек в большинстве случаев встроена в имя ее файла.
- Большинство приложений статически связаны со своими библиотеками, поэтому никакой dll-ад не может возникнуть.
- Среда выполнения GCC поддерживалась очень стабильной, поэтому эти проблемы не могли возникнуть.