最近在设计一个编译系统的依赖管理部分,如果一个project的dependency closure(所有直接和间接的依赖)中有某个相同的library的不同版本,我们就认为这里有一个版本冲突, 那么在检测到版本冲突的时候,是报一个warning让警告用户,还是报一个错误直接退出,要求用户先解决版本冲突呢? 事实上,无论在windows上,还是在linux中,我们都有相应的机制来保证不同版本的library是可以在同一个程序中工作的,在windows上是side-by-side assembly,通过manifest和activation context实现,而在linux下则是通过设置RPATH。 所以我们编译系统的行为应该是报一个warning,让用户判断这个版本冲突究竟是个问题,还是可以接受的,并提供机制让用户抑制这种warning - 然后,针对不同平台产生side-by-side的library。
对于底层side-by-side如何实现,这里有三个方面:
- Windows下shared assembly: 对于用VC++ build的,有CRT, ATL, MFC以及OpenMP,这些library是与compiler对应的,所以用不同版本的VC++编译时会插入不同的manifest来表明依赖的library到底是哪里来的。这个用户基本不用做什么工作。
- Windows下private assembly:用户自己的library,想要side-by-side,这个需要用户提供相应的manifest,并且library必须放置在application的子目录下面,Microsoft提供了文档
- Linux下RPath,binary中有一个section让设置RPATH,需找library的时候,会从该path找。
这里是第一个例子,Windows下shared assembly:源码地址
foo是一个DLL, 用vs2008编译,依赖于vscrt90,bar是一个exe,用vs2010编译,自然依赖于vscrt100, 另外它还依赖foo。项目都用premake描述,生成visual studio文件后用msbuild编译。
编译步骤如下:
1. build foo
* cd foo
* premake4 vs2008
* "C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat"
* msbuild foo.sln
2. build bar
* cd bar
* premake4 vs2010
* "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Tools\vsvars32.bat"
* msbuild bar.sln
3. Copy foo.dll to bar/
运行bar.exe, 然后打开procexp查看该进程:
我们可以看到, vscrt90和vscrt100的library同时被加载到同一进程。