当前位置:首页 » 编程软件 » newlib编译安装使用

newlib编译安装使用

发布时间: 2022-06-30 19:57:35

1. linux嵌入式交叉编译工具链问题 浅谈

简介

交叉编译工具链是一个由编译器、连接器和解释器组成的综合开发环境,交叉编译工具链主要由binutils、gcc和glibc 3个部分组成。有时出于减小libc库大小的考虑,也可以用别的c库来代替glibc,例如uClibc、dietlibc和newlib。交叉编译工具链主要包括针对目标系统的编译器gcc、目标系统的二进制工具binutils、目标系统的标准c库glibc和目标系统的Linux内核头文件。第一个步骤就是确定目标平台。每个目标平台都有一个明确的格式,这些信息用于在构建过程中识别要使用的不同工具的正确版本。因此,当在一个特定目标机下运行GCC时,GCC便在目录路径中查找包含该目标规范的应用程序路径。GNU的目标规范格式为CPU-PLATFORM-OS。例如,建立基于ARM平台的交叉工具链,目标平台名为arm-linux-gnu。

交叉编译工具链的制作方法

  1. 分步编译和安装交叉编译工具链所需要的库和源代码,最终生成交叉编译工具链。

  2. 通过Crosstool脚本工具来实现一次编译生成交叉编译工具链。

  3. 直接通过网上(ftp.arm.kernel.org.uk)下载已经制作好的交叉编译工具链。

方法1相对比较困难,适合想深入学习构建交叉工具链的读者。如果只是想使用交叉工具链,建议使用方法2或方法3构建交叉工具链。方法3的优点不用多说,当然是简单省事,但与此同时该方法有一定的弊端就是局限性太大,因为毕竟是别人构建好的,也就是固定的没有灵活性,所以构建所用的库以及编译器的版本也许并不适合你要编译的程序,同时也许会在使用时出现许多莫名的错误,建议你慎用此方法。


方法1:分步构建交叉编译工具链


  1. 下载所需的源代码包

  2. 建立工作目录

  3. 建立环境变量

  4. 编译、安装Binutils

  5. 获取内核头文件

  6. 编译gcc的辅助编译器

  7. 编译生成glibc库

  8. 编译生成完整的gcc

由于在问答中的篇幅,我不能细述具体的步骤,兴趣的同学请自行阅读开源共创协议的《Linux from scratch》,网址是:linuxfromscratch dot org


方法2:用Crosstool工具构建交叉工具链(推荐)

Crosstool是一组脚本工具集,可构建和测试不同版本的gcc和glibc,用于那些支持glibc的体系结构。它也是一个开源项目,下载地址是kegel dot com/crosstool。用Crosstool构建交叉工具链要比上述的分步编译容易得多,并且也方便许多,对于仅仅为了工作需要构建交叉编译工具链的你,建议使用此方法。

运行which makeinfo,如果不能找见该命令,在解压texinfo-4.11.tar.bz2,进入texinfo-4.11目录,执行./configure&&make&&make install完成makeinfo工具的安装

  • 准备文件:

下载所需资源文件linux-2.4.20.tar.gz、binutils-2.19.tar.bz2、gcc-3.3.6.tar.gz、glibc- 2.3.2.tar.gz、glibc-linuxthreads-2.3.2.tar.gz和gdb-6.5.tar.bz2。然后将这些工具包文件放在新建的$HOME/downloads目录下,最后在$HOME/目录下解压crosstool-0.43.tar.gz,命

令如下:
#cd$HOME/
#tar–xvzfcrosstool-0.43.tar.gz
  • 建立脚本文件

接着需要建立自己的编译脚本,起名为arm.sh,为了简化编写arm.sh,寻找一个最接近的脚本文件demo-arm.sh作为模板,然后将该脚本的内容复制到arm.sh,修改arm.sh脚本,具体操作如下:

# cd crosstool-0.43

# cp demo-arm.sh arm.sh

# vi arm.sh

修改后的arm.sh脚本内容如下:

#!/bin/sh
set-ex
TARBALLS_DIR=$HOME/downloads#定义工具链源码所存放位置。
RESULT_TOP=$HOME/arm-bin#定义工具链的安装目录
exportTARBALLS_DIRRESULT_TOP
GCC_LANGUAGES="c,c++"#定义支持C,C++语言
exportGCC_LANGUAGES
#创建/opt/crosstool目录
mkdir-p$RESULT_TOP
#编译工具链,该过程需要数小时完成。
eval'catarm.datgcc-3.3.6-glibc-2.3.2.dat'shall.sh--notest
echoDone.
  • 建立配置文件

在arm.sh脚本文件中需要注意arm-xscale.dat和gcc-3.3.6-glibc-2.3.2.dat两个文件,这两个文件是作为Crosstool的编译的配置文件。其中arm.dat文件内容如下,主要用于定义配置文件、定义生成编译工具链的名称以及定义编译选项等。

KERNELCONFIG='pwd'/arm.config#内核的配置
TARGET=arm-linux#编译生成的工具链名称
TARGET_CFLAGS="-O"#编译选项


gcc-3.3.6-glibc-2.3.2.dat文件内容如下,该文件主要定义编译过程中所需要的库以及它定义的版本,如果在编译过程中发现有些库不存在时,Crosstool会自动在相关网站上下载,该工具在这点上相对比较智能,也非常有用。

BINUTILS_DIR=binutils-2.19
GCC_DIR=gcc-3.3.6
GLIBC_DIR=glibc-2.3.2
LINUX_DIR=linux-2.6.10-8(根据实际情况填写)
GDB_DIR=gdb-6.5
  • 执行脚本

将Crosstool的脚本文件和配置文件准备好之后,开始执行arm.sh脚本来编译交叉编译工具。具体执行命令如下:

#cdcrosstool-0.43
#./arm.sh

经过数小时的漫长编译之后,会在/opt/crosstool目录下生成新的交叉编译工具,其中包括以下内容:

arm-linux-addr2linearm-linux-g++arm-linux-ldarm-linux-size
arm-linux-ararm-linux-gccarm-linux-nmarm-linux-strings
arm-linux-asarm-linux-gcc-3.3.6arm-linux-objarm-linux-strip
arm-linux-c++arm-linux-gccbugarm-linux-objmpfix-embedded-paths
arm-linux-c++filtarm-linux-gcovarm-linux-ranlib
arm-linux-cpparm-linux-gprofarm-linux-readelf
  • 添加环境变量

然后将生成的编译工具链路径添加到环境变量PATH上去,添加的方法是在系统/etc/ bashrc文件的最后添加下面一行,在bashrc文件中添加环境变量

export PATH=/home/jiabing/gcc-3.3.6-glibc-2.3.2/arm-linux-bin/bin:$PATH

至此,arm-linux下的交叉编译工具链已经完成,现在就可以使用arm-linux-gcc来生成试验箱上的程序了!












2. 交叉编译的准备素材

怎么说呢,你先得准备好主机平台,对我们这个项目来说,我们建议采用x86 Linux做主机平台,因为这样需要的设置工作最少。当然你也可以使用你所喜欢的平台或你所能得到的平台,其中的区别在于你可能必须做更多的设置工作,当然也有这种可能,就是你所选择的主机平台根本不能生成适用于目标平台的正确的交叉编译器。
对于交叉编译器,可以自己生成,也可以从网上下载。区别在于从网上下载非常简单方便,但也许你找不到适合你所选择的平台的。而自己生成交叉编译器,有时会遇到很多挫折,但这的确是个有趣的值得怀念的经历。
如果你想自己生成交叉编译器,那你必须先准备下面这些东西:
1、磁盘空间。至少要500M左右的空间,如果想一气呵成的话,那就要900M-1G的空间。
2、各种源代码。你至少要准备binutils-2.11.2、gcc-2.95.3、linux-2.4.6、newlib-1.8.2或glibc-2.2.2的源代码。
如果你所使用的主机平台不是运行的linux,那你还必须注意以下这些问题:
1、GNU bash必须是默认shell,所以你也许得把/bin/sh改成bash。
2、你要确认已经安装了GNU bison,因为这些软件同样使用了bison扩展。
3、GNU gmake最好是系统默认的make,因为这些软件都使用了gmake扩展,如果不是,在需要make时,记得使用gmake。
4、如果你想生成交叉glibc,则GNU gsed必须是默认sed,因为glibc会用到gsed的扩展。
5、如果你想生成交叉glibc,那还必须准备glibc-linuxthreads-2.2.2的源代码。
6、确认正确的路径搜索顺序,最好让GNU软件首先被执行。

3. 如何使用clang+llvm+binutils+newlib+gdb搭建交叉编译环境

1,Build llvm/clang/lldb/lld 3.5.0等组件

1.0 准备:

至少需要从llvm.org下载llvm, cfe, lldb, compiler-rt,lld等3.5.0版本的代码。

