ICE笔记(04):slice2cpp 及编译、运行

colorado 】

 

slice2cpp 命令行语法:
[options] file…

1、通用的命令行选项是:
• -h, --help
显示帮助信息。
• -v, --version
显示编译器版本。
• -DNAME
定义预处理器符号NAME。
• -DNAME=DEF
定义预处理器符号NAME,其值为DEF。
• -UNAME
解除预处理器符号NAME 的定义。
• -IDIR
在#include 指令的搜索路径中增加目录DIR。
• E
在stdout上打印预处理器输出。
• --output-dir DIR
把生成的文件放进目录DIR。
• -d, --debug
打印调试信息,显示Slice分析器的操作。
• --ice
启用正常情况下保留的标识符前缀Ice。应该只在编译Ice 运行时的源码时使用这个选项。

Slice 编译器允许你编译不止一个源文件,所以你可以同时编译若干Slice 定义:
slice2cpp -I. file1.ice file2.ice file3.ice

2、slice2cpp特定命令行选项:
• --header-ext EXT
把生成的头文件扩展名从缺省的h 变成EXT 所指定的扩展名。
你也可以用全局元数据指令修改头文件扩展名:
[["cpp:header-ext:hpp"]]
// ...
每个源文件中仅能有一个这种指令。如果既在命令行上指定了头文件扩展名,又用元数据指令指定了头文件扩展名,则元数据指令优先。这确保了分别编译的Slice文件能得到正确的头文件扩展名(假定Slice文件包含一个相应的元数据指令)。例如:
// File example.ice
#include
// ...
以如下命令行编译本文件
$ slice2cpp --header-ext=hpp -I/opt/Ice/include example.ice
生成example.hpp, 但是该文件中的 #include 指令包含了Ice/BuiltinSequences.h (而不是Ice/BuiltinSequences.hpp),因为BuiltinSequences.ice包含了元数据指令[[”cpp:header-ext:h”]]。
你通常不需要使用该元数据指令,仅当如下条件时该指令才是必须的:
• 你 #include 自己Slice文件集中的一个Slice文件。
• 被包含的 Slice文件是你要链接的库的一部分。
• 库带有被包含的Slice文件的头文件。
• 库头文件使用了与你自己代码不同的头文件扩展名。
例如,如果库使用.hpp作为头文件扩展名,但你自己的代码使用.h,库的Slice文件应该包含[[”cpp:header-ext:hpp”]]指令。(如果该指令丢失,你要为库的Slice文件加上它。)

• --source-ext EXT
把生成的源文件的文件扩展名从缺省的cpp 变成EXT 所指定的扩展名。

• --add-header HDR[,GUARD]
该选项为生成的源文件开头添加包含指定头文件的指令(先于任何其它包含指令)。如果指定GUARD,包含指令被指定标识符保护。例如: --add-header precompiled.h,__PRECOMPILED_H__
在生成源文件的开始产生上面的指令:
#ifndef __PRECOMPILED_H__
#define __PRECOMPILED_H__
#include
#endif
该选项可以为多个文件重复创建包含指令。如上例所推荐的那样,该选项主要是以编译器的预编译头机制整合生成的代码。

• --include-dir DIR
修改源文件中#include指令,为每个头文件添加DIR目录下的路径名。

• --impl
生成示范性的实现文件,这个选项不会覆盖已有文件。

• --depend
把makefile依赖信息打印到标准输出。指定该选项时不产生代码。输出在包含进makefile之前通常需要过滤;Ice构建系统为此使用了脚本config/makedepend.py。

• --dll-export SYMBOL
使用SYMBOL控制DLL输入、输出。该选项允许你在生成的代码中分别输入、输出全局符号。例如,用下面的命令编译Slice定义:
$ slice2cpp --dll-export ENABLE_DLL x.ice
会在x.h中产生如下额外的代码:
#ifndef ENABLE_DLL
# ifdef ENABLE_DLL_EXPORTS
# define ENABLE_DLL ICE_DECLSPEC_EXPORT
# else
# define ENABLE_DLL ICE_DECLSPEC_IMPORT
# endif
#endif
ICE_DECLSPEC_EXPORT 和 ICE_DECLSPEC_IMPORT 是平台特定的宏。例如,在Windows平台上,它们被分别定义为__declspec(dllexport) 和 __declspec(dllimport);在使用CC 5.5以上版本的Solaris平台上, ICE_DECLSPEC_EXPORT 被定义为 __global,ICE_DECLSPEC_IMPORT 是空。

你在命令行指定的,被生成代码用来输入、输出符号的符号名,在生成的编译单元外面也必须是对代码可见的。实际效果是,如果你要创建包含x.cpp的DLL,也要在DLL之外的编译单元中使用生成类型,要使用-DENABLE_DLL_EXPORTS来编译x.cpp,这样才可以输出相关符号。

• --checksum
为Slice定义生成检查和。

• --stream
为Slice类型生成流助手函数。

