Chinaunix首页 | 论坛 | 博客
  • 博客访问: 283706
  • 博文数量: 65
  • 博客积分: 3091
  • 博客等级: 中校
  • 技术积分: 705
  • 用 户 组: 普通用户
  • 注册时间: 2005-01-25 09:44
文章存档

2013年(2)

2012年(11)

2011年(12)

2010年(13)

2009年(15)

2008年(12)

分类:

2008-07-15 18:07:34

    对程序的可移植性而言,各种Lunix(各类unix和linux)系统之间的差异不大,这里主要考虑程序在Lunix与Windows系统之间互相移植的问题,而且限定在C/C++语言范围类,以典型的两种编译环境,即Lunix下的GCC和MS的VC编译工具集为例来阐述问题。
    一个编译单元,即这里所指的一个C/C++源程序文件,它所编译出来的二进制目标文件通常被用来构建一个动态共享库,或者被连接进一个可执行程序文件。这两种不同的用途使得我们在编译时需要多考虑一些因素(在Win环境下尤其如此)。具体有:
    (1) C/C++头文件在被用于构建动态共享库的源程序文件使用时,以及在被使用动态共享库的其他源程序文件使用时,表现出不同的行为和作用。
    (2) 全局对象(变量,函数,类的实例)的声明和定义,以及初始化。
    (3) Lunix下的(动态)共享库中所有的全局对象是外部可见的(一般的连接方法下);Windows下的动态(共享)库中的全局对象的外部可见性可由程序员指定。(个人愚见,win下的思路是好的,但是实现的方法不好,包括使用__declspec...,鉴于C语言中的全局对象在申明时默认为extern类型的,可以考虑使用这个保留字来指定全局对象的外部可见性和指明某(些)全局变量来自动态共享库。)
    代码是最好的注释,举例如下:
1. 文件f.h
#ifndef F_H
#define F_H

#ifdef F_FULL_LINKED
# ifdef F_BEING_COMPILED
#  define F_LINK_SPEC
#  define F_DECL_SPEC
# else
#   define F_LINK_SPEC
#   define F_DECL_SPEC extern
# endif
#else /* To be dynamic linked */
# ifdef F_BEING_COMPILED
#  ifdef WIN32
#   define F_LINK_SPEC __declspec(dllexport)
#   define F_DECL_SPEC
#  else
#   define F_LINK_SPEC
#   define F_DECL_SPEC
#  endif
# else
#  ifdef WIN32
#   define F_LINK_SPEC __declspec(dllimport)
#   define F_DECL_SPEC
#  else
#   define F_LINK_SPEC
#   define F_DECL_SPEC extern
#  endif
# endif
#endif

# define F_LINK_DECL F_LINK_SPEC F_DECL_SPEC

#ifdef F_GLOBAL_INIT
F_LINK_SPEC int g_f = 1;
F_LINK_SPEC int gfA[2] = {1, 2};
#else
F_LINK_SPEC extern int g_f;
F_LINK_SPEC extern int gfA[2];
#endif

F_LINK_DECL int f(int a);

#endif /* F_H */

2. 文件f.c
#include

#define F_BEING_COMPILED

#define F_GLOBAL_INIT
#include "f.h"

int f(int a)
{
    return a * (gfA[0] + gfA[1]);
}

3. 文件t.c
#include

#include "f.h"

int main()
{
    gfA[0]++, gfA[1]++;
    printf("g_f = %d, f(1) returns %d\n", g_f, f(1));
    return 0;
}

  说明:有些预处理器不支持类如 #define F_LINK_DECL F_LINK_SPEC F_DECL_SPEC 的预定义方法。
 
  在Linux下,使用命令行 gcc -E f.c > f.i; gcc -E t.c > t.i 生成的预处理代码如下:
预处理后的文件f.i:
......
# 2 "f.c" 2




# 1 "f.h" 1
# 35 "f.h"
 int g_f = 1;
 int gfA[2] = {1, 2};





 int f(int a);
# 7 "f.c" 2

int f(int a)
{
    return a * (gfA[0] + gfA[1]);
}

预处理后的文件t.i:
......
# 2 "t.c" 2

# 1 "f.h" 1
# 38 "f.h"
 extern int g_f;
 extern int gfA[2];


 extern int f(int a);
# 4 "t.c" 2

int main()
{
    gfA[0]++, gfA[1]++;
    printf("g_f = %d, f(1) returns %d\n", g_f, f(1));
    return 0;
}
然后,可以通过命令行 gcc -c -fPIC -o f.o f.c; gcc -c -fPIC -o t.o t.c和命令行 gcc -shared -o libf.so f.o; gcc -o t -L. -lf t.o 生成共享(动态)库和可执行程序。

在Windows的VC6.o编译环境下,使用命令行 cl /E /DWIN32 f.c > f.i 和 cl /E /DWIN32 t.c > t.i 生成的预处理代码如下:
预处理后的文件f.i:

......

__declspec(dllexport) int g_f = 1;
__declspec(dllexport) int gfA[2] = {1, 2};



#line 41 "f.h"

__declspec(dllexport)  int f(int a);

#line 45 "f.h"

#line 7 "f.c"

int f(int a)
{
    return a * (gfA[0] + gfA[1]);
}


预处理后的文件t.i:

......

__declspec(dllimport) extern int g_f;
__declspec(dllimport) extern int gfA[2];
#line 41 "f.h"

__declspec(dllimport)  int f(int a);

#line 45 "f.h"

#line 4 "t.c"

int main()
{
    gfA[0]++, gfA[1]++;
    printf("g_f = %d, f(1) returns %d\n", g_f, f(1));
    return 0;
}
然后,可以通过命令行 cl /c /DWIN32 /Fof.obj f.c 和 cl /c /DWIN32 /Fot.obj t.c 以及命令行 link /DLL /IMPLIB:libf.lib /OUT:libf.dll f.obj 和 cl /Fet.exe t.obj /link /LIBPATH:.\ libf.lib(或 cl -o t.exe t.obj /link /LIBPATH:.\ libf.lib) 生成(共享)动态库和可执行程序。

若不生成(共享)动态库而直接构建可执行程序,则可以在Windows的VC6.o编译环境下通过命令行 cl /DWIN32 /DF_FULL_LINKED /Fetest.exe f.c t.c (或 cl -o test.exe /DWIN32 /DF_FULL_LINKED f.c t.c)。源程序经过预处理后的内容如下(使用命令行 cl /E /DWIN32 /DF_FULL_LINKED f.c > f.i 和 cl /E /DWIN32 /DF_FULL_LINKED t.c > t.i):
文件f.i的内容:
......

 int g_f = 1;
 int gfA[2] = {1, 2};



#line 41 "f.h"

  int f(int a);

#line 45 "f.h"

#line 7 "f.c"

int f(int a)
{
    return a * (gfA[0] + gfA[1]);
}
文件t.i的内容:
......

 extern int g_f;
 extern int gfA[2];
#line 41 "f.h"

 extern int f(int a);

#line 45 "f.h"

#line 4 "t.c"

int main()
{
    gfA[0]++, gfA[1]++;
    printf("g_f = %d, f(1) returns %d\n", g_f, f(1));
    return 0;
}
在Lunix环境下,使用命令行 gcc -E -DF_FULL_LINKED f.c > f.i; gcc -E -DF_FULL_LINKED t.c > t.i 可得到类似的预处理后的结果。

采用命令行的编译方法,可以写出一份跨平台的Makefile文件。

以上的这些方法,可以用于开发跨平台的软件项目。
阅读(828) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~