$tar xf llvm-3.5.0.src.tar.gz

$cd llvm-3.5.0.src

$mkdir -p tools/clang
$mkdir -p tools/clang/tools/extra
$mkdir -p tools/lld
$mkdir -p projects/compiler-rt

$tar xf cfe-3.5.0.src.tar.xz -C tools/clang --strip-components=1
$tar xf compiler-rt-3.5.0.src.tar.xz -C projects/compiler-rt --strip-components=1
$tar xf lldb-3.5.0.src.tar.xz -C tools/clang/tools/extra --strip-components=1
$tar xf lld-3.5.0.src.tar.xz -C tools/lld --strip-components=1
1.1 【可选】使用clang --stdlib=libc++时,自动添加-lc++abi。

libc++组件可以使用gcc libstdc++的supc++ ABI,也可以使用c++abi,cxxrt等,实际上自动添加-lc++abi是不必要的,这里这么处理,主要是为了方便起见。实际上完全可以在“clang++ -stdlib=libc++”时再手工添加-lc++abi给链接器。

这里涉及到链接时DSO隐式还是显式的问题,早些时候ld在链接库时会自动引入由库引入的依赖动态库,后来因为这个行为的不可控性,所以ld链接器的行为做了修改,需要显式的写明所有需要链接的动态库,才会有手工添加-lc++abi这种情况出现。

--- llvm-3.0.src/tools/clang/lib/Driver/ToolChain.cpp 2012-03-26 18:49:06.663029075 +0800
+++ llvm-3.0.srcn/tools/clang/lib/Driver/ToolChain.cpp 2012-03-26 19:36:04.260071355 +0800
@@ -251,6 +251,7 @@
switch (Type) {
case ToolChain::CST_Libcxx:
CmdArgs.push_back("-lc++");
+ CmdArgs.push_back("-lc++abi");
break;

case ToolChain::CST_Libstdcxx:
1.2 【必要】给clang++添加-fnolibgcc开关。

这个开关主要用来控制是否连接到libgcc或者libunwind。

注:libgcc不等于libunwind。libgcc_eh以及supc++的一部分跟libunwind功能相当。

注:libgcc_s和compiler_rt的一部分相当。

这个补丁是必要的, 不会对clang的正常使用造成任何影响 ,只有在使用“-fnolibgcc"参数时才会起作用。

之所以进行了很多unwind的引入,主要是为了避免不必要的符号缺失麻烦,这里的处理相对来说是干净的,通过as-needed规避了不必要的引入。

--- llvm-static-3.5.0.bak/tools/clang/lib/Driver/Tools.cpp 2014-09-10 13:46:02.581543888 +0800
+++ llvm-static-3.5.0/tools/clang/lib/Driver/Tools.cpp 2014-09-10 16:03:37.559019321 +0800
@@ -2060,9 +2060,15 @@
".a");

CmdArgs.push_back(Args.MakeArgString(LibClangRT));
- CmdArgs.push_back("-lgcc_s");
- if (TC.getDriver().CCCIsCXX())
- CmdArgs.push_back("-lgcc_eh");
+ if (Args.hasArg(options::OPT_fnolibgcc)) {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lunwind");
+ CmdArgs.push_back("--no-as-needed");
+ } else {
+ CmdArgs.push_back("-lgcc_s");
+ if (TC.getDriver().CCCIsCXX())
+ CmdArgs.push_back("-lgcc_eh");
+ }
}

static void addProfileRT(
@@ -7150,24 +7156,50 @@
bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android;
bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) ||
Args.hasArg(options::OPT_static);
+
+
+
if (!D.CCCIsCXX())
- CmdArgs.push_back("-lgcc");
+ if (Args.hasArg(options::OPT_fnolibgcc)) {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lunwind");
+ CmdArgs.push_back("--no-as-needed");
+ } else
+ CmdArgs.push_back("-lgcc");

if (StaticLibgcc || isAndroid) {
if (D.CCCIsCXX())
- CmdArgs.push_back("-lgcc");
+ if (Args.hasArg(options::OPT_fnolibgcc)) {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lunwind");
+ CmdArgs.push_back("--no-as-needed");
+ } else
+ CmdArgs.push_back("-lgcc");
} else {
if (!D.CCCIsCXX())
CmdArgs.push_back("--as-needed");
- CmdArgs.push_back("-lgcc_s");
+ if (Args.hasArg(options::OPT_fnolibgcc))
+ CmdArgs.push_back("-lunwind");
+ else
+ CmdArgs.push_back("-lgcc_s");
if (!D.CCCIsCXX())
CmdArgs.push_back("--no-as-needed");
}

if (StaticLibgcc && !isAndroid)
- CmdArgs.push_back("-lgcc_eh");
+ if (Args.hasArg(options::OPT_fnolibgcc)) {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lunwind");
+ CmdArgs.push_back("--no-as-needed");
+ } else
+ CmdArgs.push_back("-lgcc_eh");
else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX())
- CmdArgs.push_back("-lgcc");
+ if (Args.hasArg(options::OPT_fnolibgcc)) {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lunwind");
+ CmdArgs.push_back("--no-as-needed");
+ } else
+ CmdArgs.push_back("-lgcc");

// According to Android ABI, we have to link with libdl if we are
// linking with non-static libgcc.
--- llvm-static-3.5.0.bak/tools/clang/include/clang/Driver/Options.td 2014-08-07 12:51:51.000000000 +0800
+++ llvm-static-3.5.0/tools/clang/include/clang/Driver/Options.td 2014-09-10 13:36:34.598511176 +0800
@@ -788,6 +788,7 @@
def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>;
def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>;
def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group<f_Group>, Flags<[CC1Option]>;
+def fnolibgcc : Flag<["-"], "fnolibgcc">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>;
def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>;
def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>;
def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">;
1.3 llvm的其他补丁。

llvm/clang将gcc toolchain的路径hard code在代码中,请查阅tools/clang/lib/Driver/ToolChains.cpp。

找到x86_64-redhat-linux之类的字符串。

如果没有你系统特有的gcc tripple string,请自行添加。

这个tripple string主要是给llvm/clang搜索gcc头文件等使用的,不影响本文要构建的toolchain

1.4 构建clang/llvm/lldb

本文使用ninja。顺便说一下,llvm支持configure和cmake两种构建方式。可能是因为工程太大,这两种构建方式的工程文件都有各种缺陷(主要表现在开关选项上,比如configure有,但是cmake却没有等)。llvm-3.4.1就是因为cmake工程文件的错误而导致了3.4.2版本的发布。

综合而言,cmake+ninja的方式是目前最快的构建方式之一,可以将构建时间缩短一半以上。

mkdir build
cd build

cmake \
-G Ninja \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_BUILD_TYPE="Release" \
-DCMAKE_CXX_FLAGS="-std=c++11" \
-DBUILD_SHARED_LIBS=OFF \
-DLLVM_ENABLE_PIC=ON \
-DLLVM_TARGETS_TO_BUILD="all" \
-DCLANG_VENDOR="MyOS" ..

ninja

ninja install
如果系统原来就有clang/clang++的可用版本,可以添加:

-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
这样就会使用系统的clang++来构建llvm/clang

2,测试clang/clang++。

自己找几个简单的c/cpp/objc等编译测试一下即可。完整测试可以在构建时作ninja check-all

3,libunwind/libc++/libc++abi,一套不依赖libgcc, libstdc++的c++运行库。

3.1 从https://github.com/pathscale/libunwind 获取代码。

libunwind有很多个实现,比如gnu的libunwind, path64的libunwind,还有libcxxabi自带的Unwinder.

这里作下说明:

1),gnu的libunwind会有符号缺失和冲突。

2),libcxxabi自带的Unwinder是给mac和ios用的,也就是只能在darwin体系构建。目前Linux的实现仍然不全,等linux实现完整了或许就不再需要path64的unwind实现了。

暂时建议使用pathscale的unwind实现。

mkdir -p build
cd build
cmake -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_C_FLAGS="-m64" ..
ninja

mkdir -p /usr/lib
cp src/libunwind.so /usr/lib
cp src/libunwind.a /usr/lib
3.2 第一次构建libcxx.

必须先构建一次libcxx,以便后面构建libcxxabi。这里构建的libcxx实际上是使用gcc的libgcc/stdc++/supc++的。

打上这个补丁来禁止libgcc的引入:

diff -Nur libcxx/cmake/config-ix.cmake libcxxn/cmake/config-ix.cmake
--- libcxx/cmake/config-ix.cmake 2014-06-25 06:57:50.000000000 +0800
+++ libcxxn/cmake/config-ix.cmake 2014-06-25 09:05:24.980350544 +0800
@@ -28,5 +28,4 @@
check_library_exists(c printf "" LIBCXX_HAS_C_LIB)
check_library_exists(m ccos "" LIBCXX_HAS_M_LIB)
check_library_exists(rt clock_gettime "" LIBCXX_HAS_RT_LIB)
-check_library_exists(gcc_s __gcc_personality_v0 "" LIBCXX_HAS_GCC_S_LIB)
编译安装:

