将Linux代码移植到Windows的简单方法

将Linux代码移植到Windows的简单方法

 
 

  一.前言html

  Linux拥有丰富各类源代码资源,可是大部分代码在Windows平台状况是没法正常编译的。Windows平台根本没法直接利用这些源代码资源。若是想要使用完整的代码,就要作移植工做。由于C/C++ Library的不一样和其余的一些缘由,移植C/C++代码是一项困难的工做。本文将以一个实际的例子(Tar)来讲明如何把Linux代码移植到Windows平台上。移植过程将尽可能少修改代码,以便代码的运行逻辑不会发生任何变更。保留绝大部分软件主要功能。linux

  二.准备工做编程

  Tar是Linux平台下面一个打包工具。移植这样一个程序到windows平台须要作那些工做呢?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多线程

  命令,运行完毕以后,再次输入app

makeide

  命令。开始编译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平台下面没有的头文件包含。也许其余地方还有不少头文件包含关系须要处理,可是这里的定义基本上解决了大部分的头文件包含问题。

/* Define if you have the <linux/fd.h> header file. */
/* #undef HAVE_LINUX_FD_H */

/* Define if you have the <locale.h> header file. */
#define HAVE_LOCALE_H 1

/* Define if you have the <malloc.h> header file. */
#define HAVE_MALLOC_H 1

/* Define if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1

/* Define if you have the <ndir.h> header file. */
/* #undef HAVE_NDIR_H */

  第二步,调整各类数据类型的定义,可能在linux下面会有不少特殊的数据类型定义,Config.h文件中也包含了一部分能够变更的数据类型定义项。这些定义通常都是基本数据类型的重定义。能够根据Windows平台下的数据类型定义状况进行修补。好比在Cygwin的开发环境中有个数据类型mode_t, Visual Studio的C Library中却(做者 很土,联系方法 jackforce at 163 dot com)找不到这样数据类型。Tar代码中使用了大量的mode_t数据类型. config.h中提供了修改项来让开发人员本身修改mode_t的定义,并提示若是mode_t在<sys/types.h>中没有定义的话,能够把他定义为int型。因此在config.h加上#define mode_t int。这样mode_t没有定义的问题就解决了。其余的数据类型也是一样对待处理。

* Define to `int' if <sys/types.h> doesn't define. */
#define mode_t int

/* Define to `long' if <sys/types.h> doesn't define. */
/* #undef off_t */

/* Define to `int' if <sys/types.h> doesn't define. */
#define pid_t int

  第三步,调整各类函数定义。在Config.h中除了HAVE_XXXXX_H以外还有一种预约义,HAVE_XXXX。 这是一些可选用函数定义开关。#define HAVE_MEMSET 1 表示工程中可使用memset函数。也就是说工程用到的类库中已经实现了这个函数。若是没有,那么就须要#undef HAVE_MEMSET,固然也能够本身提供这些函数。

/* Define if you have the memset function. */
#define HAVE_MEMSET 1

/* Define if you have the mkdir function. */
#define HAVE_MKDIR 1

/* Define if you have the mkfifo function. */
#define HAVE_MKFIFO 1

/* Define if you have the munmap function. */
#define HAVE_MUNMAP 1

  最后,Config.h文件中除了上面的头文件,函数,数据类型编译选项以外,还有其余一些东西,好比环境变量,其余编译选项。这些内容会根据不一样的项目而有很大的不一样。可是能够从Config.h基本看出移植的工做量有多大。

  通过上面的调整以后,势必(做者很土,其余文章 请查看vchelp很土专栏)由于Windows环境下没有某些头文件,好比poll.h,就会没有poll函数,没有dirent.h 就会没有dirent 结构体。而继续使得WinTar编译不过。这个时候就须要根据具体的编译错误信息进行细节修饰。当须要使用Windows下一些特殊的定义的时候请不要忘了在Config.h的最前面加入#include <Windows.h>. 
关于细节修饰,举个例子来讲明。好比有个选项HAVE_INTTYPES_H

/* Define if <inttypes.h> exists, doesn't clash with <sys/types.h>,
and declares uintmax_t. */
#define HAVE_INTTYPES_H 1

  经过分析代码能够发现,代码并非须要一个完整的inttypes.h文件,而是为了一个uintmax_t的定义。在Visual Stdio的C Library中并无inttypes.h这个文件,也没有uintmax_t这个定义。回溯Cygwin的include目录的inttypes.h文件,发现了uintmax_t的定义

