一.前言
Linux拥有丰富各种源代码资源,但是大部分代码在Windows平台情况是无法正常编译的。Windows平台根本无法直接利用这些源代码资源。如果想要使用完整的代码,就要做移植工作。因为C/C++ Library的不同和其他的一些原因,移植C/C++代码是一项困难的工作。本文将以一个实际的例子(Tar)来说明如何把Linux代码移植到Windows平台上。移植过程将尽量少修改代码,以便代码的运行逻辑不会发生任何变动。保留绝大部分软件主要功能。 二.准备工作
Tar是Linux平台下面一个打包工具。移植这样一个程序到windows平台需要做那些工作呢?
首先是一些准备工作,在Windows平台上面安装上Cygwin的最新版本,在Cygwin中安装好GCC等开发工具。 同样也需要一个Windows开发环境。可以使用最新版本Visual Studio, Microsoft Visual Studio .NET 2003。从www.gnu.org上取得Tar的最新源代码,版本是1.13。在Cygwin下面解开tar-1.13.tar.gz.源代码包。注意请不要在Windows下面使用WINRAR或者WINZIP来解压缩。 WINRAR和WINZIP在解压缩某些tar.gz包的时候会有问题。使得解包之后的目录和文件出现异常。如果是源代码包将有可能不能在Cygwin下面正确编译。解开压缩包之后,进入 tar-1.13目录,在当前的目录下面输入./configure命令,运行完毕之后,再次输入make命令。开始编译tar的Cygwin版本。编译基本上不会有问题,进入src目录,可以看到新编译好的Tar程序tar.exe。
Cygwin是一个API层的Linux模拟环境。如果能够在Cygwin下面编译,运行。实际上也就是能在Windows下面编译和运行,只是需要有一层中间API模拟某些Linux特有的操作。简单的判断一个Linux程序能不能移植到Windows平台下面,就是看是否能在Cygwin下面编译源代码,并运行程序。在Cygwin中编译Tar的源代码,判断能否移植只是其中一个原因。另外一个原因是移植代码过程中需要一个特殊的头文件config.h。config.h是移植过程中最重要的源代码文件。Config.h文件并不是源代码本身的一部分。文件是在Cygwin下面运行”./configure”命令时生成的。在Cygwin下运行”./Configure”命令时,会根据Cygwin平台开发环境生成config.h文件。编译时也需要config.h文件对代码编译项进行控制。移植工作也以config.h文件为基础。
接下来就是构造Windows工程。先用Visual Studio .NET 2003创建一个空的工程(Project),命名为WinTar。根据Cygwin中的编译输出信息,Tar主要的代码在Src和lib两个目录中。把这两个目录复制到新工程里,并把代码加入到工程中。然后复制Config.h到WinTar工程目录下面。
准备工作基本上完成了,接着就是移植。移植过程可以分为3个部分。
三.第一个目标:使得WinTar能编译过(Compiler)
第一个目标的完成主要围绕Config.h来实现。Linux下开发环境和Windows开发环境很大的不同是C Library头文件和各种类型的定义不同。而Config.h提供了完整编译开关来处理因为不同平台间开发环境不同带来的不同之处。现在需要手工去修改这个文件,以便Tar源代码能适应Windows平台。
首先调整各种C Library头文件(Header File)的包含问题。在Config.h中定义了很多类似HAVE_XXXX_H。比如定义HAVE_CONFIG_H为1表示工程中可以使用config.h。
#define HAVE_MALLOC_H 1表示可以在工程中使用Malloc.h头文件。通过调整这些定义值,可以去除一些Windows平台下面没有的头文件包含。也许其他地方还有很多头文件包含关系需要处理,但是这里的定义基本上解决了大部分的头文件包含问题。在编译过程中,很多错误是有由lib目录下的文件产生的,但是lib目录下的文件不是完全都需要的。lib目录只是一个对Tar的补充库。需要的代码才需要编译。 具体判断的方法一个是参考Windows C Library库的内容。如果同样的函数,数据类型已经定义,就不需要Lib目录中的相同数据类型的定义和函数实现了。还有一个方法是尽量去掉lib目录中的C文件,只保留头文件,并使得编译能够通过,根据link的错误信息去检查那些lib中的C文件是需要的。
除了修改外围的各种头文件之外,还不要忘了修改工程的编译选项,特别是预定义选项。在Tar的移植过程就需要以下的预定义HAVE_CONFIG_H,_POSIX_SOURCE,MSDOS。HAVE_CONFIG_H 表示程序编译需要config.h文件。为了方便期间,在tar移植过程中就放到工程的预编译选项中了。MSDOS,移植的是Linux下的控制台程序,而Windows平台最接近Linux控制台就是DOS,特别是一些环境变量设置和全局常量的定义。Tar的有些代码针对MSDOS环境已经做了一部分修正,这点在移植过程中可以利用起来。还有一个可选项是__CYGWIN__。有些Linux程序会针对Cygwin平台做出代码上的特殊设定。当遇到这样的代码的时候,一定要加上__CYGWIN__预定义项,能够大大减少移植需要的工作量。还有就是移植过程引入的各种Cygwin代码中也可能需要__CYGWIN__定义(有时候是其他的定义,比如_POSIX_SOURCE,或者__INSIDE_CYGWIN__)。
经过上述的几个步骤。第一个目标,代码能够编译通过基本上是不会有什么问题的。只要把握好二个修改代码的基本原则,第一。引入新的代码,而不修改原有的代码。在没有办法进行调试前修改源代码是不允许的,修改的不好就会引起最后代码运行逻辑的混乱,而且在代码能够运行之前是很难发现问题的。所以除非非常有把握,否则不要修改被移植工程的源代码。第二,引入新的代码之后,不能因为这次引入而需要再次引入新的代码。这样子,就进入死循环了。为了解决某个数据类型的定义,而引入了新的不能解释的数据类型。这样还不如不引入新的代码。所以引入新的代码,特别是很多头文件。引入之前一定要做修改,只保留工程本身需要的部分,去除那些不需要的代码。直到能编译通过为止。 三:第二个目标,使得代码能够链接过(Link)完成了第一个目标之后,就会有大量的link错误。原因是前面引入了很多外部函数,外部全局常量只有定义而没有实体,于是就会产生link错误。现在需要的是为代码提供引入的函数实体,外部全局变量实体。一般都是函数link(本文于2003年完成. 如需要转载 请联系jackforce at 163.com)不到的比较多。
要解决link错误就需要了解不同平台上面函数操作的区别,特别是某些概念的区别。这里最好的参考资料有两个。一个是Windows Services for UNIX (SFU)的帮助文件,一个是MSDN中的一篇文章《UNIX Application Migration Guide》。SFU是微软提供一个Unix兼容环境,有点像Cygwin。在安装上SFU之后有一个帮助文件。其中有一部分就是Unix,Linux函数的说明,有些函数提供了信息说明可以用Windows Library中那些函数来替代。这点对于移植是很重要的(省事)。UNIX Application Migration Guide应该不算文章而是有点像书了。它说明了很多windows和Unix系统(类Unix系统)中很多概念不同之处,针对这些不同的概念提供了很多相关的信息来说明如何进行模拟这些不同之处。比如Unix系统中Signals概念可以使用Windows环境中的Event来替代。SIGALRM用Windows Message来替代等。
SFU的帮助文件提供了一部分信息来说明Windows平台中哪些低阶函数(C 函数库)可以替代相关Unix函数。《UNIX Application Migration Guide》则提供了一种方法来转换Unix平台上的一些OS级的概念到windows上。实际上Cygwin下面也做了很多这样的转换。具体解决link问题的时候可以参考Cygwin本身的实现。
不过有些概念,比如安全权限方面的概念。在Linux平台和windows平台上面是完全不能互换的。而且windows平台中的权限函数操作(本文于2003年完成. 如需要转载 请联系jackforce@163.com)的过于复杂。这样对于某些linux函数。比如getuid处理可以参考Cygwin的处理办法。什么也不做直接返回0 (return 0)。当代码中遇到这些函数的时候可以从Cygwin的代码中复制一个getuid出来。放入工程中去。利用这些资料,并通过相关的工具比如sourceinsight来搜索Cygwin本身的源代码,Link问题并不难处理。只是有可能在处理link问题的过程中会回复到上面的问题,编译不过。这个时候的代码修改还是一定要注意不要引入太多的新的代码,免得问题越来越复杂。
四:代码运行正常
实际上当link问题解决之后,程序可以在windows环境中运行时,一切就尽在掌握了。如果不考虑做多平台的程序的话,这个时候就可以任意去修改程序了。不过在代码调试过程可能需要一个参照,看看正常的程序运行流程是怎么样的。刚刚移植过来的程序在很多地方并不能马上就能正常的运行。回到Cygwin中,重新编译一个可以调试的版本(在GCC编译选项加上-g3),在需要的时候可以在Cygwin中调试程序。调试可以用GDB或者Insight。如果习惯Windows 平台下面编程,可以使用Insight,这是一个TCL/TK脚本程序,它提供了一个Windows界面以方便用户调试程序,不过Insight最终还是调用GDB。在这里具体调试就不细说明了。
五:多平台代码
移植后的代码(本文于2003年完成. 如需要转载 请联系jackforce@163.com)如果需要在多个平台上面运行,就要在lib目录里面大做文章了。提供自己的函数库,并根据各个平台进行调整。Tar的代码由Config.h和一些编译选项来控制如何在各个不同的平台上面做编译。Lib则提供了很多C Library函数或者不同平台下面的其他函数的替代版本。这样Tar在编译过程中就不会因为某些平台下某些函数的缺失而编译不过。多平台支持,一般都是在代码中加上很多编译开关,在编译期间去分隔Linux,Windows或者其他平台下面的特殊代码。比如utime.h头文件的包含问题。因为文件在Linux(gcc)下面和Windows(cl)下所处的C Library目录不同。包含的处理办法就不一样。可能需要这样写才能完全正确的包含。