gcc4.6.1编译问题总结以及modules的使用
前言
在MIT6.828操作系统工程Lab1-Booting a PC实验报告中,出现了高版本gcc(> 7.1.1-3)编译出的JOS内核不能使用的问题(Triple Fault)。此外,gcc无法编译生成32位的JOS内核。因此需要手动降级到低版本并且开启gcc-multilib。
根据arch-dev-public,gcc-multilib已经被合并至了core/gcc之中。当然仍然可以通过Arch Linux Archive获取旧版本的gcc-multilib。
然而Arch是一个崇尚“Modernity”的发行版(参考Arch之道):
Arch尽全力保持软件处于最新的稳定版本,只要不出现系统软件包破损,都尽量用最新版本。
Arch Linux strives to maintain the latest stable release versions of its software as long as systemic package breakage can be reasonably avoided.
综合arch-dev-public对于gcc所做的改动和Arch之道,保持系统gcc为旧版本的gcc-multilib显然不是一个“优雅”的做法。最终,我决定按照6.828 Lab Tools的指导,手动编译gcc 4.6.1作为JOS内核的交叉编译工具链。
问题
编译gcc 4.6.1中遇到的问题以及解决方案总结如下:
- 网站上给出的部分软件包的下载链接已经过期。
- 网站上的教程默认将工具链安装在了/usr/local/下,这里为了管理上的方便没有采用默认的做法,而是将gcc直接安装在了home目录下(通过configure时的–prefix参数指定)。
- 接2,使用./comfigure –help获取帮助。在某些包configure时,需要使用如–with-mpc=… –with-gmp=…等参数来告知相应包的位置。
- 由于texinfo版本过高导致低版本的gcc不能正确编译,需要在configure时加上MAKEINFO=missing(当然,你也可以降级texinfo)。
- gcc 4.6.1的源码存在一个作用域错误问题。找到gcc/gengtype.c的write_field_root函数,将struct pair new;移动到函数的起始位置。
- 编译gcc时出现了libmpc.so.2库找不到的问题。需要修改环境变量LD_LIBRARY_PATH并添加相应的目录,或者也可以在configure的时候用参数–libdir指定库位置。
- gcc 4.6.1的源码存在一个数组访问越界错误,具体参考这里。
Modules
包管理软件与环境变量
提一个简单的问题,当我们使用包管理软件(例如pacman)安装某个包(例如unzip)之后,在终端中输入unzip …即可解压zip文件。那么包管理软件究竟做了什么呢?
如果是从yaourt安装AUR的包,情况又会发生什么变化呢?
包管理软件主要管理各种包以及处理包与包之间的依赖问题。在安装包的时候,包管理软件从镜像源获取包,将包解压并且将内容复制到系统对应的位置。
诸如yaourt这样的包管理软件使用ABS(Arch Build System),根据pkgbuild文件的指导在本机下载源码、编译并打包,并且将生成的包安装到系统中。
以unzip-natspec为例(这是一个可以识别zip编码格式的unzip版本),我们使用pacman查看包的内容以及对应的位置:
1 | pacman -Ql unzip-natspec |
可以看出unzip被放在/usr/bin目录下。可是为什么我们可以直接在终端中输入unzip …执行解压的命令而不是输入/usr/bin/unzip …呢?这就涉及到了环境变量PATH。
环境变量是一个动态命名的值,用来影响计算机上进程运行的行为。PATH设置了一组包含可执行文件的目录。在输入unzip的时候,终端默认会在PATH所包含的目录中寻找unzip,如果找到了就执行它。我们使用echo命令打印当前终端的环境变量。
1 | echo $PATH |
6.828网站上默认将工具链安装在了/usr/local目录下,而/usr/local/bin是位于环境变量PATH中的。
因此,我们的qemu以及make可以直接找到编译好的工具链并调用。
现在,我们将工具链安装在了一个不属于PATH的目录中。对于这种情况,我们必须使用某种方式(如shell脚本),将相应目录添加PATH中。
对于我们编译的工具链,还需要设置环境变量LD_LIBRARY_PATH才可正常工作。LD_LIBRARY_PATH涉及linux的动态链接库(共享库),可以自行去搜索相关知识。
当我们安装的程序变多,脚本也会越变越多,管理诸如PATH的环境变量也变得不方便。
我们的jos内核使用的工具链加上了“i386-jos-elf”的前缀。若没有该前缀,添加环境变量后,终端会优先使用gcc 4.6.1作为默认的gcc,这显然不是我们期望的结果。
因此,我们可能还需要写另一个脚本,将相应的目录从PATH中移除。
此外,根据脚本的是否在终端启动时被执行,还可能出现不同终端环境不同的问题。
那么,有没有一种方法可以快速方便的管理不同软件以及他们所需要的环境变量呢?Modules正是一个可行的方法。
简介
Modules(Environment Modules)通过modulefile动态地改变用户环境。可以在Arch中安装env-modules(AUR)以使用Modules。
安装完毕后,需要编辑终端的配置文件来启用Modules。Modules的shell初始化放在/etc/modules/init文件夹下。
Modules使用Tcl作为脚本语言,编写modulefile时可以直接man modulefile获取帮助。
实例
给出管理jos工具链的modulefile,文件放置在/etc/modules/modulefiles文件夹下。使用module load jos加载环境,module unload jos取消环境。modulefile中的prepend-path扩展了环境变量PATH以及LD_LIBRARY_PATH。在调用unload的时候prepeng-path会自动被替换成remove-path。
jos1
2
3
4
5
6
7
8
9
10
11#%Module1.0
##
## modulefile
##
proc ModulesHelp {} {
puts stderr "Adds cross compile toolchain(gcc 4.6.1 i386) for MIT jos to user environment"
}
module-whatis "adds cross compile toolchain(gcc 4.6.1 i386) for MIT jos to user environment"
set root_dir /home/chenzhihao/6.828/gcc
prepend-path PATH $root_dir/bin
prepend-path LD_LIBRARY_PATH $root_dir/lib