typedef unsigned long long uintmax_t;

  很简单的数据类型重定义。这么简单定义,彻底能够从Cygwin的Include目录中单独拿出来作一个专用版本的inttypes.h加入到WinTar项目中。这样编译过程当中uintmax_t没有定义的问题就解决了。解决这类问题的通常的作法也就是从Cygwin的Include目录里面拿出相关的头文件进行修改或者单独复制到WinTar的目录下面。[本文于2003年完成. 如须要转载 请联系jackforce at 163 dot com ]修改或者复制代码的原则是再也不引入更多的定义或者头文件,仅取所需部分。其余相似的问题还有direct结构定义和相关函数。

  在编译过程当中,不少错误是有由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目录不一样。包含的处理办法就不同。可能须要这样写才能彻底正确的包含。

#if HAVE_UTIME_H ---- 若是有utime.h 文件
# ifdef WIN32 -----若是是win32环境 
# include <sys/utime.h> -----包含sys/utime.h
# endif
# ifdef LINUX ---- 若是是Linux环境
# include <utime.h> ---- 包含utime.h 
# endif
#else --- 若是没有utime.h定义出须要的结构 
struct utimbuf
{
long actime;
long modtime;
};
#endif

  在其余的代码中基本上也是这样的处理。根据编译环境的不一样来编译不一样的代码。 这样的define的区隔,主要就是为了区隔不一样平台的不一样细微区别。有的区别也许是某些常量没有定义,有些区别是某些函数不存在。若是代码中调用函数在某些平台下面不存在,就须要提供一个lib去提供这些函数。Tar的Lib的做用也是如此。

  基本上代码的移植是前难后易。前期首先要保证源代码自己的逻辑不能变更,因此在修改代码方面只能尽可能修改外围的代码,而不是修改源代码自己。若是link过了以后,则就是通常的Windows下面的编程了,能够根据需求任意修改移植后的代码了。最难的地方可能就是OS级不一样概念的替换了。C Library虽然在各个平台上有不一样之处,可是老是比较接近,不一样的地方能够提供本身编写的代码来替换。可是OS级的概念,和平台相关性太大,通常不太容易替换。

  六:扩展问题,待解决的问题

  若是须要把移植过来的代码改为DLL或者lib给其余的工程调用。好比给其余的工程提供一个解包Tar文件的功能。若是不加修改,那么移植过来的代码有不少缺陷。

  首先是多线程支持问题。若是代码中有不少全局变量,那么改为DLL或者lib以后就不能在多线程下面调用。

  其次,DLL接口表。移植后的代码入口是main函数,虽然整个工程里面有不少独立功能,可是这些独立功能的调用都是经过使用不一样的参数来实现。如何输出接口表给其余工程使用,须要作些功夫。

  3、控制 原始的控制台程序在下了运行参数以后,通常都是一头运行到底的,也有可能在中间有些要求输入某些信息的。这样的程序如何集成到其余的工程中并受到其余工程的控制?好比遇到某些错误要返回等等。在Tar代码中遇到错误就直接退出程序。显然这些地方就不合DLL设计要求。可能须要从新设计代码的结构。

  四,输出信息。Tar工程里面不少向控制台输出的信息。这些信息输出须要从新定向或者屏蔽。

  第三第四部分能够参考Linux下面的FrontEnd程序,即只是为某个特殊的程序提供的一个GUI界面的程序。FrontEnd程序就是控制了主程序的运行并从新定向输出信息到GUI界面上。

  注1. Cygwin,是Windows平台下面的一个Linux模拟环境。能够从www.Cygwin.com上下载所有内容。

  注2. Windows Services for UNIX (SFU)的SDK能够从微软网站上得到 http://www.microsoft.com/windows/sfu/

  注3. UNIX Application Migration Guide 能够从MSDN中取得,若是没有MSDN能够从微软MSDN网站上取得。 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnucmg/html/ucmglp.asp

  注4. Tar, Cygwin下面有Tar。可是只能在Cygwin下面运行 或者必须提供Cygwin的平台DLL才能在windows下面单独使用Tar程序。
注5. CL是微软的C/C++编译器,包含在Visual Studio各个版本中

  本文于2003年完成. 如须要转载 请联系jackforce@163.com,若是有看到部分干扰信息.请原谅.主要避免转载过程当中做者信息丢失用.不得觉得之,请各位原谅.

  PS :

  用一个例子简单说明了从linux平台移植到windows平台上的一些须要注意的问题和解决方法.

  例子仅用来讲明移植过程产生的问题用.

相关文章
相关标签/搜索