3、包含指令
由Slice到C++编译器生成的#include指令,若这种指令生成的语义没有被充分理解的话,会是混乱之源。生成的#include指令受命令行选项-I 和 --include-dir的影响;这些选项在下面详细讨论。--output-dir选项指定编译器将所有生成文件放入一个特定目录,但是不会影响生成代码的内容。

在头文件和源代码中#inlcude指令使用不同的语义生成。
⑴、头文件
大多数情况下,编译器缺省生成适当的#inlcude指令。例如,假定文件A.ice包含B.ice,使用如下的语句:
// A.ice
#include
假定两个文件都在当前工作目录下,我们如下运行编译器:
$ slice2cpp -I. A.ice
生成的文件A.h包含#include指令:
// A.h
#include
如果为C++编译器指定合适的包含路径,编译将会正确进行。
类似地,考虑常见情况,A.ice包含子目录中的B.ice:
// A.ice
#include
假定两个文件都在inc子目录中,我们如下运行编译器:
$ slice2cpp -I. inc/A.ice
编译器缺省输出产生了如下所示A.h中的#inlcude指令:
// A.h
#include
强调一下,这里需要配置C++编译器,以确保编译期间能够找到inc/B.h。

现在,让我们考虑一个更复杂的例子,我们不想要头文件中的#include指令匹配Slice文件。当Slice文件的组织结构不匹配应用程序的C++代码时,这是必须的。这种情况下,用户可能需要从它们创建的目录中重新定位生成的文件,且#include指令必须匹配新结构。

例如,让我们假定B.ice位于子目录slice/inc:
// A.ice
#include
但是,我们不想要slice子目录出现在生成的头文件的#include指令中,因此我们指定额外的编译选项-Islice:
$ slice2cpp -I. -Islice slice/inc/A.ice
生成的代码显示了该额外选项的影响:
// A.h
#include
如你所见,生成头文件中的#inlcude指令受到运行编译器时指定的包含路径的影响。特别是,当包含路径在生成的#inlcude指令中使用了路径名缩写时,更是如此。当编译#include指令时,编译器比较每个包含路径和已包含文件的路径。如果包含路径匹配已包含文件路径的前导部分,编译器就删除#include路径的前导部分。如果匹配一个以上的包含路径,编译器的选择是已包含文件中最短的路径。

例如,假定我们编译A.ice时使用下面选项:
$ slice2cpp -I. -Islice -Islice/inc slice/inc/A.ice
这种情况下,编译器对所有包含目录和已包含的文件slice/inc/B.ice进行比较,生成下面指令:
// A.h
#include
选项-Islice/inc产生最短路径,因此包含文件(slice/inc/B.h)的缺省路径被替换为B.h。

通常,-I选项扮演两种角色:它允许预处理器定位包含的Slice文件,而且它还为你在生成#include指令时提供一定程度的控制。上面最后一个例子中,预处理器使用由-I.选项指定的包含路径定位slice/inc/B.ice。余下的-I选项不能帮助预处理器定位包含文件;它们只是给编译器某些提示。

最终,我们推荐谨慎使用包含路径。如果预处理器能够通过多个包含路径定位一个包含文件,它总是首先使用能够成功定位文件的包含路径。如果你要通过指定额外的-I选项来修改生成的#inlcude指令,你必须确保你包含路径的提示能够匹配预处理器选择的用于定位包含文件的包含路径。一般来说,你不应该指定预处理器通过多种途径定位文件的包含路径。

⑵、源文件
缺省情况下,编译器在源文件中生成的#include指令,仅使用包含文件的基本名称。当源文件和头文件驻留于同一目录时,该行为通常是合适的。
例如,假定A.ice包含子目录中的B.ice,下面列出了A.ice的一段代码:
// A.ice
#include
我们使用下列命令生成源文件:
$ slice2cpp -I. inc/A.ice
经检查,我们看到源文件包含下面#include指令:
// A.cpp
#include
但是,假定我们希望为生成的#include指令强制使用一个特定标准,以便它们兼容我们的C++编译器的现有包含路径设置。可以使用--include-dir选项修改生成的代码。例如,考虑如下的编译命令:
$ slice2cpp --include-dir src -I. inc/A.ice
源文件现在包含下列#include指令:
// A.cpp
#include
通常包含文件中的任何前导路径被丢弃,--include-dir选项值被加入。

4、编译
以$ICE_HOME/demo/book/printer为例,Linux平台上编译运行的过程:
slice2cpp Printer.ice
生成Printer.h,Printer.cpp

编译服务器:
c++ -I. -I$ICE_HOME/include -c Printer.cpp Server.cpp
c++ -o server Printer.o Server.o -L$ICE_HOME/lib -lIce -lIceUtil

编译客户端:
c++ -I. -I$ICE_HOME/include -c Printer.cpp Client.cpp
c++ -o client Printer.o Client.o -L$ICE_HOME/lib -lIce -lIceUtil

在一个控制台窗口中运行:
./server
在另一个控制台窗口中运行:
./client

 

在Windows平台上,过程大体类似,只是可以使用VC++2008 Express的解决方案编译C++代码,更方便。

 

你可能感兴趣的:(ZeroC,Ice)