微软的技术态度 -- 从其对于CRT的设计考虑说起(Thought on the CRT - What Microsoft Prefers)

      很多人从C语言学习过来的人都知道,在编写程序时用到的像printf这样的函数,是作为该语言标准库函数提供的,这也是C语言标准中规定的内容。因此,操作系统必须对其保持一定程度上的透明,也就是说,作为一个生态系统提供商,这里以Windows为例,如果提供C语言作为开发语言,那么应该尽量提高透明度,减少开发者学习成本。然而据我这几天的研究,微软的态度可能不太明朗。

两个CRT    

      熟悉Visual C++的朋友很容易发现,每次新的Visual Studio版本发布总会附加一个新的CRT库,这也是导致在高版本上编写的C程序通常无法在比较旧的平台上运行,必须安装相应版本的可在发行组件包才行。几大版本的Visual C++附带的C库如下表所示:

Version       C Runtime Library C++ Runtime Library
Visual C++ 2005 msvcr80.dll msvcp80.dll
Visual C++ 2008 msvcr90.dll msvcp90.dll
Visual C++ 2010 msvcr100.dll msvcp100.dll
Visual C++ 2012 msvcr110.dll msvcp110.dll
Visual C++ 2013 msvcr120.dll msvcp120.dll

(注:msvc*80.dll和msvc*90.dll还存在多个相同名称的版本,但从VC2010开始就不存在这种情况,这里牵涉到Side-by-side assembly技术,这比较坑,不展开说明)

同时如果足够细心,会发现在system32目录下存在着msvcrt.dll文件,这样的名称足足让人产生怀疑,notepad等程序正是依赖这个文件运行,

另外,该文件的详细信息中也表明这是一个CRT

如果细究其导出函数,也可以发现基本也是差不多的,更能说明其用途。

 

存在的问题

      一个系统存在两套同样功能的程序库,这显然不太符合常识。在估测微软为什么做如此设计的原因之前,需要关注下目前Windows平台下CRT各版本的兼容性问题及其技术背景。

      一个系统的好坏、特别是软件系统是由其提供的向前兼容性高低决定的。也就是说,理想情况下,新版本的程序库A替换旧版本的A不会出现问题。在实践上程序库的编写者为了达到以上目的对程序代码制订了一些规范,如调用约定、函数签名等(可参看Application binary interface),很多实例证明,这样的约束对C语言编写的程序库苛刻程度比较低,相对于C++而言(可以参考KDE C++ Compatibility Issues),Linux平台下各种C编写的库均持有良好的兼容规范。

      这里可以用Glibc作为对比,Glibc文件名形如x.y.z,是x为主版本号、y为次版本号、z为发布版本号,其中主版本号不要求兼容性,及此项不提供向后兼容性;此版本号要求兼容性;而发布版本号是bugfix,不改变原版本的兼容性。这一描述摘自于GNU的官方描述,从中我们可以知道,获取一定程度上的向后兼容在技术上还是可以实现的。

      然而Windows平台下CRT版本兼容性却令人摸不着头脑,这样的问题特别集中在VS2005和VS2008发布的CRT版本上。这两个大版本的CRT在小版本之间也是不兼容,比如使用VS2005发布的C程序与VS2005 SP1发布的两者无法兼容,就像上面提到的,微软甚至开发WinSxS技术来维持这种不兼容性,实在令人费解。

      这样带来的麻烦也是显而易见的,对于开发者而言,由于最终用户端不定的环境,需要更多的考虑发布程序上的事宜,分散关注应用本身的精力;更致命的是,或者说有可能打击到开发者的开发兴趣的是,软件应用开发过程中需要的各种依赖于CRT的程序库由于上述的兼容性问题,必须与应用软件本身一起统一到同一个版本上来,而这样做会使得开发软件的成本进一步提高,MSDN中也提到该问题。这里可以举一个例子,比如A软件应用,依赖B、C两个程序库,假设开发团队计划基于VS2010开发A,然而提供B的软件公司最高只提供VS2008编译版本,这时不得不把A的开发平台也降至VS2008下,不仅如此,往后的对A的开发平台的升级更会受制于B、C 程序库的版本。对于开发团队而言,无论是平台迁移还是购置新版本的程序库都是一笔很大的开销。综上所述,微软设置的不同版本间的完全不兼容性确实给开发者一定的麻烦,更重要的是,这并不是由技术水平限制而带来的。

      对于最终用户而言,最常见的现象就是软件缺少相对应的CRT而无法运行,而用户不得不需要承担由此带来的上手难度;面对诸多Visual C/C++可发行组件包必将会束手无策,让最终用户承担这种由非技术原因引起的后果的确很不应该。

      总之,相比其它平台,作为微软为什么如此设计Windows操作系统中的CRT,可能更多要从非技术层面去考量。

不纯的动机

      从上述的问题中,不难看出微软在对待CRT的两个决策,一个是相似功能的CRT提供了两套,依据其作用可分为系统级和用户级;另一个是用户级CRT中设置了多了版本,且多个版本之间完全不兼容。依我之见,这两个决策的形成,将本来很是容易实现的技术复杂化,可能更多是商业上的原因。

      第一个决策中的两套CRT设置,暂且没有细究它们两者提供的接口差别,但容易想到的是系统级版本的CRT可能会在效率和稳定性等方面故意设计得比用户级好,这也符合闭源软件的一贯作风。另外,诸多Windows系统软件均是基于CRT实现无疑是承认C语言同时作为系统开发和应用开发语言的优势,但这内外的两套标准折射出微软对开发者似乎不太信任,因此设定某些限制,与第二个决策一同弱化C语言的作为Windows应用开发优势,甚至可以说是淡化C语言的地位,事实确实如此,结合微软近年来推广的.NET平台,版本间的兼容性问题带来的麻烦会让开发者在选择开发语言上做更多的权衡,而且微软一直在引导更多的人到C#语言上来。C#作为.NET主推语言在目前至少可以说还是主要在Windows平台下,联想到ObjectiveC之于iOS平台,可以看出微软在向苹果学习,不断提高Windows应用开发者迁移至其他平台的难度,加大开发者的黏性。但又做不到像苹果那样纯粹(在开源方面,也没有Linux做的纯粹),这种故意将技术复杂化带来的恶果,Windows现如今在IOS、Android双面夹击的窘迫状况无疑是最后的佐证。 

      可能这句英语更能体现微软对待技术态度 :“Microsoft tends to make things more complicated for some commercial reasons, although they does really make them look easier at the first time.”

参考

(1)History of DLL Hell and why it will repeat itself - Joseph Nord

(2)Fighting the MSVCRT.DLL hell - Mladen Turk

posted on 2014-02-08 10:17  Somnus.V  阅读(4986)  评论(39编辑  收藏  举报

导航