×
Namespaces

Variants
Actions

如何在Symbian SDK下使用GCCE4

From Nokia Developer Wiki
Jump to: navigation, search
Article Metadata

兼容于
平台:
Symbian

文章
dougcn 在 19 Dec 2008 创建
最后由 hamishwillee 在 08 May 2013 编辑

Contents

为什么要用GCCE 4

Symbian OS v.9.1+ SDK依赖于GCCE CSL Arm Toochain来为真实设备编译代码。然而,随SDK发布的GCCE编译器相当老,3.4.3,最初发布于2004年11月。

尽管在大多数情况下GCCE 3.4.3是一个很好的编译器,不过仍含有一些问题。它也相当慢,在较大的应用程序开发中,你会发现更新的工具链(toolchain)会更好,基于以下理由:

  • GCC 4 编译器明显更快,特别是编译C代码时
  • GCC 4 似乎与优化有关的问题变得更少了
  • GCC 4 生成显著更小的二进制文件(例如,在测试用例中, 整个应用程序的SIS从1.4MB缩小到1MB(Release)).
  • GCC 4 似乎误编译更少了
  • GCC 4 在生成错误及警告信息时更严格,因此导致更好的代码质量。


免责声明

若你打算在你的SDK中使用GCCE 4,注意在功能或正确性方面没有保证。这是一个“尽力服务”的Howto,提供但没有保证。

按照: CodeSourcery:

"You are attempting to do something that we do not recommend you do with the zero-cost downloads. The Lite toolchains are provided at zero cost without support."

若你想安全一些,在开始前做一个备份。

必要的文件

首先,必须下载新版的CSL Arm工具链(Toolchain):CodeSourcery。下载路径在这里。若直接的链接不好使,可以在'Downloads'菜单找到下载。

CodeSourcery生成了许多不同的包。你需要的包是“Sourcery G++ Lite Edition for ARM”,Symbian OS为目标OS的那个。这个包应可以免费获得。

也有以前发行的归档版本可用。通常每年发行两次。常常推荐选择较老的发行版。

版本

所有的包已在Series 60 3rd Edition, Maintenance Release (Symbian 9.1) SDK下测试过:

Package version GCC version Results of tests
2006q1 - 6 4.1.0 Even in simple code, a compilation error with "internal compiler error" message. Recommendation: do not attempt to use it.
2007q1 - 26 4.2.0 After making necessary changes to the SDK, the compilation runs well. HelloWorldBasic can be built and run on device (both Debug and Release modes).
2007q3 - 52 4.2.1 Not tested. Should behave similarly to 4.2.0 and 4.2.3.
2008q1 - 126 4.2.3 After making necessary changes to the SDK, compilation runs well.

HelloWorldBasic can be built and run on device (both Debug and Release modes). This version has been tested on a very large project (over 100,000 lines of code): some changes were necessary, but overall it seemed to work.

2008q3 – 67 4.3.2 After making necessary changes to the SDK, the compilation runs well.

Linker problems with missing "_Unwind_GetTextRelBase". Recommendation: stick to 4.2.3, if possible.

工具链的更换

从CodeSourcery下载想要的包版本之后安装。缺省时将安装到下面的目录:

c:\program files\CodeSourcery\Sourcery G++ Lite\ 

备份旧的工具链

在开始改变工具链前,给老版(3.4.3)做一个备份。万一有问题时,不必重新安装SDK。

随SDK提供的那个版本通常在下面的目录:

C:\Program Files\CSL Arm Toolchain\ 

另创建一个目录,比如C:\Program Files\CSL-Backup\,拷贝旧版目录下的所有内容到备份目录。若发生错误,只需简单删除改变过的C:\Program Files\CSL Arm Toolchain\目录下的内容,把备份的内容拷贝到原来的位置。

拷贝新的工具链

移除C:\Program Files\CSL Arm Toolchain\目录下所有旧的内容,然后从c:\program files\CodeSourcery\Sourcery G++ Lite\拷贝新工具链的内容到旧目录。

这个完成后,新的工具链就装上了。然而要使用新工具链,还需给SDK打补丁。

给SDK打补丁

编辑编译脚本

就目前所致,所有SDK都需要这个补丁。

在SDK的子目录epoc32\tools下有一些文件,指向工具链的准备版本,因此需要打补丁。即:

