4 生成(Build )ARM 目的文件
4.1 概述
针对ARMI 的生成(Build)工作总体上比针对WINS 的要困难得多,因此,从一开始就寻找由gcc报告的额外编译错误和报警信息就是再正常不过了。首先这是由于: 在很多情况下gcc 比微软的编译器要严格得多,而且具有一些微妙的差异,它们在第一次的ARMI 生成(Build)过程中就会表现出来。下面几节涉及一些最通用的问题。
4.2 函数导出
当定义导出函数时,gcc 的工具链比WINS工具链要严格得多。从某个DLL 导出一个函数的正确方式如下所示:
在头文件中:
class CMyClass : public CBase
{
IMPORT_C void Function();
}
在CPP 文件中:
EXPORT_C void CMyClass::Function()
{
}
WINS 工具链并不在意是否将EXPORT_C排除在CPP 文件之外了,总之它会导出该函数。然而,gcc工具链需要IMPORT_C和EXPORT_C 之间能完美匹配。如果不能,就不能从DLL 中导出该函数。最终,当试图连接这个DLL 时将导致如“无法找到函数”之类的错误。
4.3 来自PETRAN 的“MyDll.DLL has (un)initialized data”错误
Symbian OS 架构并不允许DLLs 具有数据片(静态数据,已初始化的或未初始化的)。要确定这种数据片的意义是一个棘手问题:
* 该DLL 的所有用户都能共享它吗?
* 是否需要针对每个附着于该DLL 的处理都复制它?
* 在顶层存在着重要的运行时环境以解答任何可能的问题
然而,由于WINS模拟器使用了底层Windows DLL 架构,它能用“copy-on-write”语法提供预处理DLL 数据。这就是为什么在为某台实际Symbian OS 设备生成(built )代码之前,总是查不出问题。
请看本节中的C++代码,它被添加到了文件QSORT.CPP 中。该文件是ESTLIB.DLL的一部分。
// variables
struct div_t uninitialised1; // in .DATA
static struct div_t uninitialised2;// in .BSS
struct div_t initialised1 = {1,1}; // in .DATA
static struct div_t initialised2 = {2,2};// in .DATA
// constants
const struct div_t const1 = {3,3};
const static struct div_t const2 = {4,4};
const TPoint none(-1,-1);
static const TText* plpPduName[12] =
{
_S("Invalid"),
_S("DataFlowOff"),
_S("DataFlowOn"),
_S("ConnectRequest"),
_S("ConnectResponse"),
_S("ChannelClose"),
_S("Info"),
_S("ChannelDisconnect"),
_S("End"),
_S("Delta"),
_S("EndOfWrite"),
_S("PartialWrite")
};
当生成这段代码时,来自PETRAN 的消息看上去如下所示:
PETRAN - PE file preprocessor V01.00 (Build 170)
WARNING: Dll 'ESTLIB[10003B0B].DLL' has initialised data.
WARNING: Dll 'ESTLIB[100002C3].DLL' has uninitialised data.
相关联的.map 文件含有能帮助向下追踪有关源文件的信息。
请到Symbian OS/release/arm4/urel/dllname.map 查找。
搜寻“.data”或“.data”。
在这个范例中,我们发现:
.data 0x10017000 0x200
0x10017000 __data_start__=.
*(.data)
.data 0x10017000 0x40 ../../Symbian
OS/BUILD/STDLIB/BMMP/ESTLIB/ARM4/UREL/ESTLIB.in(QSORT.o)
0x10017000 initialised1
*(.data2)
*(SORT(.data$*))
0x10017040 __data_end__=.
*(.data_cygwin_nocopy)
.bss 0x10018000 0x18
0x10018000 __bss_start__=.
*(.bss)
.bss 0x10018000 0x18 ../../Symbian
OS/BUILD/STDLIB/BMMP/ESTLIB/ARM4/UREL/ESTLIB.in(QSORT.o)
0x10018008 uninitialised1
*(COMMON)
0x10018018 __bss_end__=.
所以,该DLL 有0x18 字节的未初始化数据(.bss)和0x40 字节的已初始化数据(.data),所有这些都来自qsort.o。 initialised1和uninitialised1这两个变量都具有全局范围,所以.map文件按文件名列出了它们(并将两者都放进了已初始化数据中)。 从上面的代码中移去最前面四行,只留下被声明为const 的变量,但却只减少了.bss的0x08字节,及.data 的0x30字节。这里还存在两个问题:
如果C++对象有一个构造函数,那么将其定义为const也没什么用。虽然分配了未初始化数据的8个字节以保持Tpoint对象,但是在构造函数完成之前它并不会成为const。 const TText*声明表示,可能无法改变Ttext 的值,但它也不会使指针成为一个常量。已初始化数据的48个字节是plpPduName 阵列中的12个指针。要使这些指针成为常量,并使其指向的值 也成为常量,该声明中还需要在TText*后加上额外的const。
static const TText* const plpPduName[12] =
{
_S("Invalid"),
_S("DataFlowOff"),
_S("DataFlowOn"),
_S("ConnectRequest"),
_S("ConnectResponse"),
_S("ChannelClose"),
_S("Info"),
_S("ChannelDisconnect"),
_S("End"),
_S("Delta"),
_S("EndOfWrite"), _S("PartialWrite")
};
移去Tpoint全局变量并向plpPduName 阵列添加额外的const,最终将导致移去最后出问题的
.bss和.data。