mkdir build
cd build
cmake \
-G Ninja \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
..
ninja
ninja install
3.3,测试第一次构建的libcxx。

使用"clang++ -stdlib=libc++ -o test test.cpp -lstdc++"编译简单c++代码,检查是否出错。(如果前面构建clang是已经apply了c++abi的链接补丁,这里会出现找不到c++abi的情况,跳过即可)

使用"ldd test"查看test二进制动态库使用情况。可以发现,test依赖于libgcc_s/libc++/libstdc++。(多少有些不爽了吧?使用了libc++居然还要依赖libstdc++?)

4. 建立交叉编译环境后root无法登陆linux。

你这是建立交叉编译?
只看见你复制了一堆软件包到tmp,然后解压,然后安装了个编译器.貌似也没安装,没见编译和安装啊
你既然用tar的-v参数了,就要看他的信息啊.他报什么错了么?
我用的c到arm的交叉编译环境搭建方法,你参考一下
用的软件包:
linux-2.6.9.tar.gz
binutils-2.15.tar.gz
gcc-core-3.4.2.tar.bz2
gcc-g++3.4.2.tar.bz2
glibc-2.3.5.tar.gz
glibc-linuxthreads-2.3.5.tar.bz2
东西准备好了就开始搭建
[root@binnary ~ ]# mkdir /armtools
[root@binnary ~ ]#mkdir –p ~/tars/sourcedir
[root@binnary ~ ]#mkdir ~/tars/builddir
~/tars/sourcedir这个临时目录放源文件及解压缩后的源文件。 ~/tars/builddir在这里进行编译。
/armtools把arm-linux交叉编译环境安装在这里。

首先安装binutils
[root@binnary ~ ]# cd ~/tars/sourcedir
[root@binnary sourcedir]# tar -zxf binutils-2.15.tar.gz
[root@binnary sourcedir ]# cd ~/tars/builddir
[root@binnary builddir ]# mkdir binutils
[root@binnary builddir ]# cd binutils
[root@binnary binutils ]# ../../sourcedir/binutils-2.15/configure --target=arm-linux --prefix=/armtools
[root@binnary binutils ]# make
[root@binnary binutils ]# make install
该编译过程较慢,需要数十分钟,安装完成后查看/armtools/bin目录下的文件
[root@binnary binutils ]# export PATH=/armtools/bin:$PATH

然后解压缩,配置,拷贝头文件
[root@binnary binutils ]# cd ~/tars/sourcedir
[root@binnary sourcedir ]# tar -zxvf linux-2.6.9.tar.gz
[root@binnary sourcedir ]# cd linux-2.6.9
[root@binnary linux-2.6.9 ]# vi Makefile
修改
ARCH ?= $(SUBARCH)
将$(SUBARCH)改为arm
# CROSS_COMPILE ?=(注释掉) 然后新加一行
CROSS_COMPILE ?= arm-linux-
[root@binnary linux-2.6.9 ]# make menuconfig
然后设置顺序如下(我对应的开发板上s3c2440,你的板子是什么你找什么选)
System Type --->
ARM system type (Samsung S3C2410) --->
S3C24XX Implementations --->\S3C2410(System Type->ARM System Type->/Samsung S3C2410)
[root@binnary linux-2.6.9 ]# make include/linux/version.h
[root@binnary linux-2.6.9 ]# mkdir -p /armtools/arm-linux/include
[root@binnary linux-2.6.9 ]# cp -dR include/asm-arm /armtools/arm-linux/include/asm
[root@binnary linux-2.6.9 ]# cp -dR include/linux /armtools/arm-linux/include/linux
[root@binnary linux-2.6.9 ]# cp -dR ~/tars/sourcedir/linux-2.6.9/include/asm-generic /armtools/arm-linux/include/

再下来编译gcc-3.4.2
[root@binnary linux-2.6.9 ]# cd ~/tars/sourcedir
[root@binnary sourcedir ]# tar –jvxf gcc-core-3.4.2.tar.bz2
给gcc打一个补丁,在目录gcc-3.4.2/gcc/下编辑一个文件flow.c.diff,内容如下
RCS file: /cvs/gcc/gcc/gcc/flow.c,v
retrieving revision 1.593
retrieving revision 1.594
diff -u -r1.593 -r1.594
--- gcc/gcc/flow.c 2004/07/09 03:29:32 1.593
+++ gcc/gcc/flow.c 2004/08/02 13:19:39 1.594
@@ -1865,19 +1865,22 @@
rtx set_src = SET_SRC (pc_set (BB_END (bb)));
rtx cond_true = XEXP (set_src, 0);
rtx reg = XEXP (cond_true, 0);
+ enum rtx_code inv_cond;
if (GET_CODE (reg) == SUBREG)
reg = SUBREG_REG (reg);
/* We can only track conditional lifetimes if the condition is - in the form of a comparison of a register against zero. - If the condition is more complex than that, then it is safe - not to record any information. */
- if (REG_P (reg)
+ in the form of a reversible comparison of a register against + zero. If the condition is more complex than that, then it is + safe not to record any information. */
+ inv_cond = reversed_comparison_code (cond_true, BB_END (bb));
+ if (inv_cond != UNKNOWN
+ && REG_P (reg)
&& XEXP (cond_true, 1) == const0_rtx)
{
rtx cond_false
- = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond_true)),
+ = gen_rtx_fmt_ee (inv_cond,
GET_MODE (cond_true),
XEXP (cond_true, 0),
XEXP (cond_true, 1));
if (GET_CODE (XEXP (set_src, 1)) == PC)
用此文件给flow.c打补丁,或者依此文件直接修改flow.c(修改前请备份这两个文件),flow.c.diff该补丁用于产生crti.o和crtn.o文件。
[root@binnary gcc ]# patch flow.c –p1 < ../../flow.c.diff [root@binnary gcc ]# cd ~/tars/builddir
[root@binnary builddir ]# mkdir gcc-core
[root@binnary builddir ]# cd gcc-core
[root@binnary gcc-core ]# ../../sourcedir/gcc-3.4.2/configure --target=arm-linux --prefix=/armtools --enable-languages=c --disable-shared --disable-threads --without-headers --with-newlib
其中选项--enable-languages=c表示只支持C语言,--disable-threads表示去掉thread功能,这个功能需要glibc的支持。--disable-shared表示只进行静态库编译,不支持共享库编译。
接下来执行编译和安装操作,命令如下:
[root@binnary gcc-core ]# make
[root@binnary gcc-core ]# make install