cl_bpabi.pm
cl_gcce.pm 
ide_cw.pm 
compilation_config/gcce.mk

备份上面的文件到不同的目录(比如,"original_343")。然后编辑所有文件,移除"3.4.3"字符串,用在新工具链使用的那个GCC版本替换它们(例如:"4.2.3")。

备份这些文件到不同的目录——不要备份在同一个目录。IDE中处理这些文件的脚本可能误将备份作为真实的文件。更多信息参看这里的讨论

移除失败断言

这个修补与Series 60 3rd Edition, MR SDK有关。你的SDK或许不同,可能根本不需要这个修补。

在你的SDK的include目录找到文件d32locd.h。备份一下这个文件。然后找到并注释掉下面的行:

__ASSERT_COMPILE(_FOFF(TLocalDriveCaps,iSize)%8 == 0);
__ASSERT_COMPILE(_FOFF(TLocalDriveCapsV3,iFormatInfo.iCapacity) % 8 == 0);

这些行在GCC4下会触发一个编译错误("not a constant", 等)。


更正va_lists

这个修补与Series 60 3rd Edition, MR SDK有关。你的SDK或许不同,可能根本不需要这个修补。

类型
va_list
和相关类型用在处理可变参数长度的函数中(例如,LIBC库中的
printf
函数)。 在新工具链安装后,将有这些必需类型的多个定义,使编译器困惑,每次你用
va_list
和相关类型时都将打出错误信息。 要避免这个,在SDK的include目录找到
gcce\gcce.h
文件。备份一下这个文件。在这个文件中,找到并注释掉这些行:
typedef struct __va_list { void *__ap; } va_list;
#define va_start(ap, parmN) __builtin_va_start(ap.__ap, parmN)
#define va_arg(ap, type) __builtin_va_arg(ap.__ap, type)
#define va_end(ap) __builtin_va_end(ap.__ap)

然后添加下面的行,就在被注释掉的第一行之前:

#include <libc/stdarg.h>

注意由于这个修补,现在事实上你的每个项目都需从标准C库中包含stdarg.h头文件。为克服这个问题,必需在每个你要用新工具链编译的项目的MMP文件中有下面这一行:

SYSTEMINCLUDE     \epoc32\include\libc
因为
stdarg.h
文件从这个目录包含了更多的文件。

从SDK的头文件移除额外的限定符号

这个修补与Series 60 3rd Edition, MR SDK有关。你的SDK或许不同,可能根本不需要这个修补。

若你在用AVKON Query Dialog,在SDK的include目录找到aknquerydialog.h,备份一下这个文件,然后找到下面的行:

CCoeControl* CAknQueryDialog::FindControlOnAnyPageWithControlType(TInt aControlType, TInt* aLineIndex=0, TInt* aPageIndex=0) const;

然后去掉前面的限定符号:

CAknQueryDialog::

结果如下:

CCoeControl* FindControlOnAnyPageWithControlType(TInt aControlType, TInt* aLineIndex=0, TInt* aPageIndex=0) const;

这阻止了一个"extra qualification"编译错误。在GCC 3.4.3不产生这个错误,而GCC 4会检测到。

若使用ImageConversion.h,将碰到一个类似的问题。有问题的行为:

IMPORT_C static CIclRecognizerUtil* CIclRecognizerUtil::NewL();

再次,移除额外的限定符号:

你会在Symbian SDK include文件中发现更多的"extra qualification"错误。这似乎是一个常见问题。下一个这样的错误在mmf\mmfcontrollerpluginresolver.h, 以及coecntrl.h,等等。它们都需要修补一下。应该不会超过4-5个错误。

同样也适用于你自己的代码——不允许额外的限定符号。

解决libsupc++链接错误。只GCCE4.3.2检测

在链接阶段,GCCE 4.3.2工具链会抱怨找不到对<pr>_Unwind_GetTextRelBase</PR>的引用。

这是由于在下面的文件中缺少二进制代码引起的:

CSL Arm Toolchain\lib\libsupc++.a

在4.3.2发行中,这个文件大约7kB。

这个问题有两个可行的解决方案。

简单的方法是用从一些更老的工具链(甚至3.4.3)的原来文件替换这个文件。老文件将有15kB。只需用较旧的文件替换这个较新的文件。

