代码跨平台移植宏定义

上传人:大米 文档编号:502600966 上传时间:2022-09-17 格式:DOCX 页数:7 大小:25.45KB
返回 下载 相关 举报
代码跨平台移植宏定义_第1页
第1页 / 共7页
代码跨平台移植宏定义_第2页
第2页 / 共7页
代码跨平台移植宏定义_第3页
第3页 / 共7页
代码跨平台移植宏定义_第4页
第4页 / 共7页
代码跨平台移植宏定义_第5页
第5页 / 共7页
点击查看更多>>
资源描述

《代码跨平台移植宏定义》由会员分享,可在线阅读,更多相关《代码跨平台移植宏定义(7页珍藏版)》请在金锄头文库上搜索。

1、文档供参考,可复制、编制,期待您的好评与关注! 原文:http:/ Windows 移植到 UNIX 环境大多数基于 Microsoft Windows 的项目都是使用 Microsoft Visual Studio 构建的,这是一种复杂的集成开发环境 (IDE),它可以为开发人员实现几乎整个构建过程的自动化。此外,Windows 开发人员使用了 Windows 平台特定的应用程序程序接口 (API)、头文件和语言扩展。大多数类 UNIX 系统,如 SunOS、OpenBSD 和 IRIX,都不支持 IDE 或者任何 Windows 特定的头文件或扩展,因此进行移植是一项非常耗费时间的活动。更

2、麻烦的是,遗留的基于 Windows 的代码需要运行于 16 位或者 32 位的 x86 体系结构中。基于 UNIX 的环境通常是 64 位的,并且大多数 UNIX 供应商都不支持 x86 指令集。本系列文章共由两个部分组成,本文是其中的第一部分,介绍将 Windows 操作系统中一个典型的 Visual C+ 项目移植到 SunOS 中的g+环境的过程,同时详细说明了如何解决前面提到的一些问题。Visual Studio 中的 C/C+ 项目类型您可以使用 Visual C+ 项目创建三种项目变体(单线程或者多线程)中的一种: 动态链接库(DLL 或者 .dll) 静态库(LIB 或者 .l

3、ib) 可执行文件(.exe)对于更复杂的变体,可以使用 Visual Studio .NET 解决方案,这种解决方案允许创建和管理多个项目。本文在下面的几个部分中将重点关注如何将动态和静态库项目变体从 Windows 移植到 UNIX。将 DLL 移植到 UNIX 环境对于 Windows 中的 .dll 文件,UNIX 的等价物是共享对象 (.so) 文件。然而,创建一个 .so 文件的过程与创建一个 .dll 文件的过程完全不同。请考虑清单 1中的示例,在这个示例中,您尝试创建一个小的 .dll 文件,其中仅包含一个函数printHello,并且在 main.cpp 文件的 main 例

4、程中调用了这个函数。清单 1. 包含 printHello 例程声明的文件 hello.h#ifdef BUILDING_DLL #define PRINT_API _declspec(dllexport) #else #define PRINT_API _declspec(dllimport) #endif extern C PRINT_API void printHello();清单 2提供了 hello.cpp 的源代码。清单 2. 文件 hello.cpp#include #include hello.h void printHello std:cout hello Windows/U

5、NIX usersn; extern C PRINT_API void printHello();如果您使用了用于 80x86 平台的 Microsoft 32 位C/C+标准编译器 (cl),那么可以使用下面的命令来创建 hello.dll 文件:cl /LD hello.cpp /DBUILDING_DLL/LD指示cl创建一个 .dll 文件。(还可以指示它创建其他格式的文件,如 .exe 或者 .obj。)/DBUILDING_DLL为这个特定的构建过程定义了PRINT_API宏,以便从这个 DLL 导出 printHello 符号。清单 3包含了 main.cpp main 源文件,

6、其中使用了 printHello 例程。这里所做的假设是,hello.h、hello.cpp 和 main.cpp 都位于相同的文件夹中。清单 3. 使用 printHello 例程的 main 的源代码#include hello.h int main ( ) printHello(); return 0; 要编译并连接 main 代码,可以使用下面的命令行:cl main.cpp hello.lib快速地查看源文件和生成的输出,其中说明了两个重要的问题。第一点,要从一个 DLL 中导出任何函数、变量、或者类,都需要使用 Windows 特定的语法_declspec(dllexport)。同

