先总结一下主要流程:

1、安装cygwin
2、下载crosstool-ng的源码,然后在cygwin中编译该源码,得到crosstool-ng程序
3、使用crosstool-ng程序,根据需要,编译生成对应的交叉编译器
4、使用交叉编译器,对你的目标代码进行编译,生成在对应平台下的可执行程序
另外补充一句,整个步骤几乎全程都在cygwin环境下进行

1、安装cgywin

直接去官网找下载链接就行了,一般默认装最新版吧;
安装cygwin时需注意,最好将安装组件中devel目录下内容全部安装了,否则后面使用make等指令时容易出错,缺失东西,见图所示: 

go windows交叉编译生成centos的可执行文件_bc

2、安装crosstool-ng

 

go windows交叉编译生成centos的可执行文件_bc_02

编译安装,在cygwin环境下执行以下命令:

tar xvf crosstool-ng-1.23.0.tar.bz2     #解压源码
cd crosstool-ng-1.23.0     #切换进目录
./configure --prefix=/opt/crosstool-ng    #配置
make    #编译
make install    #安装

编译过程中,可能会出现错误,大部分情况下是环境中缺失某些工具,因此一开始安装cgywin时选择全部内容的意义就在这里,如果还有缺失,就自己查漏补缺吧,错误信息里会有提示的

接下来将crosstool-ng添加到环境变量中,这样后面才可以使用 ct-ng 下面的一堆命令
找到当前用户的.bashrc文件,在windows下可以直接用everything搜索这个文件,然后用notepad++打开直接修改,在最后一行添加:
PATH=$PATH:/opt/crosstool-ng/bin 完事儿测试一下,使用命令:
ct-ng help 测试一下是否安装成功了,或者环境变量是不是配置成功了,未成功的话会提示ct-ng command not found类似的话

3.crosstool-ng的使用

写在前面,要学会使用ct-ng help 来查看crosstool-ng的功能,会列出来所有功能,真的很详细了

使用之前,最好新建一个文件夹,然后在cygwin中 cd 进去,再做所有的编译工作
crosstool-ng内置了一些模板配置,其中很有可能有你需要的,使用命令:
ct-ng list-samples 列出所有内置的模板配置,部分列表长这样:

[G..]   i686-ubuntu12.04-linux-gnu
[G..]   i686-ubuntu14.04-linux-gnu
[G..]   i686-ubuntu16.04-linux-gnu
[G.X]   i686-w64-mingw32
[G..]   m68k-unknown-elf
[G..]   m68k-unknown-uclinux-uclibc
[G..]   powerpc-unknown-linux-uclibc,m68k-unknown-uclinux-uclibc
[G..]   mips-ar2315-linux-gnu
[G..]   mips-malta-linux-gnu
[G..]   mips-unknown-elf
[G..]   mips-unknown-linux-uclibc
[G..]   mips64el-multilib-linux-uclibc
[G..]   mipsel-multilib-linux-gnu
[G..]   mipsel-sde-elf
[G..]   mipsel-unknown-linux-gnu
[G.X]   i686-w64-mingw32,nios2-spico-elf
[G..]   powerpc-405-linux-gnu
[G..]   powerpc-860-linux-gnu
[G..]   powerpc-e300c3-linux-gnu
[G..]   powerpc-e500v2-linux-gnuspe
[G..]   x86_64-multilib-linux-uclibc,powerpc-unknown-elf
[G..]   powerpc-unknown-linux-gnu
[G..]   powerpc-unknown-linux-uclibc
[G..]   powerpc-unknown_nofpu-linux-gnu
[G..]   powerpc64-multilib-linux-gnu
[G..]   powerpc64-unknown-linux-gnu
[G..]   powerpc64le-unknown-linux-gnu
[G.X]   s390-ibm-linux-gnu
[G..]   s390x-ibm-linux-gnu
[G..]   sh4-multilib-linux-gnu
[G..]   sh4-multilib-linux-uclibc
[G..]   sh4-unknown-linux-gnu
[G..]   sparc-leon-linux-uclibc
[G..]   sparc-unknown-linux-gnu
[G..]   sparc64-multilib-linux-gnu
[G..]   x86_64-centos6-linux-gnu
[G..]   x86_64-centos7-linux-gnu
[G..]   x86_64-multilib-linux-gnu
[G.X]   x86_64-multilib-linux-musl
[G..]   x86_64-multilib-linux-uclibc
[G.X]   x86_64-w64-mingw32,x86_64-pc-linux-gnu
[G..]   x86_64-ubuntu12.04-linux-gnu
[G..]   x86_64-ubuntu14.04-linux-gnu
[G..]   x86_64-ubuntu16.04-linux-gnu
[G..]   x86_64-unknown-linux-gnu
[G..]   x86_64-unknown-linux-uclibc
[G.X]   x86_64-w64-mingw32
[G..]   xtensa-fsf-linux-uclibc
 L (Local)       : sample was found in current directory
 G (Global)      : sample was installed with crosstool-NG
 X (EXPERIMENTAL): sample may use EXPERIMENTAL features
 B (BROKEN)      : sample is currently broken