更复杂的办法是自己写丢失的函数,然后把它们添加到你的项目的源代码中。函数实现可以为空。这里这个办法没有测试。

GCCE 4.2.0或4.2.3不检测这个问题。

提供自己的整数除法例程

一些S60第三版SDK遇到下面的问题:系统库不含编译器辅助函数__aeabi_uidiv和__aeabi_idiv的定义。这是一个Symbian的疏忽,它不仅限于SDK,设备也受到影响。

若你从不打算在项目中使用使用整数除法,可完全跳过这个部分。

要找出你的SDK是否含有这个错误,在你的代码的某个地方输入下面的代码片段(不要在不可到达的地方),然后尝试用GCCE DEBUG编译代码:

 #include <e32debug.h>
 
...
void tryDivision ()
{
TInt a, b, c;
a = 10;
b = 5;
c = a / b;
RDebug::Printf("Result of division is %d",c);
}

下一步,在你的代码的某处调用tryDivision()函数,例如在AppUi类的ConstructL方法中。

(这里Printf行是必要的因为否则的话编译器抛出无用的除法代码,而不能检测到可能的错误。)

这段代码在WINSCW下总是可编译的,在GCCE DEBUG下,编译过程可能终止,给出提示信息:"missing reference to __aeabi_idiv"

这种情形下,你使用的SDK有些问题,需执行下面的修改:

在你的项目的src/目录下创建一个新文件,命名为division.c。文件内容如下:

// This code was suggested by Julian Brown from CodeSourcery. It is in public domain.
// Many thanks!
 
#if __GCCE__
#if __SERIES60_30__
extern unsigned int __aeabi_uidivmod(unsigned numerator, unsigned denominator);
int __aeabi_idiv(int numerator, int denominator)
{
int neg_result = (numerator ^ denominator) & 0x80000000;
int result = __aeabi_uidivmod ((numerator < 0) ? -numerator : numerator, (denominator < 0) ? -denominator : denominator);
return neg_result ? -result : result;
}
unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator)
{
return __aeabi_uidivmod (numerator, denominator);
}
#endif // __SERIES60_30__
#endif // __GCCE__

这个文件将被自动加到MMP文件中。按照需要调整预处理块(#if __SERIES60_30__)

项目清理

在命令行(你的项目的group目录)下执行下面的命令:

bldmake clean 
bldmake bldfiles
abld build gcce udeb

这应该清除并重建了你的GCCE makefiles文件(含有旧工具链路径)。

已知移植问题

警告

GCCE4给出比GCCE3更多的警告信息,因此,你会在以前没有警告的代码发现许多警告。然后,这是一个功能而不是bug,大多数警告是有用的。

static initialization fiasco

GCCE4对"static initialization fiasco"比GCCE3更敏感。

"Static initialization fiasco"意味着这样的情形:用另一个静态变量(或常量)初始化某个静态变量(或常量)。应为编译器或系统不保证静态初始化的正确顺序,若你试图用一个尚未初始化的值去初始化某些东西你将碰到错误。

要阅读更多关于"static initialization fiasco"的资料,访问: C++ Faq Lite.

若在你的Symbian代码中有"static initialization fiascos",机会是GCCE 3.4.3不触发任何错误,而GCCE 4.x会。那是因为编译器产生了不同的代码,因此,静态初始化顺序也改变了。

这是一个十分让人沮丧的状态,因为它导致你的应用程序的过早退出。然而static initialization fiasco是一个严重问题,退回使用旧GCCE它也不会消失。机会是,将来你需要用新的工具链编译你的代码,不管怎样你将被迫做些修理。

典型的例子是static const描述符从另一个static const描述符初始化,或者是一个使用静态常量描述符的static const结构,或者是使用资源id的static const结构。解决办法:这个种情形下,有问题的结构只局部使用,在单个类或单个函数中。因此,值得考虑从全局头文件移到那里(单个类或单个函数)。

检测"static initialization fiascos"的方法是用GCCE Debug编译,运行on/device debugging,然后观察错误。panic栈会导航到引起问题的那个结构(点击"static initialization and destruction"行)。

Links

This page was last modified on 8 May 2013, at 03:01.
102 page views in the last 30 days.
×