Mike 发表于 2018-1-3 23:07:59

GCC 交叉编译工具链制作 Add-in 教程

本帖最后由 Mike 于 2018-1-4 01:18 编辑

心血来潮翻译了一下国外大神 GCC 交叉编译环境搭建的帖子。有兴趣的朋友可以看看。翻译时用的MarkDown,不过论坛好像不支持……对排版要求比较高的话可以下载附件中的pdf文档。PS: 我也不知道为什么标题读起来会这么尬…
static/image/hrline/line3.png

使用 GCC 交叉编译制作 Add-inLinux 上多样而自由的编程环境离不开强大的编译器套件 GCC。这篇教程就将展示如何使 GCC 能够支持计算器所使用的 sh3eb-elf 结构文件的编译。其实也没那么难,比军训轻松多了。第一部分:准备工作步骤1:砺兵秣马(依赖安装)我们要安装的不只有 GCC,而是包括两部分:
[*]Binutils(Binary Utilities,二进制工具),用于处理汇编、链接、可执行文件格式,以及与一切编译期之后的东西打交道;
[*]GCC(GNU Compiler Collection,GNU 编译器套件)本身。
在这篇教程中我们使用了 gcc-5.5.0 与 binutils-2.29(【译注】原文写作于2016年9月11日,作者使用了 gcc-6.1.0 与 binutils-2.26;但 gcc-6.x/7.x 在我电脑上死活编译不了,换了 5.5.0 反而好了)。你也可以选用其他版本合适的版本——当然那些老古董的版本还是不要考虑了。OSDev 社区(他们经常使用 GCC 交叉编译)维护了一份编译成功的版本的列表;如果你尝试其他组合成功了,也可以向他们反馈。在操作过程中,你可能因为各种玄学原因失败。在这种情况下,很不幸,你只能下载其他版本然后从头再来(译者:深有体会……)。你可以通过点击以下链接进行下载(【译注】出于国内访问速度考虑,我选了清华大学的 TUNA 镜像源,上面有很多其他的镜像源):
[*]Binutils
[*]GCC
接下来是逃不掉的依赖项。下载时需要注意,名字中有 -dev 后缀的往往提供了库给其他程序调用,而不仅仅是他们的可执行文件。以下列举的是所需的依赖项,括号里的名字在本文写作时尚可用(【译注】原文写于2016年9月11日,事实上我在2018年1月翻译这篇文章时这些名字也还都可用;而且事实上,有些依赖并不是必需的,如果你没有成功安装其中的某个依赖项,仍然可以尝试编译 GCC):
[*]mpfr (libmpfr-dev):可变精度浮点数
[*]mpc(libmpc-dev):可变精度复数
[*]gmp(libgmp-dev):多种精度的算数运算
[*]png(libpng-dev):图像操作
[*]ppl(libppl-dev):多面体(经过神奇的优化)
[*]g++(g++):C++ 编译器
[*]git(git):版本控制工具
总之,下载最新版本。在 Debian 系下(包括 Ubuntu,Mint 等等衍生版),用 apt-get;其他发行版嘛,看你的心情吧(比如 yogurt,yum,pacman,随便哪个,应该不用我来教你了)。步骤 2:勘测地形(环境准备)所有的编译操作都将在你个人目录下的 opt 文件夹内完成(古老而神秘的好习惯),所以你需要先创建这个文件夹,再进入它。打开终端,准备好与它共度一段时光。
$ mkdir -p ~/opt/sh3eb-elf
$ cd ~/opt/sh3eb-elf记一下,我们将要编译的交叉编译器就叫 sh3eb-elf。然后我们在其中建立两个子目录用于编译 binutils 和 GCC。整个的编译过程都会在这两个文件夹中完成。如果你不幸要从头再来,你需要把这两个文件夹删除再重新建立。
$ mkdir build-binutils build-gcc最后,把你下载好的 binutils 和 GCC 的源码解压到 ~/opt/sh3eb-eif 中。完成之后文件夹中应该会有四个文件夹,分别是上面步骤中建立的两个文件夹 build-binutils 和 build-gcc,以及视你下载的版本而定的两个源码文件夹,比如我的就是 binutils-2.29 和 gcc-7.2.0。记得修改下面用到的命令行中的相应部分,如果你选了和我不同的版本。第二部分:直抵前线步骤 3:兵戎初接(编译 Binutils)binutils 的编译过程相当经典——先 configure 再 make。注意一下(后面的教程中也一样),如果你给 make 传递了 -j 参数(不要忘了在后面跟一个数字,代表线程数,例如 -j8),就可以获得多线程的加速(【译注】线程数大致可以选 CPU 核心数的 2~4 倍)。
$ cd build-binutils
$ ../binutils-2.29/configure --target=sh3eb-elf --prefix="$HOME/opt/sh3eb-elf/" --disable-nls --disable-werror你可能会注意到 --target 参数,顾名思义,它制定了目标架构(我们的计算器用的是一个 SuperH-3 处理器)。你大可不必担心 SH4 ,因为 SH4 兼容 SH3(反之则不然)。--disable-nls 选项强制编译器使用英语(这也是一个古已有之的好习惯),而 --disable-werror 选项关闭了编译器的 -Werror 选项,反正你也不会去用。然后我们就可以用 make 来编译和安装了。
$ make
$ sudo make install如果你遇到了编译错误,检查一下你的依赖项以及它们对应的头文件是否被正确安装了。如果还是不行,就只能回到步骤 1 中重新选择 binutils 和 GCC 的版本了。步骤 4:装甲压境(编译 GCC)现在你已经装好了 Binutils 了,它的可执行文件应该会出现在 ~/opt/sh3eb-elf/bin 下。如果我们想要使用它们,就需要将这个目录加入系统的环境变量 PATH(运行命令时会从其记录的目录中寻找程序)。下面这个命令可以帮你临时完成这个工作。
$ export PATH=$PATH:$HOME/opt/sh3eb-elf/bin如果你需要使其永久生效,则应将上述命令加入你的 Shell 配置文件如 ~/.bash_profile。
$ echo 'export PATH=$PATH:"$HOME/opt/sh3eb-elf/bin"' >> ~/.bash_profile
$ source ~/.bash_profile接下来的工作和上一步骤差不多。我们首先运行配置脚本,然后编译。你可以用 --enable-languages 选项来指定编译你需要的语言的编译器。一般来讲,C 和 C++ 足够了,但是如果你打算用 Ada,Go 或者 Fortran 的话也可以把它们加入进来。不过不要贪杯,除非你可以忍受漫长的编译时间(译者:何况连能用的库都没有……)。
$ cd ~/opt/sh3eb-elf/build-gcc
$ ../gcc-5.5.0/configure --target=sh3eb-elf --prefix="$HOME/opt/sh3eb-elf" --disable-nls --enable-languages=c,c++ --without-headers选项的组织和之前类似。如果配置因为丢失头文件而失败,安装好它们之后重新运行配置脚本。如果一切顺利,那么你就已经为这场战役中最漫长的部分做好了准备(别忘了用 -j 选项来指定线程数)。
$ make all-gcc
$ sudo make install-gcc如果你遇到了你解决不了的编译错误……抱歉,只能从步骤 1 重来了。步骤 5:空中支援(安装 libgcc)最后的一大任务是编译 libgcc,你需要用它来编译你的程序。
$ make all-target-libgcc
$ sudo make install-target-libgcc如果编译又失败了……抱歉,还是只能从步骤 1 重新开始(都到了这一步,确实让人沮丧)。祝贺!你的编译器已经安装完成,可以使用了。你可以运行一些命令来检查一下它……
$ sh3eb-elf-as --version
GNU assembler (GNU Binutils) 2.29 [...]
$ sh3eb-elf-gcc --version
sh3eb-elf-gcc (GCC) 5.5.0 [...]
$ sh3eb-elf-gcc -print-file-name=libgcc.a
/Users/mike/opt/sh3eb-elf/lib/gcc/sh3eb-elf/5.5.0/libgcc.a如果你得到了类似的输出,那么你就可以……嗯,继续看下去了!这教程还没有结束。第三部分:占地为王步骤 6:全副武装(Add-in 包装器)你可能会对我所谈论的 ELF 文件格式感到困惑,因为计算器上只能使用 g1a……不过到现在为止,g1a 还只是 CASIO 专有的格式,GCC 对如何生成它一无所知。所以,我们要使用包装器(Wrapper)来将 ELF 文件打包为 g1a 格式文件。我们已经将它上传到一个 Git 仓库。你可以使用以下命令来将它安装到你的编译器所在目录(【译注】可能会有权限问题,需要使用 sudo 来运行命令)。
$ cd ~/opt/sh3eb-elf
$ git clone "https://Lephenixnoir""@""bitbucket.org/Lephenixnoir/add-in-wrapper.git"
$ cd add-in-wrapper
$ make
$ cp build/g1a-wrapper ~/opt/sh3eb-elf/bin你现在已经可以给计算器开发程序了!让我们一起来看看具体应该怎么做……步骤 7:号令天下(项目环境)我们将会创建一个模板工程来供你重复使用。因为这些与 GCC 的编译过程无关,所以我建议你在别的文件夹里面做这事(比方说 ~/my-awesome-project 就很棒)。不论如何,你都可以暂时关掉终端了。我假定你已经有一定的有 C 语言程序设计的经验,所以我不会再教你如何组织一个项目……你只需要这些文件就可以了(译者:下载速度感人……)。你一定已经迫不及待地想用你的新工具来编译它了。一个不错的选择是(【译注】当然用 CMake 什么的就更舒服了,过几天我可能会写一下怎么操作)……
$ sh3eb-elf-gcc -m3 -mb -ffreestanding -nostdlib -T addin.ld crt0.s addin.c -o addin.elf -I include -lgcc -L .这里对这些选项做些说明:
[*]-m3 和 -mb 选项表明我们想要生成 SH3 上的二进制(SH3 还是有很多变种的,所以我们仍然需要指定一下),并使用大端模式(这和多字节变量每个字节在内存中的顺序相关);
[*]ffreestanding 选项要求编译后的代码不会依赖任何特定的操作系统(而是由 GCC 提供一些东西);
[*]-I 是包含目录标记(我们有一些头文件在 include 目录中);
[*]-nostdlib 表示我们不会使用标准库(其实它已经被包含在 libfx.a 中了);
[*]-O2 是优化选项(【译注】运行速度能快很多)。
这些编译选项都是在编译期使用的。由于我们的项目比较简单,所以我们一次性将它编译完成。如果你有一个大项目,最好逐个文件编译完成后再进行链接。下面这些是链接选项:
[*]-T addin.ld 选项告诉编译器,链接时需要参考 addin.ld 文件中编写的规则;
[*]-L . 和 lfx 选项表明我们需要链接当前目录中的 libfx.a 文件;
[*]-lgcc 表示我们将要使用 libgcc(你总是需要它的!);
[*]当然 -o addin.elf 表明了我们想要的输出文件。
注意文件夹中的 crt0.s 文件是另一种源代码文件,它包含了基础代码。别忘了把它也编译了(这里我们把它和 addin.c 同时编译了)。编译器输出的文件是用于 SH3 架构的 ELF 文件(经典的 Linux 格式),这正是我们一开始所期望的。步骤 8:强强联合(g1a 格式文件的生成)使用 ELF 格式的文件有很多好处,不过我们想要的只是纯二进制文件。为此,我们将使用 Binutils 中的一个工具 objcopy 来改变格式。简而言之,就是要将 ELF 删除而只留下纯的二进制部分。
$ sh3eb-elf-objcopy -R .comment -R .bss -O binary addin.elf addin.bin现在我们只需要给二进制添加 add-in 文件头就可以了——这也正是 Add-in Wrapper 将要做的。你可以使用 g1a-wrapper --help 命令来查看这个工具所支持的一些选项,不过现在我们只是简单地把二进制包装一下再加个图标。
$ g1a-wrapper addin.bin -o addin.g1a -i icon.bmp大功告成!现在你只要把这个 add-in 传送到你的计算器上就好了……这里有一些好用的祖传工具可以使用:
[*]Cakeisalie5 的杰出工具 P7;
[*]Nessotrin 的 CasioUSB。
感谢阅读。https://www.cncalc.org/static/image/hrline/line3.png