我这里第一次尝试,于是选了x86_64-unknown-linux-gnu这个配置作为基础,然后做一些配置的修改;
关于这个x86_64-unknown-linux-gnu名称的含义,参考https://www.crifan.com/files/doc/docbook/cross_compile/release/html/cross_compile.html 文章对交叉编译的解释,写的很详细了,不再赘述

选择好了配置之后,查看配置的核心参数,使用命令:
ct-ng show-<sample> 选定某个配置,使用命令:
ct-ng <sample> 这个就是上面选择的“x86_64-unknown-linux-gnu”这一串字符,

接着,进入当前选择的模板的具体配置,可以查看和修改配置,使用命令: ct-ng menuconfig 会弹出一个配置界面,通过上下来移动,回车来进入选项,空格来打钩或取消打钩
这里头大部分都不用动,有几项关键的配置要改一下,

由于我做的是针对centOS8的linux系统的交叉编译工具链,所以所有的配置要尽量与centOS8的默认配置保持一致,这里请根据实际情况去查询各自的GCC版本、linux内核版本、binutils版本等

友情提示:一定要设置配套的GCC版本、linux内核版本、工具包版本,否则,后面构建过程中会出现很多不匹配的错误,而且改版本重新编译几乎等于要从头再来,这很浪费时间

记录几个linux系统下查看各种版本号的命令:

  1. 操作系统内核版本
uname -a

安装的各种包的版本

rpm -qa | grep xxx

xxx表示要查询的包的关键字

  1. gcc版本
gcc --version

查询到之后,就是去网上下载这些包的源码,由于官网下载通常比较慢,给一个gcc的镜像站网址:Index of /gcc/,去这里下会快很多

接下来就是去配置交叉编译工具链的各项属性,有很多设置需要了解一下

1.Paths and misc options菜单下

这个菜单下面有很多重要配置,

  •  [*] Try features marked as EXPERIMENTAL

这个配置选上之后,会增加一些新的配置,包括可以设置指定的内核版本、GCC版本等配置,如果你需要的这些版本在工具中并未提供,就需要勾上这个选项,去自定义你的配置版本,我这里就需要勾上这个选项

  •  [*] Debug crosstool-NG

这个选项表示调试相关的参数,勾上之后会在这行下面出现新的配置选项,其中,

  •  [*]   Save intermediate steps

一定要选上,这个选项的作用是,记录编译步骤,以便使你可以从之前出错那一步之前恢复继续编译,在编译的过程中,一定会遇到各种出错,一旦报错,就得解决问题之后再继续编译,这里如果不勾的话,每次解决完问题,只能从头开始,那会浪费很多时间

勾上这个选项后,怎么使用呢,每次执行完一个步骤后,会有如下类似的语句:

[INFO ]  Installing MPC for host
[EXTRA]    Configuring MPC
[EXTRA]    Building MPC
[EXTRA]    Installing MPC
[INFO ]  Installing MPC for host: done in 182.22s (at 27:10)
[EXTRA]  Saving state to restart at step 'binutils_for_host'...
[INFO ]  =================================================================
[INFO ]  Installing binutils for host
[EXTRA]    Configuring binutils
[ERROR]    configure: error: cannot create configure.lineno; rerun with a POSIX shell
[ERROR]
[ERROR]  >>
[ERROR]  >>  Build failed in step 'Installing binutils for host'
[ERROR]  >>        called in step '(top-level)'
[ERROR]  >>
[ERROR]  >>  Error happened in: CT_DoExecLog[scripts/functions@257]
[ERROR]  >>        called from: do_binutils_backend[scripts/build/binutils/binutils.sh@205]
[ERROR]  >>        called from: do_binutils_for_host[scripts/build/binutils/binutils.sh@92]
[ERROR]  >>        called from: main[scripts/crosstool-NG.sh@632]

其中的这句,

[EXTRA] Saving state to restart at step 'binutils_for_host'...

表明你的步骤执行到binutils_for_host这一步,那么,引号括起来的内容'binutils_for_host'就是关键字了,下次恢复编译时,使用命令: 

ct-ng binutils_for_host+    #从这一步开始并自动往后执行
ct-ng binutils_for_host     #只重新执行这一步
ct-ng +binutils_for_host    #重新执行到这一步

可以根据你的需要从新执行某个步骤,这样最大的好处是前面那些成功的构建步骤就不用了再重复了,强无敌,可即使这样,仍然很可能要花费很多时间来重复这个编译过程,慢慢来吧

另外还有一些配置,例如

  • (4) Number of parallel jobs

用于设置多线程编译,可以提高编译速度,虽然没有测试过,但我在设置了4个线程的情况下,从头到尾完整编译完一个编译器,基本上也要花数个小时

  • ()  Extra build compiler flags 