7、样地,要向一个 DLL 导入任何函数、变量、或者类,都需要使用 Windows 特定的语法_declspec(dllimport)。第二点,这个编译过程生成了两个文件:printHello.dll 和 printHello.lib。PrintHello.lib 用于连接 main 源文件,而 UNIX 中共享对象的头文件不需要declspec语法。成功的编译过程将输出一个 .so 文件,它已经与 main 源文件进行了连接。要在 UNIX 平台中使用g+创建一个共享库,需要通过向g+传递-fPIC标志,将所有的源文件编译为可重定位的共享对象。PIC 表示位置无关代码 (position ind

8、ependent code)。在每次加载一个共享库时,可以将其潜在地映射为一个新的内存地址。因此,需要通过某种很容易进行计算的方式在库中生成所有变量和函数的地址(相对于加载该库的起始地址)。这个代码由-fPIC选项生成,并使得代码成为可重定位的。-o选项用于指定输出文件的名称,而-shared选项用于构建一个共享库,其中允许出现未解析的引用。要创建 hello.so 文件,您必须修改头文件,如下面的清单 4所示。清单 4. 包含 UNIX 特定更改的、经过修改的 hello.h 头文件#if defined (_GNUC_) & defined(_unix_) #define PRINT_AP

9、I _attribute_ (_visibility_(default) #elif defined (WIN32) #ifdef BUILDING_DLL #define PRINT_API _declspec(dllexport) #else #define PRINT_API _declspec(dllimport) #endif extern C PRINT_API void printHello();下面的g+命令用于连接共享库 hello.so:g+ -fPIC -shared hello.cpp -o hello.so要创建 main 可执行文件,请编译源代码:g+ -o mai

10、n main.cpp hello.sog+ 中的符号隐藏有两种典型的方式可以从一个基于 Windows 的 DLL 中导出符号。第一种方法是仅对从 DLL 中导出的选择元素(例如,类、全局变量或者全局函数)使用_declspec(dllexport)。第二种方法是使用一个模块-定义 (.def) 文件。.def 文件具有自己的语法,并且包含需要从 DLL 中导出的符号。g+连接器的缺省行为是从一个 .so 文件中导出所有的符号。这可能并不是所需要的,并且将使得连接多个 DLL 变成一项非常耗时的任务。为了从一个共享库中有选择地导出符号,可以使用g+属性机制。例如,可以考虑用户源代码中包含两个方

11、法,void print1();和 int print2(char*);,并且用户只需要导出 print2。清单 5包含一种实现这个目的的方法,可用于 Windows 和 UNIX。清单 5. g+ 中的符号隐藏#ifdef _MSC_VER / Visual Studio specific macro #ifdef BUILDING_DLL #define DLLEXPORT _declspec(dllexport) #else #define DLLEXPORT _declspec(dllimport) #endif #define DLLLOCAL #else #define DLLEX

12、PORT _attribute_ (visibility(default) #define DLLLOCAL _attribute_ (visibility(hidden) #endif extern C DLLLOCAL void print1(); / print1 hidden extern C DLLEXPORT int print2(char*); / print2 exported使用_attribute_ (visibility(hidden)可以防止从 DLL 中导出符号。最新版本的g+(4.0.0 以及更高的版本)还提供了-fvisibility开关,您可以使用它从一个共享库

13、中有选择地导出相关符号。在命令行中使用g+加上-fvisibility=hidden延迟从共享库中导出所有的符号,除了那些使用_attribute_ (visibility(default)声明的符号。这是一种非常简洁的方式,用于通知g+没有显式地标注可见属性的每项声明,其可见性都是隐藏的。使用dlsym提取一个隐藏的符号将会返回NULL。g+ 中的属性机制概述与 Visual Studio 环境非常相似(Visual Studio 环境在C/C+的基础上提供了许多附加的语法),g+也支持该语言的许多非标准扩展。在g+中,属性机制的用途之一就是便于进行移植。前面的示例讨论了符号隐藏。属性的另一

14、个用途是为 Visual C+ 设置函数类型,如cdecl、stdcall和fastcall。本系列文章的第 2 部分将详细地介绍属性机制。在 UNIX 环境中显式加载 DLL 或者共享对象在 Windows 系统中,可以由 Windows 程序显式地加载一个 .dll 文件,这是很常见的情况。例如,可以考虑一个复杂的、提供了打印功能的、基于 Windows 的编辑器。在用户第一次提出相应请求的时候,这种编辑器将动态地加载打印机驱动程序 DLL。基于 Windows 的开发人员可以使用 Visual Studio 提供的 API,如LoadLibrary显式地加载一个 DLL,GetProcA

15、ddress用于查询 DLL 中的符号,而FreeLibrary则用于卸载一个显式加载的 DLL。对于这些函数,UNIX 的等价物分别是dlopen、dlsym和dlclose例程。而且在 Windows 中,有一个特殊的DllMain方法,在第一次将 DLL 加载到内存时将调用这个方法。类 UNIX 系统提供了一个对应的方法,称为_init。可以考虑前面示例的一个变体。清单 6中是 loadlib.h 头文件,在调用 main 方法的源文件中使用了这个文件。清单 6. 头文件 loadlib.h#ifndef _LOADLIB_H #define _LOADLIB_H #ifdef UNIX #include #endif #include using namespace std; typedef void* (*funcPtr)(); #ifdef

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 国内外标准规范

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号