再再然后编译安装glibc
[root@binnary gcc-core ]# cd ~/tars/sourcedir
[root@binnary sourcedir ]# tar -zxvf glibc-2.3.5.tar.gz
[root@binnary sourcedir ]# cd glibc-2.3.5
[root@binnary glibc-2.3.5 ]# tar -jxvf ../glibc-linuxthreads-2.3.5.tar.gz
然后进行编译配置,glibc-2.3.5配置前必须新建一个编译目录,否则在glibc-2.3.5目录下不允许进行配置操作,此处在~/tars/builddir/目录下建立名为glibc的目录,配置操作如下:
[root@binnary glibc-2.3.5 ]# cd ~/tars/builddir
[root@binnary builddir ]# mkdir glibc
[root@binnary builddir ]# cd glibc
[root@binnary glibc ]# vi ~/tars/sourcedir/glibc2.3.5/sysdeps/unix/sysv/linux/arm/ioperm.c
将里面的BUS_ISA改为CTL_BUS_ISA
98 static int
99 init_iosys (void)
100 {
101 char systype[256];
102 int i, n;
103 static int iobase_name[] = { CTL_BUS, CTL_BUS_ISA, BUS_ISA_PORT_BASE };
104 static int ioshift_name[] = { CTL_BUS, CTL_BUS_ISA, BUS_ISA_PORT_SHIFT };
105 size_t len = sizeof(io.base);
106
107 if (! sysctl (iobase_name, 3, &io.io_base, &len, NULL, 0)
108 && ! sysctl (ioshift_name, 3, &io.shift, &len, NULL, 0))
109 {
110 io.initdone = 1;
111 return 0;
112 }
[root@binnary glibc ]# vi ~/tars/sourcedir/glibc-2.3.5/Makeconfig
把里面的-lgcc_eh都删掉
505 ifneq ($(have-as-needed),yes)
506 libgcc_eh := -lgcc_eh $(libunwind)
507 else
508 libgcc_eh := -Wl,--as-needed -lgcc_s$(libgcc_s_suffix) $(libunwind) -Wl,--no-as-needed
509 endif
510 gnulib := -lgcc $(libgcc_eh)
511 static-gnulib := -lgcc -lgcc_eh $(libunwind)
512 libc.so-gnulib := -lgcc
513 endif
[root@binnary glibc ]# export CC=arm-linux-gcc
[root@binnary glibc ]# ~/tars/sourcedir/glibc-2.3.5/configure \
--prefix=/armtools/arm-linux \ --host=arm-linux \ --build=i686-pc-linux-gnu \ --with-headers=/armtools/arm-linux/include \ --enable-add-ons=linuxthreads
配置完后编译和安装 glibc
[root@binnary glibc ]# make
[root@binnary glibc ]# make install

最后编译安装gcc 的c, c++ 编译器。
[root@binnary glibc ]# cd ~/tars/sourcedir/
[root@binnary sourcedir ]# tar -jxf gcc-g++-3.4.2.tar.bz2 [root@binnary sourcedir ]# cd ~/tars/builddir/
[root@binnary builddir ]# mkdir gcc
[root@binnary builddir ]# cd gcc
[root@binnary gcc ]# unset CC
[root@binnary gcc ]# ../../sourcedir/gcc-3.4.2/configure \
--prefix= /armtools\ --target=arm-linux \ --enable-languages=c,c++ \ --without-headers \ --disable-shared
[root@binnary gcc ]# make
[root@binnary gcc ]# make install

这就算是结束了.
测试的话你到/armtools/bin下写一个c程序
例如#cd /armtools/bin
#vim c1.c
写完之后#gcc -Wall -o c1 c1.c
如果你写的c1.c里面有调用math.h的话上面的命令变为
#gcc -Wall -o -lm c1 c1.c
完成之后#file c1.c
再#file c1
两者对比一下
你会发现一个是基于ASC-II一个是基于ARM的
这就说明你搭建成功了
最后你可以把你的/armtools打个包,保存起来,以备日后使用

中间很多编译的环节时间较长,如果一切顺利的做完大概需要两个小时.要有耐心哦

P.S. 终于完了,希望对你有帮助

5. 移植newlib的问题

先尝试直接简单修改配置编译 如果有合适的配置这样当然最省事
有如果有问题了在考虑完全移植的问题

6. 如何使用clang+llvm+binutils+newlib+gdb搭建交叉编译环境

测试环境:Windows8.1 + MSYS2 with Mingw, Clang, LLVM + GNU Tools for ARM Embedded Processor


  1. 首先用用Clang生成LLVM字节码

    clang -emit-llvm --target=arm-none-eabi -mcpu=cortex-m3 -mthumb -mfloat-abi=soft

    注意,需要手动添加GNU Tools for ARM Embedd的头文件

  2. 然后用llc生成汇编代码

  3. 接着,使用GNU Tools for ARM Embedded Processor的汇编器生成可执行文件

    arm-none-eabi-as -mcpu=cortex-m3 -mthumb -mfloat-abi=soft

    二进制文件用GNU Tools for ARM Embedded Processor里的arm-none-eabi-obj生成

  4. 一些需要注意的地方是Clang的默认配置可能和目标架构的汇编器不一致。比如arm-none-eabi-as会默认开启short-enums,当直接使用arm-none-eabi-gcc时这不是问题,因为编译器也默认开启了这个选项,但Clang不会,所以需要手动加上-fshort-enums。

7. 如何构建MIPS交叉编译工具链

第一步 创建目录以及环境变量
在当前用户目录下创建target-project文件夹,在该文件夹下创建mips-mole文件夹,在mips-mole文件夹下创建三个文件夹:build-tools,kernel,tools,最后,在build-tools文件夹下创建build-gcc,build-boot-gcc,build-glibc,build-binutils文件夹。命令如下:

$ cd ~
$ mkdir -p ./target-project/mips-mole/{kernel/,tools/,build-tools/{build-gcc,build-boot-gcc,build-glibc,build-binutils}}
$ tree ./target-project/mips-mole/

使用脚本构建环境变量
#! /bin/bash

注意修改/home/用户名,修改正确后,使用source使脚本生效

$ cd target-project
$ chmod +x mips.sh
$ source mips.sh
可以使用echo査看相关变量名以观察环境变量是否生效。
最后把linux-2.6.38.tar.bz2下载放置在kernel文件夹下,binutils-2.22.tar.gz,gcc-4.6.2.tar.gz,glibc-2.14.tar.gz,glibc-ports-2.14.tar.gz,gmp-5.0.4.tar.gz,mpc-0.9.tar.gz,mpfr-3.0.1.tar.gz下载放置在build-tools文件夹下。

第二步 安装基于MIPS的linux头文件

$ cd $PRJROOT/kernel
$ tar -xjvf linux-2.6.38.tar.bz2
$ cd linux-2.6.38
在指定路径下创建include文件夹,用来存放相关头文件。

$ mkdir -p $TARGET_PREFIX/include
保证linux源码是干净的。

$ make mrproper
生成需要的头文件。
$ make ARCH=mips headers_check

$ make ARCH=mips INSTALL_HDR_PATH=dest headers_install
将dest文件夹下的所有文件复制到指定的include文件夹内。

$ cp -rv dest/include/* $TARGET_PREFIX/include
最后删除dest文件夹
$ rm -rf dest
$ ls -l $TARGET_PREFIX/include

第三步 安装binutils-2.22

$ cd $PRJROOT/build-tools
$ tar -xzvf binutils-2.22.tar.gz
$ cd build-binutils
$ ../binutils-2.22/configure --target=$TARGET --prefix=$PREFIX
$ make
$ make install

再安装automake。

$ tar -xzvf automake-1.11.1.tar.gz
$ cd automake-1.11.1
$ ./configure
$ make
$ sudo make install
下面开始修改相关文件,主要是去掉-Werror。
$ cd $PRJROOT/build-tools/binutils-2.22/gas
$ ge dit configure
将下面内容
# Enable -Werror by default when using gcc
if test "${GCC}" = yes -a -z "${ERROR_ON_WARNING}" ; then
ERROR_ON_WARNING=yes
fi
修改为
# Enable -Werror by default when using gcc
if test "${GCC}" = yes -a -z "${ERROR_ON_WARNING}" ; then
ERROR_ON_WARNING=no
fi
但是,需要重新configure生成Makefile.in。

$ ./configure (在binutils/gas路径下的configure)
$ make distclean (切记)
然后重新执行第三步,这次编译可过。

第四步 安装gcc引导器

$ cd $PRJROOT/build-tools
$ tar -xzvf gcc-4.6.2.tar.gz
$ tar -xjvf gmp-5.0.4.tar.bz2
$ mv gmp-5.0.4 ./gcc-4.6.2/gmp
$ tar -xzvf mpc-0.9.tar.gz
$ mv mpc-0.9 ./gcc-4.6.2/mpc
$ tar -xzvf mpfr-3.0.1.tar.gz
$ mv mpfr-3.0.1 ./gcc-4.6.2/mpfr
$ cd build-boot-gcc
$ ../gcc-4.6.2/configure --target=$TARGET --prefix=$PREFIX --disable-shared <br>--without-headers --with-newlib --enable-languages=c --disable-decimal-float <br>--disable-libgomp --disable-libmudflap --disable-libssp --disable-threads --disable-multilib
编译并安装gcc引导器、libgcc库。

$ make all-gcc
$ make all-target-libgcc
$ make install-gcc
$ make install-target-libgcc

第五步 编译glibc

$ cd $PRJROOT/build-tools
$ tar xzvf glibc-2.14.tar.gz
$ cd glibc-2.14
删除Makefonfig文件中的内容-lgcc_eh。

$ cp -v Makeconfig{,.b肠花斑拘职饺办邪暴矛k}
$ sed -e 's/-lgcc_eh//g' Makeconfig.bk > Makeconfig
$ cd ..
$ tar -xjvf glibc-ports-2.14.tar.bz2
$ mv glibc-ports-2.14 ./glibc-2.14/ports
$ cd build-glibc
$ CC=mipsel-linux--gcc ../glibc-2.14/configure --host=$TARGET --prefix="/usr" <br>--enable-add-ons --with-headers=$TARGET_PREFIX/include libc_cv_forced_unwind=yes <br>libc_cv_c_cleanup=yes
注意:此时如何设置了LD_LIBRARY_PATH环境变量会configure error,需要删除该变量重新configure。

$ make
$ make install_root=$TARGET_PREFIX prefix=”” install
第六步 完全安装gcc
首先,也是很重要的是去掉libc等库文件的绝对路径。

$ cd $TARGET_PREFIX/lib
备份一下。

$ cp libc.so libc.so.bk
$ gedit libc.so
将原内容
GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a AS_NEEDED ( /lib/ld.so.1 ) )
修改为
GROUP ( libc.so.6 libc_nonshared.a AS_NEEDED ( ld.so.1 ) )

$ cp libpthread.so libpthread.so.bk
$ gedit libpthread.so
将原内容
GROUP ( /lib/libpthread.so.0 /lib/libpthread_nonshared.a )
修改为
GROUP ( libpthread.so.0 libpthread_nonshared.a )
然后可以完全编译gcc。

8. 如何为嵌入式开发建立交叉编译环境

下面我们将以建立针对arm的交叉编译开发环境为例来解说整个过程,其他的体系结构与这个相类似,只要作一些对应的改动。我的开发环境是,宿主机 i386-redhat-7.2,目标机 arm。
这个过程如下
1. 下载源文件、补丁和建立编译的目录
2. 建立内核头文件
3. 建立二进制工具(binutils)
4. 建立初始编译器(bootstrap gcc)
5. 建立c库(glibc)
6. 建立全套编译器(full gcc)
下载源文件、补丁和建立编译的目录
1. 选定软件版本号
选择软件版本号时,先看看glibc源代码中的INSTALL文件。那里列举了该版本的glibc编译时所需的binutils 和gcc的版本号。例如在 glibc-2.2.3/INSTALL 文件中推荐 gcc 用 2.95以上,binutils 用 2.10.1 以上版本。
我选的各个软件的版本是:
linux-2.4.21+rmk2
binutils-2.10.1
gcc-2.95.3
glibc-2.2.3
glibc-linuxthreads-2.2.3
如果你选的glibc的版本号低于2.2,你还要下载一个叫glibc-crypt的文件,例如glibc-crypt-2.1.tar.gz。 Linux 内核你可以从www.kernel.org 或它的镜像下载。
Binutils、gcc和glibc你可以从FSF的FTP站点ftp://ftp.gun.org/gnu/ 或它的镜像去下载。 在编译glibc时,要用到 Linux 内核中的 include 目录的内核头文件。如果你发现有变量没有定义而导致编译失败,你就改变你的内核版本号。例如我开始用linux-2.4.25+vrs2,编译glibc-2.2.3 时报 BUS_ISA 没定义,后来发现在 2.4.23 开始它的名字被改为 CTL_BUS_ISA。如果你没有完全的把握保证你改的内核改完全了,就不要动内核,而是把你的 Linux 内核的版本号降低或升高,来适应 glibc。
Gcc 的版本号,推荐用 gcc-2.95 以上的。太老的版本编译可能会出问题。Gcc-2.95.3 是一个比较稳定的版本,也是内核开发人员推荐用的一个 gcc 版本。
如果你发现无法编译过去,有可能是你选用的软件中有的加入了一些新的特性而其他所选软件不支持的原因,就相应降低该软件的版本号。例如我开始用 gcc-3.3.2,发现编译不过,报 as、ld 等版本太老,我就把 gcc 降为 2.95.3。 太新的版本大多没经过大量的测试,建议不要选用。
回页首
2. 建立工作目录
首先,我们建立几个用来工作的目录:
在你的用户目录,我用的是用户liang,因此用户目录为 /home/liang,先建立一个项目目录embedded。
$pwd
/home/liang
$mkdir embedded
再在这个项目目录 embedded 下建立三个目录 build-tools、kernel 和 tools。
build-tools-用来存放你下载的 binutils、gcc 和 glibc 的源代码和用来编译这些源代码的目录。
kernel-用来存放你的内核源代码和内核补丁。
tools-用来存放编译好的交叉编译工具和库文件。
$cd embedded
$mkdir build-tools kernel tools
执行完后目录结构如下:
$ls embedded
build-tools kernel tools
3. 输出和环境变量
我们输出如下的环境变量方便我们编译。
$export PRJROOT=/home/liang/embedded
$export TARGET=arm-linux
$export PREFIX=$PRJROOT/tools
$export TARGET_PREFIX=$PREFIX/$TARGET
$export PATH=$PREFIX/bin:$PATH
如果你不惯用环境变量的,你可以直接用绝对或相对路径。我如果不用环境变量,一般都用绝对路径,相对路径有时会失败。环境变量也可以定义在.bashrc文件中,这样当你logout或换了控制台时,就不用老是export这些变量了。
体系结构和你的TAEGET变量的对应如下表

你可以在通过glibc下的config.sub脚本来知道,你的TARGET变量是否被支持,例如:
$./config.sub arm-linux
arm-unknown-linux-gnu
在我的环境中,config.sub 在 glibc-2.2.3/scripts 目录下。
网上还有一些 HOWTO 可以参考,ARM 体系结构的《The GNU Toolchain for ARM Target HOWTO》,PowerPC 体系结构的《Linux for PowerPC Embedded Systems HOWTO》等。对TARGET的选取可能有帮助。
4. 建立编译目录
为了把源码和编译时生成的文件分开,一般的编译工作不在的源码目录中,要另建一个目录来专门用于编译。用以下的命令来建立编译你下载的binutils、gcc和glibc的源代码的目录。
$cd $PRJROOT/build-tools
$mkdir build-binutils build-boot-gcc build-gcc build-glibc gcc-patch
build-binutils-编译binutils的目录
build-boot-gcc-编译gcc 启动部分的目录
build-glibc-编译glibc的目录
build-gcc-编译gcc 全部的目录
gcc-patch-放gcc的补丁的目录
gcc-2.95.3 的补丁有 gcc-2.95.3-2.patch、gcc-2.95.3-no-fixinc.patch 和gcc-2.95.3-returntype-fix.patch,可以从 http://www.linuxfromscratch.org/ 下载到这些补丁。
再将你下载的 binutils-2.10.1、gcc-2.95.3、glibc-2.2.3 和 glibc-linuxthreads-2.2.3 的源代码放入 build-tools 目录中
看一下你的 build-tools 目录,有以下内容:
$ls
binutils-2.10.1.tar.bz2 build-gcc gcc-patch
build-binutls build-glibc glibc-2.2.3.tar.gz
build-boot-gcc gcc-2.95.3.tar.gz glibc-linuxthreads-2.2.3.tar.gz
回页首
建立内核头文件
把你从 www.kernel.org 下载的内核源代码放入 $PRJROOT /kernel 目录
进入你的 kernel 目录:
$cd $PRJROOT /kernel
解开内核源代码
$tar -xzvf linux-2.4.21.tar.gz

$tar -xjvf linux-2.4.21.tar.bz2
小于 2.4.19 的内核版本解开会生成一个 linux 目录,没带版本号,就将其改名。
$mv linux linux-2.4.x
给 Linux 内核打上你的补丁
$cd linux-2.4.21
$patch -p1 < ../patch-2.4.21-rmk2
编译内核生成头文件
$make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig
你也可以用 config 和 xconfig 来代替 menuconfig,但这样用可能会没有设置某些配置文件选项和没有生成下面编译所需的头文件。推荐大家用 make menuconfig,这也是内核开发人员用的最多的配置方法。配置完退出并保存,检查一下的内核目录中的 include/linux/version.h 和 include/linux/autoconf.h 文件是不是生成了,这是编译 glibc 是要用到的,version.h 和 autoconf.h 文件的存在,也说明了你生成了正确的头文件。
还要建立几个正确的链接
$cd include
$ln -s asm-arm asm
$cd asm
$ln -s arch-epxa arch
$ln -s proc-armv proc
接下来为你的交叉编译环境建立你的内核头文件的链接
$mkdir -p $TARGET_PREFIX/include
$ln -s $PRJROOT/kernel/linux-2.4.21/include/linux $TARGET_PREFIX/include/linux
$in -s $PRJROOT/kernel/linux-2.4.21/include/asm-arm $TARGET_PREFIX/include/asm
也可以把 Linux 内核头文件拷贝过来用
$mkdir -p $TARGET_PREFIX/include
$cp -r $PRJROOT/kernel/linux-2.4.21/include/linux $TARGET_PREFIX/include
$cp -r $PRJROOT/kernel/linux-2.4.21/include/asm-arm $TARGET_PREFIX/include
回页首
建立二进制工具(binutils)
binutils是一些二进制工具的集合,其中包含了我们常用到的as和ld。
首先,我们解压我们下载的binutils源文件。
$cd $PRJROOT/build-tools
$tar -xvjf binutils-2.10.1.tar.bz2
然后进入build-binutils目录配置和编译binutils。
$cd build-binutils
$../binutils-2.10.1/configure --target=$TARGET --prefix=$PREFIX
--target 选项是指出我们生成的是 arm-linux 的工具,--prefix 是指出我们可执行文件安装的位置。
会出现很多 check,最后产生 Makefile 文件。
有了 Makefile 后,我们来编译并安装 binutils,命令很简单。
$make
$make install
看一下我们 $PREFIX/bin 下的生成的文件
$ls $PREFIX/bin
arm-linux-addr2line arm-linux-gasp arm-linux-objmp arm-linux-strings
arm-linux-ar arm-linux-ld arm-linux-ranlib arm-linux-strip
arm-linux-as arm-linux-nm arm-linux-readelf
arm-linux-c++filt arm-linux-obj arm-linux-size
我们来解释一下上面生成的可执行文件都是用来干什么的
add2line - 将你要找的地址转成文件和行号,它要使用 debug 信息。
Ar-产生、修改和解开一个存档文件
As-gnu 的汇编器
C++filt-C++ 和 java 中有一种重载函数,所用的重载函数最后会被编译转化成汇编的标号,c++filt 就是实现这种反向的转化,根据标号得到函数名。
Gasp-gnu 汇编器预编译器。
Ld-gnu 的连接器
Nm-列出目标文件的符号和对应的地址
Obj-将某种格式的目标文件转化成另外格式的目标文件
Objmp-显示目标文件的信息
Ranlib-为一个存档文件产生一个索引,并将这个索引存入存档文件中
Readelf-显示 elf 格式的目标文件的信息
Size-显示目标文件各个节的大小和目标文件的大小
Strings-打印出目标文件中可以打印的字符串,有个默认的长度,为4
Strip-剥掉目标文件的所有的符号信息
回页首
建立初始编译器(bootstrap gcc)
首先进入 build-tools 目录,将下载 gcc 源代码解压
$cd $PRJROOT/build-tools
$tar -xvzf gcc-2.95.3.tar.gz
然后进入 gcc-2.95.3 目录给 gcc 打上补丁
$cd gcc-2.95.3
$patch -p1< ../gcc-patch/gcc-2.95.3.-2.patch
$patch -p1< ../gcc-patch/gcc-2.95.3.-no-fixinc.patch
$patch -p1< ../gcc-patch/gcc-2.95.3-returntype-fix.patch
echo timestamp > gcc/cstamp-h.in
在我们编译并安装 gcc 前,我们先要改一个文件 $PRJROOT/gcc/config/arm/t-linux,把
TARGET_LIBGCC2-CFLAGS = -fomit-frame-pointer -fPIC
这一行改为
TARGET_LIBGCC2-CFLAGS = -fomit-frame-pointer -fPIC -Dinhibit_libc -D__gthr_posix_h
你如果没定义 -Dinhibit,编译时将会报如下的错误
../../gcc-2.95.3/gcc/libgcc2.c:41: stdlib.h: No such file or directory
../../gcc-2.95.3/gcc/libgcc2.c:42: unistd.h: No such file or directory
make[3]: *** [libgcc2.a] Error 1
make[2]: *** [stmp-multilib-sub] Error 2
make[1]: *** [stmp-multilib] Error 1
make: *** [all-gcc] Error 2
如果没有定义 -D__gthr_posix_h,编译时会报如下的错误
In file included from gthr-default.h:1,
from ../../gcc-2.95.3/gcc/gthr.h:98,
from ../../gcc-2.95.3/gcc/libgcc2.c:3034:
../../gcc-2.95.3/gcc/gthr-posix.h:37: pthread.h: No such file or directory
make[3]: *** [libgcc2.a] Error 1
make[2]: *** [stmp-multilib-sub] Error 2
make[1]: *** [stmp-multilib] Error 1
make: *** [all-gcc] Error 2
还有一种与-Dinhibit同等效果的方法,那就是在你配置configure时多加一个参数-with-newlib,这个选项不会迫使我们必须使用newlib。我们编译了bootstrap-gcc后,仍然可以选择任何c库。
接着就是配置boostrap gcc, 后面要用bootstrap gcc 来编译 glibc 库。
$cd ..; cd build-boot-gcc
$../gcc-2.95.3/configure --target=$TARGET --prefix=$PREFIX \
>--without-headers --enable-languages=c --disable-threads
这条命令中的 -target、--prefix 和配置 binutils 的含义是相同的,--without-headers 就是指不需要头文件,因为是交叉编译工具,不需要本机上的头文件。-enable-languages=c是指我们的 boot-gcc 只支持 c 语言。--disable-threads 是去掉 thread 功能,这个功能需要 glibc 的支持。
接着我们编译并安装 boot-gcc
$make all-gcc
$make install-gcc
我们来看看 $PREFIX/bin 里面多了哪些东西
$ls $PREFIX/bin
你会发现多了 arm-linux-gcc 、arm-linux-unprotoize、cpp 和 gcov 几个文件。
Gcc-gnu 的 C 语言编译器
Unprotoize-将 ANSI C 的源码转化为 K&R C 的形式,去掉函数原型中的参数类型。
Cpp-gnu的 C 的预编译器
Gcov-gcc 的辅助测试工具,可以用它来分析和优程序。
使用 gcc3.2 以及 gcc3.2 以上版本时,配置 boot-gcc 不能使用 --without-headers 选项,而需要使用 glibc 的头文件。
回页首
建立 c 库(glibc)
首先解压 glibc-2.2.3.tar.gz 和 glibc-linuxthreads-2.2.3.tar.gz 源代码
$cd $PRJROOT/build-tools
$tar -xvzf glibc-2.2.3.tar.gz
$tar -xzvf glibc-linuxthreads-2.2.3.tar.gz --directory=glibc-2.2.3
然后进入 build-glibc 目录配置 glibc
$cd build-glibc
$CC=arm-linux-gcc ../glibc-2.2.3/configure --host=$TARGET --prefix="/usr"
--enable-add-ons --with-headers=$TARGET_PREFIX/include
CC=arm-linux-gcc 是把 CC 变量设成你刚编译完的boostrap gcc,用它来编译你的glibc。--enable-add-ons是告诉glibc用 linuxthreads 包,在上面我们已经将它放入了 glibc 源码目录中,这个选项等价于 -enable-add-ons=linuxthreads。--with-headers 告诉 glibc 我们的linux 内核头文件的目录位置。
配置完后就可以编译和安装 glibc
$make
$make install_root=$TARGET_PREFIX prefix="" install
然后你还要修改 libc.so 文件

GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a)
改为
GROUP ( libc.so.6 libc_nonshared.a)
这样连接程序 ld 就会在 libc.so 所在的目录查找它需要的库,因为你的机子的/lib目录可能已经装了一个相同名字的库,一个为编译可以在你的宿主机上运行的程序的库,而不是用于交叉编译的。
回页首
建立全套编译器(full gcc)
在建立boot-gcc 的时候,我们只支持了C。到这里,我们就要建立全套编译器,来支持C和C++。
$cd $PRJROOT/build-tools/build-gcc
$../gcc-2.95.3/configure --target=$TARGET --prefix=$PREFIX --enable-languages=c,c++
--enable-languages=c,c++ 告诉 full gcc 支持 c 和 c++ 语言。
然后编译和安装你的 full gcc
$make all
$make install
我们再来看看 $PREFIX/bin 里面多了哪些东西
$ls $PREFIX/bin
你会发现多了 arm-linux-g++ 、arm-linux-protoize 和 arm-linux-c++ 几个文件。
G++-gnu的 c++ 编译器。
Protoize-与Unprotoize相反,将K&R C的源码转化为ANSI C的形式,函数原型中加入参数类型。
C++-gnu 的 c++ 编译器。
到这里你的交叉编译工具就算做完了,简单验证一下你的交叉编译工具。
用它来编译一个很简单的程序 helloworld.c
#include <stdio.h>
int main(void)
{
printf("hello world\n");
return 0;
}
$arm-linux-gcc helloworld.c -o helloworld
$file helloworld
helloworld: ELF 32-bit LSB executable, ARM, version 1,
dynamically linked (uses shared libs), not stripped
上面的输出说明你编译了一个能在 arm 体系结构下运行的 helloworld,证明你的编译工具做成功了。
转载仅供参考,版权属于原作者

9. (cygwin gcc): 编译newlib时Segmentation fault的报错是什么意思

gcc 的问题,升级gcc版本有可能可以解决该问题。我从4.7.1升到6.2.0后就没错了。
参见 https://forums.gentoo.org/viewtopic-t-947148-start-0.html

10. 如何在linux平台构建基于newlib工具链

交叉编译通俗地讲就是在一种平台上编译出能运行在体系结构不同的另一种平台上的程式,比如在PC平台(X86 CPU)上编译出能运行在以ARM为内核的CPU平台上的程式,编译得到的程式在X86 CPU平台上是不能运行的,必须放到ARM CPU平台上才能运行,虽然两个平台用的都是Linux系统。这种方法在异平台移植和嵌入式研发时非常有用。相对和交叉编译,平常做的编译叫本地编译,也就是在当前平台编译,编译得到的程式也是在本地执行。用来编译这种跨平台程式的编译器就叫交叉编译器,相对来说,用来做本地编译的工具就叫本地编译器。所以要生成在目标机上运行的程式,必须要用交叉编译工具链来完成。在裁减和制定Linux内核用于嵌入式系统之前,由于一般嵌入式研发系统存储大小有限,通常都要在性能优越的PC上建立一个用于目标机的交叉编译工具链,用该交叉编译工具链在PC上编译目标机上要运行的程式。交叉编译工具链是个由编译器、连接器和解释器组成的综合研发环境,交叉编译工具链主要由binutils、gcc和glibc 3个部分组成。有时出于减小 libc 库大小的考虑,也能用别的 c 库来代替 glibc,例如 uClibc、dietlibc 和 newlib。建立交叉编译工具链是个相当复杂的过程,如果不想自己经历复杂繁琐的编译过程,网上有一些编译好的可用的交叉编译工具链能下载,但就以学习为目的来说读者有必要学习自己制作一个交叉编译工具链。本章通过具体的实例讲述基于ARM的嵌入式Linux交叉编译工具链的制作过程。 构建交叉编译器的第一个步骤就是确定目标平台。在GNU系统中,每个目标平台都有一个明确的格式,这些信息用于在构建过程中识别要使用的不同工具的正确版本。因此,当在一个特定目标机下运行GCC时,GCC便在目录路径中查找包含该目标规范的应用程式路径。GNU的目标规范格式为CPU-PLATFORM-OS。例如x86/i386 目标机名为i686-pc-linux-gnu。本章的目的是讲述建立基于ARM平台的交叉工具链,所以目标平台名为arm-linux-gnu。 通常构建交叉工具链有3种方法。 方法一 分步编译和安装交叉编译工具链所需要的库和原始码,最终生成交叉编译工具链。该方法相对比较困难,适合想深入学习构建交叉工具链的读者。如果只是想使用交叉工具链,建议使用方法二或方法三构建交叉工具链。 方法二 通过Crosstool脚本工具来实现一次编译生成交叉编译工具链,该方法相对于方法一要简单许多,并且出错的机会也非常少,建议大多数情况下使用该方法构建交叉编译工具链。 方法三 直接通过网上(ftp.arm.kernel.org.uk)下载已制作好的交叉编译工具链。该方法的好处不用多说,当然是简单省事,但和此同时该方法有一定的弊端就是局限性太大,因为毕竟是别人构建好的,也就是固定的没有灵活性,所以构建所用的库及编译器的版本也许并不适合你要编译的程式,同时也许会在使用时出现许多莫名的错误,建议读者慎用此方法。 为了让读者真正的学习交叉编译工具链的构建,下面将重点周详地介绍前两种构建ARM Linux交叉编译工具链的方法。 2.2.1 分步构建交叉编译链 分步构建,顾名思义就是一步一步地建立交叉编译链,不同于2.2.2节中讲述的Crosstool脚本工具一次编译生成的方法,该方法适合那些希望深入学习了解构建交叉编译工具链的读者。该方法相对来说难度较大,通常情况下困难重重,犹如唐僧西天取经,不过本文会尽可能周详地介绍构建的每一个步骤,读者完万能根据本节的内容自己独立实践,构建自己的交叉工具链。该过程所需的时间较长,希望读者有较强的耐心和毅力去学习和实践他,通过实践能使读者更加清晰交叉编译器的构建过程及各个工具包的作用。该方法所需资源如表2.1所示。 表2.1 所需资源 安装包 下载地址 安装包 下载地址 linux-2.6.10.tar.gz ftp.kernel.org glibc-2.3.2.tar.gz ftp.gnu.org binutils-2.15.tar.bz2 ftp.gnu.org glibc-linuxthreads-2.3.2.tar.gz ftp.gnu.org gcc-3.3.6.tar.gz ftp.gnu.org 通过相关站点下载以上资源后,就能开始建立交叉编译工具链了。 1.建立工作目录 首先建立工作目录,工作目录就是在什么目录下构建交叉工具链,目录的构建一般没有特别的需求,能根据个人喜好建立。以下所建立的目录是作者自定义的,当前的用户定义为mike,因此用户目录为/home/mike,在用户目录下首先建立一个工作目录(armlinux),建立工作目录的命令行操作如下: # cd /home/mike # mkdir armlinux 再在这个工作目录armlinux下建立3个目录 build-tools、kernel 和 tools。具体操作如下: # cd armlinux # mkdir build-tools kernel tools 其中各目录的作用如下。 ● build-tools 用来存放下载的binutils、gcc、glibc等原始码和用来编译这些原始码的目录; ● kernel 用来存放内核原始码; ● tools 用来存放编译好的交叉编译工具和库文件。 2.建立环境变量 该步骤的目的是为了方便重复输入路径,因为重复操作每件相同的事情总会让人觉得非常麻烦,如果读者不习惯使用环境变量就能略过该步,直接输入绝对路径就能。声明以下环境变量的目的是在之后编译工具库的时候会用到,非常方便输入,尤其是能降低输错路径的风险。 # export PRJROOT=/home/mike/armlinux # export TARGET=arm-linux # export PREFIX=$PRJROOT/tools # export TARGET_PREFIX=$PREFIX/$TARGET # export PATH=$PREFIX/bin:$PATH 注意,用export声明的变量是临时的变量,也就是当注销或更换了控制台,这些环境变量就消失了,如果还需要使用这些环境变量就必须重复export操作,所以有时会非常麻烦。值得庆幸的是,环境变量也能定义在bashrc文件中,这样当注销或更换控制台时,这些变量就一直有效,就不用老是export这些变量了。 3.编译、安装Binutils Binutils是GNU工具之一,他包括连接器、汇编器和其他用于目标文件和档案的工具,他是二进制代码的处理维护工具。安装Binutils工具包含的程式有addr2line、ar、as、c++filt、gprof、ld、nm、obj、objmp、ranlib、readelf、size、strings、strip、libiberty、libbfd和libopcodes。对这些程式的简单解释如下。 ● addr2line 把程式地址转换为文件名和行号。在命令行中给他一个地址和一个可执行文件名,他就会使用这个可执行文件的调试信息指出在给出的地址上是哪个文件及行号。 ● ar 建立、修改、提取归档文件。归档文件是包含多个文件内容的一个大文件,其结构确保了能恢复原始文件内容。 ● as 主要用来编译GNU C编译器gcc输出的汇编文件,产生的目标文件由连接器ld连接。 ● c++filt 连接器使用他来过滤 C++ 和 Java 符号,防止重载函数冲突。 ● gprof 显示程式调用段的各种数据。 ● ld 是连接器,他把一些目标和归档文件结合在一起,重定位数据,并连接符号引用。通常,建立一个新编译程式的最后一步就是调用ld。 ● nm 列出目标文件中的符号。 ● obj 把一种目标文件中的内容复制到另一种类型的目标文件中。 ● objmp 显示一个或更多目标文件的信息。使用选项来控制其显示的信息,他所显示的信息通常只有编写编译工具的人才感兴趣。 ● ranlib 产生归档文件索引,并将其保存到这个归档文件中。在索引中列出了归档文件各成员所定义的可重分配目标文件。 ● readelf 显示elf格式可执行文件的信息。 ● size 列出目标文件每一段的大小及总体的大小。默认情况下,对于每个目标文件或一个归档文件中的每个模块只产生一行输出。 ● strings 打印某个文件的可打印字符串,这些字符串最少4个字符长,也能使用选项-n设置字符串的最小长度。默认情况下,他只打印目标文件初始化和可加载段中的可打印字符;对于其他类型的文件他打印整个文件的可打印字符。这个程式对于了解非文本文件的内容非常有帮助。 ● strip 丢弃目标文件中的全部或特定符号。 ● libiberty 包含许多GNU程式都会用到的函数,这些程式有getopt、obstack、strerror、strtol和strtoul。 ● libbfd 二进制文件描述库。 ● libopcode 用来处理opcodes的库,在生成一些应用程式的时候也会用到他。 Binutils工具安装依赖于Bash、Coreutils、Diffutils、GCC、Gettext、Glibc、Grep、Make、Perl、Sed、Texinfo等工具。 介绍完Binutils工具后,下面将分步介绍安装binutils-2.15的过程。 首先解压binutils-2.15.tar.bz2包,命令如下: # cd $PRJROOT/build-tools # tar -xjvf binutils-2.15.tar.bz2 接着设置Binutils工具,建议建立一个新的目录用来存放设置和编译文件,这样能使源文件和编译文件独立开,具体操作如下: # cd $PRJROOT/build-tools # mkdir build-binutils # cd build-binutils # ../ binutils-2.15/configure --target=$TARGET --prefix=$PREFIX 其中选项?target的意思是制定生成的是 arm-linux 的工具,--prefix 是指出可执行文件安装的位置。执行上述操作会出现非常多check信息,最后产生 Makefile 文件。接下来执行make和安装操作,命令如下: # make # make install 该编译过程较慢,需要数十分钟,安装完成后查看/home/mike/armlinux/tools/bin目录下的文件,如果查看结果如下,表明此时Binutils工具已安装结束。 # ls $PREFIX/bin arm-linux-addr2line arm-linux-ld arm-linux-ranlib arm-linux-strip arm-linux-ar arm-linux-nm arm-linux-readelf arm-linux-as arm-linux-obj arm-linux-size arm-linux-c++filt arm-linux-objmp arm-linux-strings 4.获得内核头文件 编译器需要通过系统内核的头文件来获得目标平台所支持的系统函数调用所需要的信息。对于Linux内核,最佳的方法是下载一个合适的内核,然后复制获得头文件。需要对内核做一个基本的设置来生成正确的头文件;不过,不必编译内核。对于本例中的目标arm-linux,需要以下步骤。 (1)在kernel目录下解压linux-2.6.10.tar.gz内核包,执行命令如下: # cd $PRJROOT/kernel # tar -xvzf linux-2.6.10.tar.gz (2)接下来设置编译内核使其生成正确的头文件,执行命令如下: # cd linux-2.6.10 # make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig 其中ARCH=arm表示是以arm为体系结构,CROSS_COMPILE=arm-linux-表示是以arm-linux-为前缀的交叉编译器。也能用config和xconfig来代替menuconfig,推荐用make menuconfig,这也是内核研发人员用的最多的设置方法。注意在设置时一定要选择处理器的类型,这里选择三星的S3C2410(System Type->ARM System Type->/Samsung S3C2410),如图2.1所示。设置完退出并保存,检查一下内核目录中的include/linux/version.h和include/linux/autoconf.h文件是不是生成了,这是编译glibc时要用到的,如果version.h 和 autoconf.h 文件存在,说明生成了正确的头文件。 screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt=’Click here to open new window\nCTRL+Mouse wheel to zoom in/out’;}" border=0> 图2.1 Linux 2.6.10内核设置界面 复制头文件到交叉编译工具链的目录,首先需要在/home/mike/armlinux/tools/arm-linux目录下建立工具的头文件目录inlcude,然后复制内核头文件到此目录下,具体操作如下: # mkdir -p $TARGET_PREFIX/include # cp -r $PRJROOT/kernel/linux-2.6.10/include/linux $TARGET_PREFIX/include # cp -r $PRJROOT/kernel/linux-2.6.10/include/asm-arm $TARGET_PREFIX/include/asm 5.编译安装boot-trap gcc 这一步的目的主要是建立arm-linux-gcc工具,注意这个gcc没有glibc库的支持,所以只能用于编译内核、BootLoader等不必C库支持的程式,后面创建C库也要用到这个编译器,所以创建他主要是为创建C库做准备,如果只想编译内核和BootLoader,那么安装完这个就能到此结束。安装命令如下: # cd $PRJROOT/build-tools # tar -xvzf gcc-3.3.6.tar.gz # mkdir build-gcc # cd gcc-3.3.6 # vi gcc/config/arm/t-linux 由于是第一次安装ARM交叉编译工具,没有支持libc库的头文件,所以在gcc/config/arm/t- linux文件中给变量TARGET_LIBGCC2_CFLAGS增加操作参数选项-Dinhibit_libc -D__gthr_ posix_h来屏蔽使用头文件,否则一般默认会使用/usr/inlcude头文件。 将TARGET_LIBGCC2-CFLAGS = -fomit-frame-pointer ?fPIC改为TARGET_LIBGCC2- CFLAGS=-fomit-frame-pointer-fPIC -Dinhibit_libc -D__gthr_posix_h 修改完t-linux文件后保存,紧接着执行设置操作,如下命令: # cd build-gcc # ../ build-gcc /configure --target=$TARGET --prefix=$PREFIX --enable-languages=c --disable-threads --disable-shared 其中选项--enable-languages=c表示只支持C语言,--disable-threads表示去掉thread功能,这个功能需要glibc的支持。--disable-shared表示只进行静态库编译,不支持共享库编译。 接下来执行编译和安装操作,命令如下: # make # make install 安装完成后,在/home/mike/armlinux/tools/bin下查看,如果arm-linux-gcc等工具已生成,表示boot-trap gcc工具已安装成功。 6.建立glibc库 glibc是GUN C库,他是编译Linux系统程式非常重要的组成部分。安装glibc-2.3.2版本之前推荐先安装以下的工具: ● GNU make 3.79或更新; ● GCC 3.2或更新; ● GNU binutils 2.13或更新。 首先解压glibc-2.2.3.tar.gz和glibc-linuxthreads-2.2.3.tar.gz原始码,操作如下: # cd $PRJROOT/build-tools # tar -xvzf glibc-2.2.3.tar.gz # tar -xzvf glibc-linuxthreads-2.2.3.tar.gz --directory=glibc-2.2.3 然后进行编译设置,glibc-2.2.3设置前必须新建一个编译目录,否则在glibc-2.2.3目录下不允许进行设置操作,此处在$PRJROOT/build-tools目录下建立名为build-glibc的目录,设置操作 如下: # cd $PRJROOT/build-tools # mkdir build-glibc # cd build-glibc # CC=arm-linux-gcc ../glibc-2.2.3 /configure --host=$TARGET --prefix="/usr" --enable-add-ons --with-headers=$TARGET_PREFIX/include 选项CC=arm-linux-gcc是把CC(Cross Compiler)变量设成刚编译完的gcc,用他来编译glibc。--prefix="/usr"定义了一个目录用于安装一些和目标机器无关的数据文件,默认情况下是/usr/local目录。--enable-add-ons是告诉glibc用linuxthreads包,在上面已将他放入glibc原始码目录中,这个选项等价于-enable-add-ons=linuxthreads。--with-headers告诉glibc linux内核头文件的目录 位置。 设置完后就能编译和安装 glibc了,具体操作如下: # make # make install 7.编译安装完整的gcc 由于第一次安装的gcc没有交叉glibc的支持,目前已安装了glibc,所以需要重新编译来支持交叉glibc。并且上面的gcc也只支持C语言,目前能让他同时支持C语言还要和C++语言。具体操作如下: # cd $PRJROOT/build-tools/gcc-2.3.6 # ./configure --target=arm-linux --enable-languages=c,c++ --prefix=$PREFIX # make # make install 安装完成后会发目前$PREFIX/bin目录下又多了arm-linux-g++ 、arm-linux-c++等文件。 # ls $PREFIX/bin arm-linux-addr2line arm-linux-g77 arm-linux-gnatbind arm-linux-ranlib arm-linux-ar arm-linux-gcc arm-linux-jcf-mp arm-linux-readelf arm-linux-as arm-linux-gcc-3.3.6 arm-linux-jv-scan arm-linux-size arm-linux-c++ arm-linux-gccbug arm-linux-ld arm-linux-strings arm-linux-c++filt arm-linux-gcj arm-linux-nm arm-linux-strip arm-linux-cpp arm-linux-gcjh arm-linux-obj grepjar arm-linux-g++ arm-linux-gcov arm-linux-objmp jar 8.测试交叉编译工具链 到此为止,已介绍完了用分步构建的方法建立交叉编译工具链。下面通过一个简单的程式测试刚刚建立的交叉编译工具链看是否能够正常工作。写一个最简单的hello.c源文件,内容如下: #include int main( ) { printf(“Hello,world!\n”); return 0; } 通过以下命令进行编译,编译后生成名为hello的可执行文件,通过file命令能查看文件的类型。当显示以下信息时表明交叉工具链正常安装了,通过编译生成了ARM体系可执行的文件。注意,通过该交叉编译链编译的可执行文件只能在ARM体系下执行,不能在基于X86的普通PC上执行。 # arm-linux-gcc -o hello hello.c # file hello hello: ELF 32-bit LSB executable, ARM, version 1 (ARM), for GNU/Linux 2.4.3, dynamically linked (uses shared libs), not stripped 2.2.2 用Crosstool工具构建交叉工具链 Crosstool是一组脚本工具集,可构建和测试不同版本的gcc和glibc,用于那些支持glibc的体系结构。他也是个开源项目,下载地址是http://kegel.com/crosstool。用Crosstool构建交叉工具链要比上述的分步编译容易得多,并且也方便许多,对于仅仅为了工作需要构建交叉编译工具链的读者建议使用此方法。用Crosstool工具构建所需资源如表2.2所示。

热点内容
微信忘记密码从哪里看 发布:2024-05-19 16:06:37 浏览:32
宝马x4贷款买哪个配置好 发布:2024-05-19 15:56:03 浏览:22
微控pid算法 发布:2024-05-19 15:46:31 浏览:135
云盘视频解压密码 发布:2024-05-19 15:23:17 浏览:848
和平精英怎么改地区位置安卓 发布:2024-05-19 15:19:05 浏览:286
酒店的路由器如何配置 发布:2024-05-19 15:10:44 浏览:500
rpgmaker脚本 发布:2024-05-19 14:48:58 浏览:407
hds存储虚拟化 发布:2024-05-19 14:47:09 浏览:21
mysql数据库分片 发布:2024-05-19 14:42:30 浏览:342
2021款魏派vv6买哪个配置 发布:2024-05-19 14:31:11 浏览:633