用于设置编译时传给编译器的参数,例如需要设置编译器使用的C++标准时,可以填写

-std=c++11
-std=gnu++11

 2.Operating System  ---> 菜单下

  • [*] custom tarball or directory

勾上之后,原来的选择操作系统内核版本号的选项会消失,同时出现两个新的可以设置的自定义的操作系统内核源码文件的路径和版本号的选项

 () Path to custom source, tarball or directory 
 () Custom Linux version 

在第一个选项中可以填写具体的源码压缩包的路径,比如:${HOME}/src/linux-4.18.tar.gz 

第二个选项中填写版本号

3.Binary utilities  --->菜单下

用于配置自定义的binutils版本的源码路径,与配置内核版本的方法类似,如下所示:

[*] Custom binutils                                              
(${HOME}/src/binutils-2.30.tar.bz2) Full path to custom binutils
(2.30) Binutils Custom Version number

4.C-library  --->菜单下

配置glibc自定义的版本的源码路径,与上述方法类似:

 [*] Custom glibc                                                 
(${HOME}/src/glibc-2.28.tar.bz2) Full path to custom glibc source
(2.28) Custom GLIBC version

 5.C compiler  --->菜单下

配置gcc自定义的版本的源码路径,与上述方法类似:

[*] Custom gcc                                                   
(${HOME}/src/gcc-8.4.0.tar.gz) Full path to custom gcc source    
(8.4.0) Custom GCC Version

  • 此处还有个配置:

*** Additional supported languages: ***

 [*] C++                                                          
 [ ] Fortran                                                      
 [ ] Java                                                        
 [ ] ADA (EXPERIMENTAL)                                          
 [ ] Objective-C (EXPERIMENTAL)                                 
 [ ] Objective-C++ (EXPERIMENTAL)                               
 [ ] Go (EXPERIMENTAL)                                           
 ()  Other languages (EXPERIMENTAL)   

配置额外支持的语言,根据实际需要选,我这里选C++就行了

以上就是需要注意的配置项,配置好以后,就可以编译了。

编译

使用命令:

ct-ng build

开始编译,过程中如果出现:
Extracting 'linux-custom' 的字样,建议终止编译过程,ctrl+c ,然后手动下载需要的软件包源码,否则让程序自动下载的速度可以说是非常慢了,当然,也不一定都很慢,下载链接的话,可以打开该build.log日志文件,在其中找到下载链接,然后去浏览器打开下载就行,通常会快很多,下载下来放到自动生成的tarballs文件夹下就行了,然后在使用恢复的命令或者build命令来恢复构建过程
等所有的下载都完成了,就可以放任他自己跑了。

编译过程出错的处理

参考的文章中列出了很多出错和解决办法,这里只列出我遇到的他文章里没有的出错

1.

version mismatch. This is Automake 1.15.1

Automake 版本不对, 使用 autoreconf -ivf 命令强制更新makefile中的配置

2.

'string' in namespace 'std' does not name a type

在对应文件中增加#include 的引用,是的你没有看错,我们直接改工具源码,不要怕

3.

no usable python found at /usr/bin/python

打开之前cygwin的安装程序,从中搜索python,在python目录下勾上python对应版本的devel文件,然后安装一下,安装好后从usr/include中找到名为pythonx.x的文件夹,然后放到/usr/bin下面去,如果没有文件夹就创造文件夹

4.

use of an operand of type 'bool' in 'operator++' is forbidden in C++17

遇到这个错,说明你的cygwin的gcc编译器使用的是c++17标准(我这里本地的gcc是11.0版本),与编译的源码使用的c++标准不一致,这个时候查询一下编译对象对应标准

我这里是编译gcc4.8.1的源码,而gcc4.8.1默认支持c++11,因此需要告诉本地gcc编译器,编译这个代码需要使用c++11标准,才能编译通过,因此在之前提到的

Paths and misc options

        ()  Extra build compiler flags

选项中去添加一个参数:-std=gnu++11

但我这里这样解决其实是乌龙,因为根本原因在于,我搞错了gcc版本,不是4.8.1,而是8.4.1,因此我不得不重新去下载gcc8.4.0的源码(所有官方的网站和镜像站都找不到8.4.1的源码,只能使用8.4.0),然后重新编译,因为gcc8.4.0就支持更高版本的c++标准,与我本地的编译器能够兼容,所以不需要这个额外的参数了

编译成功后:

最终编译完成,会在x-tools文件夹下找到对应的交叉编译器目录,然后要将编译器添加到环境变量中才能使用,把.bashrc的环境变量改为

PATH=$PATH:$HOME/.../x-tools/<templename>/bin:/opt/bin

就是你生成的交叉编译器目录名,...是你的路径,按实际情况填写
再去重启cygwin,然后试试命令:
 

<templename> -v

正确打印版本号信息说明配置正确,至此,恭喜你,交叉编译器生成成功了!