在Windows上构建和部署dll:SxS,清单和所有爵士乐
从VS 2005开始,我看到无法简单地针对MS运行时构建dll并将它们一起部署(http://www.ddj.com/windows/184406482)。我对manifest,SxS和co感到非常困惑:MSDN文档确实很差劲,带有循环引用。特别是由于我是Unix方面的家伙,所以我发现所有这些信息都没有意义。我的核心问题是针对msvc9或者msvc8链接dll:由于这些运行时无法重新分发,因此链接和部署此类dll的步骤是什么?特别是清单文件是如何生成的(我不希望mt.exe,我希望这些东西可以在编译器之间移植),它们是如何嵌入,使用的?并排装配是什么意思?
基本上,在哪里可以找到代替MS术语的任何规范?
谢谢所有回答的人,这真的很有帮助,
解决方案
好吧,我遇到了其中一些问题,所以也许我的一些评论会有所帮助。
- 清单是一个xml文件。虽然VS在编译时可以为我们提供帮助,但另一种解决方案是生成资源文件(.rc),并使用VS随附的资源编译器(rc.exe)将其编译为已编译的资源文件(.res)。 。我们将需要从工具菜单运行VS命令行,这将导致rc位于路径中,以及正确设置各种环境变量。然后编译资源。生成的.res文件可以由其他编译器使用。
- 确保清单XML文件的大小可被4整除。如果需要,请在文件中间添加空格以实现此目的。尝试避免在打开xml标记之前或者关闭xml标记之后包含任何字符。我有时对此有疑问。如果我们错误地执行了步骤2,则可能会遇到并行配置错误。我们可以通过在资源编辑器(例如devenv.exe)中打开exe并检查清单资源来检查这是否是错误。我们还可以通过打开一个构建文件来查看正确清单的示例,但是请注意,dll和exe在应提供资源的id上有微小的差异。
我们可能需要在Vista上进行测试,以确保其正常运行。
它们是可重新分发的,并且我们在msvs目录中具有可重新分发的软件包。
使用我们选择的运行时进行构建,将相应的软件包添加到安装程序中,不要打扰它会起作用。不同之处在于它们现在安装在不同的位置(但这也是应用程序要查找库的位置)。
否则,MSDN或者基本上所有关于Windows c ++编程的书都不会太老。
这是博客条目,解释了VC ++的SxS crt决策背后的原因。它包括说明静态链接crt有多糟糕,以及为什么不应该这样做。
这是有关如何静态链接crt的文档。
感谢回答。对于部署本身,我可以看到3个选项,然后:
- 使用.msi merge指令。
- 使用可重新分发的VS软件包并在我自己的安装程序之前运行它
- 沿着我自己的应用程序复制可再发行文件。但是在这种情况下,如何在文件系统层次结构中引用它(例如,bar / foo1 / foo1.dll和bar / foo2 / foo2.dll在bar /中引用msvcr90.dll)?我的意思是,除了明显且难看的"将dll复制到我们依赖它的dll所在的每个目录中"。
我们在所有应用程序和DLL的vcmanifest.h中使用一个简单的包含文件,然后将所有项目设置为嵌入清单文件。
vcmanifest.h
/*----------------------------------------------------------------------------*/ #if _MSC_VER >= 1400 /*----------------------------------------------------------------------------*/ #pragma message ( "Setting up manifest..." ) /*----------------------------------------------------------------------------*/ #ifndef _CRT_ASSEMBLY_VERSION #include <crtassem.h> #endif /*----------------------------------------------------------------------------*/ #ifdef WIN64 #pragma message ( "processorArchitecture=amd64" ) #define MF_PROCESSORARCHITECTURE "amd64" #else #pragma message ( "processorArchitecture=x86" ) #define MF_PROCESSORARCHITECTURE "x86" #endif /*----------------------------------------------------------------------------*/ #pragma message ( "Microsoft.Windows.Common-Controls=6.0.0.0") #pragma comment ( linker,"/manifestdependency:\"type='win32' " \ "name='Microsoft.Windows.Common-Controls' " \ "version='6.0.0.0' " \ "processorArchitecture='" MF_PROCESSORARCHITECTURE "' " \ "publicKeyToken='6595b64144ccf1df'\"" ) /*----------------------------------------------------------------------------*/ #ifdef _DEBUG #pragma message ( __LIBRARIES_ASSEMBLY_NAME_PREFIX ".DebugCRT=" _CRT_ASSEMBLY_VERSION ) #pragma comment(linker,"/manifestdependency:\"type='win32' " \ "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".DebugCRT' " \ "version='" _CRT_ASSEMBLY_VERSION "' " \ "processorArchitecture='" MF_PROCESSORARCHITECTURE "' " \ "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"") #else #pragma message ( __LIBRARIES_ASSEMBLY_NAME_PREFIX ".CRT=" _CRT_ASSEMBLY_VERSION ) #pragma comment(linker,"/manifestdependency:\"type='win32' " \ "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".CRT' " \ "version='" _CRT_ASSEMBLY_VERSION "' " \ "processorArchitecture='" MF_PROCESSORARCHITECTURE "' " \ "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"") #endif /*----------------------------------------------------------------------------*/ #ifdef _MFC_ASSEMBLY_VERSION #ifdef _DEBUG #pragma message ( __LIBRARIES_ASSEMBLY_NAME_PREFIX ".MFC=" _CRT_ASSEMBLY_VERSION ) #pragma comment(linker,"/manifestdependency:\"type='win32' " \ "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".MFC' " \ "version='" _MFC_ASSEMBLY_VERSION "' " \ "processorArchitecture='" MF_PROCESSORARCHITECTURE "' " \ "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"") #else #pragma message ( __LIBRARIES_ASSEMBLY_NAME_PREFIX ".MFC=" _CRT_ASSEMBLY_VERSION ) #pragma comment(linker,"/manifestdependency:\"type='win32' " \ "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".MFC' " \ "version='" _MFC_ASSEMBLY_VERSION "' " \ "processorArchitecture='" MF_PROCESSORARCHITECTURE "' " \ "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"") #endif #endif /* _MFC_ASSEMBLY_VERSION */ /*----------------------------------------------------------------------------*/ #endif /* _MSC_VER */ /*----------------------------------------------------------------------------*/
如果我们有要启动的服务或者要在MSI中执行" InstallFinalize"操作之前要运行的程序,则不能将VC ++ 8 SP1 / 9 CRT用作Vista和Windows Server 2008上的合并模块。
这是因为dll是通过" InstallFinalize"操作安装在WinSXS中的。
但是,MSI" ServiceStart"操作是在此之前执行的。
因此,请使用引导程序" http://www.davidguyer.us/bmg/publish.htm"
或者考虑使用安装程序4.5中的安装程序链接。但这意味着我们需要一个引导程序才能安装4.5,因此似乎毫无意义。
最简单的操作:
假设默认安装的是VS2005,我们将具有以下路径:
C:\Program Files\Microsoft Visual Studio 8\VC\redist\x86\Microsoft.VC80.CRT
去,抓住这个redist文件夹中的文件,然后将.manifest和msvcr80.dll(至少)放在应用程序.exe文件夹中。
这些文件出现在安装的根目录中,应该可以使exe和与其链接的所有dll正常运行,而无需诉诸合并模块,MSI或者实际上任何及时的未安装运行时检测。
如果打算部署Microsoft DLLs / .manifest文件并使用Java JNI,则需要将它们放在JDK / JRE的bin目录中。
如果我们正在JBoss中运行该应用程序,则需要将它们放在JBoss / bin目录中。
我们可以将JNI DLL放在适合应用程序的位置。