原文链接:http://www.planet-casio.com/Fr/f ... ompilateur-gcc.html

ZephRay 发表于 2018-1-9 05:45:20

这样做完的话,是否意味着可以使用一些新的特性了?(比如lambda表达式?)

Mike 发表于 2018-1-9 12:10:07

ZephRay 发表于 2018-1-9 05:45
这样做完的话,是否意味着可以使用一些新的特性了?(比如lambda表达式?)

是的…但是现在的主要问题是没有一个正经的标准库可以用。_(:з」∠)_

ZephRay 发表于 2018-1-10 06:26:47

Mike 发表于 2018-1-8 23:10
是的…但是现在的主要问题是没有一个正经的标准库可以用。_(:з」∠)_

所以说还是需要一个靠谱的newlib移植……顺便问下,Addin一般可以使用到多大的RAM呢?

Mike 发表于 2018-1-10 10:53:38

ZephRay 发表于 2018-1-10 06:26
所以说还是需要一个靠谱的newlib移植……顺便问下,Addin一般可以使用到多大的RAM呢?

9860的话,我看原文提供的project的ld文件里面给的是64k,并且认为这是“pretty safe guess”。所以应该至少有64k可以用(虽然还是少的可怜)。CG20的话,这里有讨论:https://www.cemetech.net/forum/viewtopic.php?t=9334
另外关于标准库,CG20上好像有一个libfxcg,C标准库部分挺完整的。不过我链接的时候好像只要有浮点数就会导致链接器段错误……不知道是不是环境没有配好。9860的标准库嘛,貌似原文作者写过一点,不过功能还是很弱。

Mike 发表于 2018-1-10 12:21:00

ZephRay 发表于 2018-1-10 06:26
所以说还是需要一个靠谱的newlib移植……顺便问下,Addin一般可以使用到多大的RAM呢?

ld挂掉的问题刚刚解决了,方法是换一个binutils版本_(:з」∠)_,换成2.26.1之后就好了。
页: [1]
查看完整版本: GCC 交叉编译工具链制作 Add-in 教程