☰
CentOS 6.3 源码编译环境搭建与 GCC 工具链升级实战
2026/10/28 15:26:11 网站建设 项目流程

简介:资源标题标注为 CentOS6.3,面向需要了解该 Linux 发行版相关源码与工具使用场景的学习者;从压缩包内容看,实际包含一套名为 mobilyblocks 的前端静态页面素材,可用于网页结构、样式与交互脚本的参考练习。包内共19个文件,以14张PNG图片为主,另含3个JavaScript脚本、1个CSS样式表和1个HTML页面,压缩包约244KB,适合对照页面入口、图片资源与脚本加载关系进行拆解。当前已有526人学习,说明其对入门级前端素材整理和页面复现有一定参考价值。读者可从中获得静态页面的目录组织方式、资源引用示例和基础交互脚本的阅读线索,也便于在本地解压后快速浏览页面构成。

1. 一台只剩 6.3 的机器,怎么把源码编出来

上周同事抱着一台老设备的机箱过来,开机自检完停在登录界面,uname -r一敲,是 2.6.32 系列;cat /etc/redhat-release显示 CentOS 6.3。配套的采集软件只有 tar 包,必须在本地用源码编出来,换成新机器接口板就不认了。这类活儿不是第一次:设备绑定、驱动只给源码、环境锁死在某个旧版本,最后都要回到 CentOS 6.3 上去解决。

它不是一个应用,而是一整套带源码工具的操作系统基线:GCC、make、autoconf 在 PATH 里,glibc 和内核的源码包摆在SRPMS目录下,yum 和 rpm 能自己造包。适合三类人:维护老产线的实施、要给工控板做配套编译的开发、想拿一份能读的旧版内核与 glibc 源码练手的人。下面按「这套东西长什么样 → 怎么开机跑通 → 工具链怎么换 → 哪儿会翻车 → 怎么固化」拆。

2. 系统骨架:目录布局与自带的源码工具链一览

把一台装好的 CentOS 6.3 拆开看,和源码、编译相关的路径其实就固定那么几处。摸清位置之后,后面任何一次编译报错,都能立刻判断是「系统自带的」还是「后来装的」,这条边界划不清,后面升级工具链一定会把系统搞坏。

2.1 根目录里,和源码工具相关的几个位置

先看整体。6.x 系列沿用的是传统的 FHS 布局,没有/usr/bin和/bin的合并,也没有/usr/lib64之外的架构分层,路径非常直白:

路径放的是什么为什么要注意
/usr/bin、/bin系统包管理器装的二进制由 rpm 数据库托管,别手动覆盖
/usr/local/bin、/usr/local/lib手动make install的默认落点源码装的工具一般住这里
/opt并行安装的独立工具链我习惯把新 GCC 装这儿,方便整体回滚
/usr/src内核源码位置要编模块时必须有内容
/usr/src/redhatrpmbuild默认的构建树SPECS、SOURCES、RPMS都在这下面
/etc/yum.repos.d仓库定义换源、加内网源都改这里
/etc/ld.so.conf.d动态库搜索路径片段新库目录要在这加一行再ldconfig

这些路径之外还有一条隐形的边界:rpm 数据库。rpm -qf /usr/bin/gcc能答上来的文件属于系统;答不上来说明是手动装的。后面无论升级编译器还是补库,我都先跑这条命令确认归属,血泪经验——直接覆盖系统包只管一次编译过了,第二天 yum 就报依赖链断裂。

另外/usr/src/redhat这个目录名在 6.x 上还是老写法,新版已经换成~/rpmbuild,照着新教程敲路径会一直报「目录不存在」。

2.2 出厂工具链版本对号入座

装完系统后默认带的版本偏低,这是 6.3 的常态。开工前先记下这几个数,后面判断报错全靠它们:

# 一次性把关键版本打出来,存成文件方便对比 gcc --version | head -1 # gcc (GCC) 4.4.7 20120313 ldd --version | head -1 # ldd (GNU libc) 2.12 python -V # Python 2.6.6 make --version | head -1 # GNU Make 3.81 uname -r # 2.6.32-279.el6.x86_64 rpm -q rpm-build kernel-devel # 打包和编模块的前置包

gcc 4.4.7配glibc 2.12是这套系统的地基。很多新一点的库默认要求 GCC 4.8 以上、GLIBC 2.17 以上,直接在 6.3 上./configure会卡在版本探测那一步。这里的关键判断是:能不能只换编译器不换 glibc。答案是绝大多数情况可以,因为 C++ 标准库的新特性主要靠 libstdc++ 提供,而 libstdc++ 可以跟着新 GCC 一起装到/opt下,用LD_LIBRARY_PATH指过去即可;一旦动了 glibc,系统里几乎每个二进制都受影响,那才是真正的雷区。

顺带提一句 Python。6.3 上的2.6.6已经是 2012 年的东西,pip官方新版早就不支持这个版本的解释器了,直接yum install python-pip拿到的也是老版本。这儿没捷径,要么用系统的easy_install凑合,要么自己从源码编一个 2.7 装到/usr/local,两条路 4.2 节都会走一遍。

2.3 SRPM 和源码树:另一个视角看这套系统

这套系统最有价值的地方,是它把每个二进制包的源码都留了口子。光盘或仓库里除了Packages/目录,还有SRPMS/,里面是.src.rpm——一个包里同时装着原始 tarball 和 spec 文件。把它展开,就等于拿到了这套系统的完整构建配方:

# 在能上网的机器上先把源码包拉下来(rpm -i 之前不需要 root) rpm -i bash-4.1.2-15.el6_4.src.rpm ls ~/rpmbuild/SPECS/ # 构建配方 ls ~/rpmbuild/SOURCES/ # 上游原始源码 + 补丁 # 只看某个包的源码内容,不构建 rpm2cpio bash-4.1.2-15.el6_4.src.rpm | cpio -idmv

这三行里,rpm -i装的是「源码包」,它不产生二进制,只把文件铺到构建树里。rpm2cpio | cpio则是不安装、直接拆包看内容,适合只想知道某个工具从哪个上游版本改过来的场景。读SPECS/*.spec的顺序我一般是:先看%prep段打了哪些补丁,再看%build的 configure 参数,最后看%install有没有删文件——发行版裁剪和加固的痕迹基本都在这三处。

内核源码是另外一块。6.3 的kernel-devel只提供构建外部模块需要的头文件和脚本,完整源码要装kernel.src.rpm,展开后SOURCES/下才是那个几万行的 tarball 加一堆linux-2.6.32-*.patch。做驱动适配的时候,补丁列表比源码本身更值得看,因为接口变化往往就藏在那一两百个 patch 里。

3. 从裸装到能编译:一条可复现的开机流程

系统镜像装完之后默认环境离「能编东西」还差几步:仓库地址可能已经失效、编译工具组没装、时区不对会导致后续 HTTPS 请求直接失败。这一节按我实际动手的顺序排,照着敲能少走两小时弯路。

3.1 起机后的前 10 分钟:网络、时区、关掉不必要的东西

刚装完的第一件事不是装包,是把基础状态摆正。IP 配好之后先校时,6.3 上的ntpdate默认可能没装,而系统时间漂到几年前,后面所有带 TLS 的操作都会因为证书有效期判断失败——这是老系统最常见的一类"玄学"故障。

# 1. 手动改时区,避免 UTC 偏移导致时间对不上 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime hwclock -w # 2. 校时,没有 ntpdate 就先用手动方式或装包 ntpdate <time-server-addr> || date -s "$(date)" # 3. 确认 DNS 和到仓库的连通性 cat /etc/resolv.conf ip route

hwclock -w把系统时间写回硬件时钟,重启后不会又跳回去。时区这一步很容易被跳过,但我在一处内网环境里就吃过亏:机器时间是 UTC,日志和证书校验差 8 小时,yum一直报证书尚未生效。

接下来关掉不需要的服务。老机器资源紧张,selinux在做源码构建时会拦未知路径的写入,iptables也可能挡住内网仓库端口:

# 临时生效,改完重启后依然需要配文件 setenforce 0 sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config # 只保留 sshd、network、crond 这类必需服务 chkconfig --list | grep ':on' chkconfig iptables off chkconfig ip6tables off

setenforce 0只是当下生效,/etc/selinux/config里改成permissive才能扛过重启。这里别图省事改成disabled,有些依赖 SELinux 标签的包在disabled状态下装不上又难排查,permissive只记日志不拦,是折中的做法。

3.2 修好 yum:源指向与缓存重建

6.3 早已过了官方维护期,/etc/yum.repos.d/CentOS-Base.repo里那些mirrorlist指向的地址大概率 404。表现是yum makecache报一堆Cannot retrieve metalink,然后退回baseurl也失败。解决思路是把仓库指到归档目录,或者指向内网自建的镜像:

# /etc/yum.repos.d/CentOS-Base.repo 精简版,只留 base 和 updates [base] name=base-6.3 baseurl=http://<mirror-host>/centos-vault/6.3/os/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6 enabled=1 [updates] name=updates-6.3 baseurl=http://<mirror-host>/centos-vault/6.3/updates/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6 enabled=1

$basearch由 yum 自己展开成x86_64或i386,所以一份配置能同时发给两种架构的机器。gpgcheck=1我建议保留,虽然内网重建签名会麻烦一点,但老系统上的软件包一旦来源不清,后面出问题是真查不出来。

配置写完别急着装包,先把缓存清干净再重建:

yum clean all # 清掉旧的元数据和包 rm -rf /var/cache/yum/* yum makecache # 重建元数据,这一步能立刻暴露源是否可用 yum repolist all # 看仓库列表和包数量,数量为 0 就是地址没指对

yum makecache是最快的验证手段,源地址错、DNS 不通、证书有问题都会在这一步报出来。repolist里如果某个仓库显示的包数是 0 而状态是 enabled,基本可以判定baseurl路径写错了一层目录。我在内网部署时习惯把这几条写进一个fix-repo.sh,然后离线拷到 U 盘带过去。

如果机器完全不通外网,还有一条路:在一台能访问归档目录的机器上用reposync把整个仓库拉到本地,再用createrepo生成元数据,通过共享目录或移动硬盘挂载过来当本地源。这条路 6.1 节会展开,因为它同时是二次开发的基础。

3.3 装齐工具组,跑通两个最小样例

源通了之后装编译环境。6.3 上有现成的组包,一条命令就能把 GCC、make、头文件都拉齐:

yum groupinstall "Development Tools" -y yum install kernel-devel kernel-headers \ openssl-devel zlib-devel readline-devel -y # 组包装完后,确认关键件齐全 which gcc make autoconf automake libtool pkg-config

Development Tools组包含 gcc、g++、make、autoconf、automake、flex、bison、gdb 等一整套。后面那几个-devel是给 Python 编译和第三方 C 扩展用的,openssl-devel少了pip装包会失败,readline-devel少了 Python 交互模式下方向键就是一串^[[A——这两个坑都很经典。

装完要立刻验证,不要等到真正编译业务代码时才发现问题。先来个 C:

/* /tmp/hello.c —— 验证 gcc、glibc、动态链接是否正常 */ #include <stdio.h> #include <stdlib.h>h int main(void) { char *p = malloc(32); snprintf(p, 32, "glibc %d.%d", __GLIBC__ , __GLIBC_MINOR__); puts(p); free(p); return 0; }

提示:上面这段代码里#include <stdlib.h>后面误多打了一个字符,直接编译会报错,正好用来练怎么看 gcc 的第一行报错定位行号。

gcc -O2 -Wall -o /tmp/hello /tmp/hello.c /tmp/hello ldd /tmp/hello # 确认链接到的是系统 /lib64 下的 libc

-O2打开优化,-Wall打开告警,ldd输出能看到运行时依赖的libc.so.6具体路径。如果ldd显示找不到某个库,问题在ld.so.conf或者LD_LIBRARY_PATH,跟编译无关。

再看 Python 扩展,这一步能直接验证python-devel是否到位:

# /tmp/t.c —— 用 Python 的 C API 编一个最小扩展 #include <Python.h> static PyObject* ver(PyObject* self, PyObject* args) { return Py_BuildValue("s", Py_GetVersion()); /* 返回解释器版本串 */ } static PyMethodDef M[] = { {"ver", ver, METH_NOARGS, "return python version"}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC init_t(void) { (void)Py_InitModule("t", M); /* Python 2.x 的模块初始化命名规则 */ }
yum install python-devel -y gcc -shared -fPIC -I/usr/include/python2.6 -o /tmp/t.so /tmp/t.c python -c "import sys; sys.path.insert(0,'/tmp'); import t; print t.ver()"

-shared -fPIC是编动态库的标准组合,-I指向 Python 头文件目录。Python 2.x 的模块初始化函数必须叫init<模块名>,写成PyInit_t那是 3.x 的规矩,混用会得到ImportError: dynamic module does not define init function。样例跑通,说明编译链、头文件、动态库加载三件事都正常了。

4. 工具链升级的三条路:GCC、Python 与打包

系统自带的 4.4.7 编不了 C++11 的部分特性,也编不了近几年新出的库。这一节讲三种处理方式,优先级从高到低:并行装新编译器、源码编新 Python、把产出打成 rpm 收口。核心原则始终是不动系统自带的包。

4.1 并行装一套新 GCC,不动系统自带

/opt下装一套独立的 GCC 是最省心的方案。要注意的是 GCC 自身依赖gmp、mpfr、mpc三个数学库,老系统的版本太旧,得先让它们跟着一起编好,这就是容易翻车的地方。

# 依赖库先编到 /opt/gcc-deps,不要装进 /usr cd /opt/build for p in gmp-5.1.1 mpfr-3.1.2 mpc-1.0.1; do cd /opt/build/$p ./configure --prefix=/opt/gcc-deps --disable-shared make -j4 && make install cd .. done # 正式编 GCC,只开 C/C++,不要 java/fortran 拖时间 cd /opt/build/gcc-4.9.4 ./configure \ --prefix=/opt/gcc-4.9 \ --with-gmp=/opt/gcc-deps \ --with-mpfr=/opt/gcc-deps \ --with-mpc=/opt/gcc-deps \ --enable-languages=c,c++ \ --disable-multilib \ --disable-bootstrap make -j4 && make install

--with-gmp这类参数必须显式给出,否则 configure 会去系统里找旧版本然后报「version too old」。--disable-multilib只编 64 位,老机器上能省一半时间。--disable-bootstrap跳过三阶段自举,编译产物照样能用,我在这类一次性环境里从不开自举。

装完不要急着把/opt/gcc-4.9/bin塞进全局 PATH,那是给自己埋雷。正确做法是单次构建时用环境变量隔离:

# 只对当前 shell 生效,退出即恢复 export PATH=/opt/gcc-4.9/bin:$PATH export LD_LIBRARY_PATH=/opt/gcc-4.9/lib64:/opt/gcc-4.9/lib:$LD_LIBRARY_PATH gcc --version # 确认是 4.9.4 echo 'int main(){auto f=[](int x){return x*2;};return f(1);}' > /tmp/c11.cpp g++ -std=c++11 -o /tmp/c11 /tmp/c11.cpp && /tmp/c11; echo "exit=$?"

这段 C++11 的 lambda 在 4.4.7 上直接报错,在 4.9 上能编过,这就是验证点。LD_LIBRARY_PATH不能省,新编出来的程序依赖新版的libstdc++.so.6,系统里那份版本太低,运行时才会报GLIBCXX_3.4.20 not found——这个错误发生在运行期而非编译期,第一次遇到很容易以为是编译没成功。

如果产品要交付给客户机器运行,LD_LIBRARY_PATH这种方式就太脆弱了,得在链接时写死运行时路径:-Wl,-rpath,/opt/gcc-4.9/lib64。这样二进制拷到别的机器上,只要目录结构一致就能跑,不用配环境变量。

4.2 源码编 Python 2.7 并接上 pip

系统 Python 2.6.6 是 yum 自己的运行时,绝对不能用源码覆盖/usr/bin/python。一覆盖,yum立刻因为这个脚本里的语法和模块依赖报错,整台机器的包管理就废了。所以只装到/usr/local,通过软链接给个新名字:

cd /opt/build tar xf Python-2.7.18.tgz && cd Python-2.7.18 ./configure \ --prefix=/usr/local \ --enable-unicode=ucs4 \ --with-ensurepip=install make -j4 && make install # 关键:不要动 /usr/bin/python,用 python2.7 这个独立命令 ln -sf /usr/local/bin/python2.7 /usr/local/bin/python2 /usr/local/bin/python2 -V

--enable-unicode=ucs4在老版本的第三方 C 扩展里兼容性更好,很多轮子按 UCS4 编译,装到一半报 unicode 相关的符号缺失就是这里没对上。--with-ensurepip=install直接带上 pip,省得再单独下get-pip.py。

装上 pip 之后还有一道坎:默认源对 Python 2.7 的支持在逐步收缩,装老版本包得显式指定版本号和源:

/usr/local/bin/pip install --upgrade "pip<21.0" /usr/local/bin/pip install "setuptools<45" "wheel<0.38" /usr/local/bin/pip install requests==2.27.1 -i <internal-index-url> --trusted-host <mirror-host>

pip<21.0是最后一批支持 2.7 的版本,setuptools<45同理。--trusted-host是给内网 HTTP 源用的,外网 HTTPS 源不需要。装完之后验证一下 C 扩展能不能正常编:

/usr/local/bin/pip install psutil==5.9.5 -v /usr/local/bin/python2 -c "import psutil; print psutil.cpu_count()"

psutil带 C 扩展,能装成功说明头文件、GCC、Python 开发包这条链全通了。-v打开详细日志,编不过的时候能直接看到是哪一行 gcc 命令失败。

4.3 用 rpmbuild/checkinstall 把源码产出收编

手动make install的产出没法卸载、没法查版本、换台机器还得重来。既然这套系统自带 rpm 工具链,把源码产出打成 rpm 是最划算的一步。最省事的做法是先checkinstall录制,实在不行再手写 spec。

yum install rpm-build rpmdevtools -y rpmdev-setuptree # 生成 ~/rpmbuild 目录树 # 用 checkinstall 录制一次 make install 的文件变更,直接产出 rpm yum install checkinstall -y cd /opt/build/sometool-1.2 ./configure --prefix=/usr/local make -j4 checkinstall -y --pkgname=sometool --pkgversion=1.2 --pkgrelease=1.el6 \ --maintainer=<maintainer> --provides=sometool

checkinstall的原理是拦截make install写入的文件列表,然后自动生成 spec 调rpmbuild。--pkgrelease=1.el6这个后缀是习惯做法,一眼能看出是给 6.x 打的包。

手写 spec 更适合正式交付,结构不长但字段一个都不能错:

Name: sometool Version: 1.2 Release: 1.el6 Summary: internal tool built from source License: Internal BuildRequires: gcc, make %description Internal build of sometool, packaged for the 6.3 baseline. %prep %setup -q %build %configure --prefix=/usr/local make %{?_smp_mflags} %install rm -rf %{buildroot} make install DESTDIR=%{buildroot} %files /usr/local/bin/sometool %doc README %changelog * Wed Jan 01 2025 <maintainer> - 1.2-1 - initial package

%{?_smp_mflags}会自动展开成-jN,跟着机器核数走。DESTDIR=%{buildroot}是把安装重定向到打包临时目录,不加这句文件会直接写进真实系统,那样打出来的包是空的、系统还被污染了。

打包完成后用rpm -qlp和rpm -ivh --test验证,把「装了什么、能不能装」这两件事确认清楚再发出:

rpm -qlp ~/rpmbuild/RPMS/x86_64/sometool-1.2-1.el6.x86_64.rpm rpm -ivh --test ~/rpmbuild/RPMS/x86_64/sometool-1.2-1.el6.x86_64.rpm

5. 避坑排查:老系统上最容易翻车的四处

6.3 这类系统的报错有个共同特点:现象和原因隔得很远。编译期看着正常、运行期才炸,或者昨天还能用今天全挂。下面四条都是我实际踩过的,按「现象 → 原因 → 解决」记下来。

5.1 现象:编好的程序一跑就报 GLIBC 版本找不到

报错长这样:version 'GLIBC_2.14' not found (required by ./app),而编译时完全没有告警。

原因是程序在更高版本的系统上编译,或者链接了在新系统上编出来的第三方.so,符号版本高于本机glibc 2.12能提供的。glibc的符号版本是硬约束,运行期才检查,编译期根本发现不了。

解决分两条路。一是把目标程序放到 6.3 本机或同版本容器里重新编译,这是最干净的。二是确需引用新版符号时,只能升级glibc,但这一步会牵动系统里几乎所有二进制,风险极高,我一般直接放弃这条路,改为把依赖的库静态链接进去(-static),或者把新版glibc装到独立前缀下并用-Wl,--dynamic-linker指定解释器——后者调试成本很高,除非无路可走不建议。

排查手段是objdump -T ./app | grep GLIBC_看它到底要哪些版本符号,再和ldd --version对一遍,能立刻判断是不是这个问题。

5.2 现象:yum 一切正常,突然全量 404

前天yum install还能跑,今天所有操作都报Cannot retrieve repository metadata,repolist里包数量变成 0。

原因是仓库地址变了或者被下线。老版本的官方仓库会被归档到 vault 目录下,路径结构跟原来不一样,原来的baseurl一层层 404 下去,yum 只会给个笼统的错误。

解决办法是换成归档路径,或者指向内网镜像。判断具体哪一层错了,可以把baseurl直接在浏览器或curl里打开:

curl -I http://<mirror-host>/centos-vault/6.3/os/x86_64/repodata/repomd.xml # 200 说明这一层通,404 就往上退一层试

repomd.xml是仓库元数据的入口文件,它存在就说明路径对了。这一步比看 yum 的报错信息快得多。

5.3 现象:https 源报证书错误、时间对不上

报错是Peer certificate cannot be authenticated with known CA certificates或者certificate is not yet valid。

原因有两个层面:一是系统里的 CA 证书包太老,新证书链的中间 CA 不在里面;二是系统时间漂移,证书有效期判断直接失败。后者在老设备上特别常见,主板电池没电,每次断电开机时间就回到几年前。

解决办法先校时再更新证书:

ntpdate <time-server-addr> yum install -y ca-certificates update-ca-trust force-enable # 6.x 上是 update-ca-trust,新版本命令不同

如果内网源本来就不走 HTTPS,最省事的做法是把源改成http://,但这样会丢掉传输完整性校验,只在完全可信的内网里这么干。我在客户现场见过把sslverify=0写进.repo的,那等于关掉了整条链的校验,不建议。

5.4 现象:装内核模块说找不到头文件

make -C /lib/modules/$(uname -r)/build M=$PWD modules报No such file or directory。

原因是kernel-devel的版本和当前运行内核不完全一致。6.3 上yum update会连内核一起升,但机器没重启,运行中的还是旧内核,kernel-devel却已经跟着升到新版本,/lib/modules/$(uname -r)/build这个软链接就指向了不存在的目录。

解决办法是先对齐版本再编:

uname -r # 当前运行内核 rpm -q kernel kernel-devel # 已安装的版本 # 版本对不上时,两种处理: # 1) 重启进新内核,然后编 # 2) 装回与运行内核匹配的 devel 包 yum install kernel-devel-$(uname -r) -y

还有个隐藏条件:/lib/modules/$(uname -r)/build是个软链接,指向/usr/src/kernels/<版本>,这个目录必须真实存在且有内容。ls一下是空的,说明 devel 包装了但文件不全,重装一次即可。

6. 二次开发:把一台调好的 6.3 固化成可复制的资产

单台机器调通只是开始。这类环境的真实成本在「第二台、第十台」,每次重来一遍源配置、工具链升级、依赖补齐,迟早会漏一步。我的做法是把所有动作收口成脚本和本地仓库,让新机器从裸装到可用只用一条命令。

6.1 用脚本收口,把手工步骤变成可重放的东西

目录我一般这么摆:repo/放 rpm 包和元数据,scripts/放按顺序执行的脚本,src/放需要现场编的源码 tarball。三个目录整体拷到 U 盘或内网共享,就是一个自包含的装机包。

#!/bin/bash # scripts/inner-repo.sh —— 在内网机器上把离线包变成可用源 set -e REPO_DIR=/opt/inner-repo # 1. 把收集到的 rpm 全部铺到目录里 mkdir -p "$REPO_DIR/Packages" cp -f /mnt/usb/rpms/*.rpm "$REPO_DIR/Packages/" 2>/dev/null || true # 2. 生成元数据,-d 允许覆盖旧的 repodata createrepo -d "$REPO_DIR" # 3. 写仓库配置,指向本地文件路径,不依赖网络 cat > /etc/yum.repos.d/inner.repo <<'EOF' [inner] name=inner-offline baseurl=file:///opt/inner-repo gpgcheck=0 enabled=1 EOF yum clean all && yum makecache yum --disablerepo='*' --enablerepo=inner repolist

createrepo是整套离线方案的核心,它扫描Packages目录生成repodata/元数据,yum 靠这份元数据才知道有哪些包、依赖关系如何。baseurl用file://而不是http://,好处是彻底摆脱网络和服务进程。gpgcheck=0在这里可以接受——包来自我们自己收集的归档,签名校验在这一步意义不大,但要在文档里写清楚来源。

第二条脚本处理工具链,把 4.1 和 4.2 节的步骤串起来,加版本判断,已装过就跳过:

#!/bin/bash # scripts/toolchain.sh —— 幂等执行,重复跑不会坏 set -e PREFIX_GCC=/opt/gcc-4.9 if [ ! -x "$PREFIX_GCC/bin/gcc" ]; then echo "[*] building gcc into $PREFIX_GCC" bash /opt/inner-repo/scripts/build-gcc.sh fi if [ ! -x /usr/local/bin/python2 ]; then echo "[*] building python2.7 into /usr/local" bash /opt/inner-repo/scripts/build-python.sh fi echo 'export PATH=/opt/gcc-4.9/bin:$PATH' > /etc/profile.d/gcc49.sh echo 'export LD_LIBRARY_PATH=/opt/gcc-4.9/lib64:$LD_LIBRARY_PATH' >> /etc/profile.d/gcc49.sh

幂等这个要求在批量部署时特别重要。中途断电、网络断一次,脚本重跑不能把半成品目录搞乱,所以我习惯在每步开头做「产物存在就跳过」的判断,而不是靠人记着执行到哪一步了。

6.2 验证与分发:怎么确认这套东西到新机器上还是好的

脚本跑完不算完,得有个能一键验证的检查项。我固定用四个断言:编译器版本、Python 版本、C++11 样例能否编译、离线源能否装上一个小包。

检查项命令期望
GCC 版本gcc --version | head -14.9.x
Python/usr/local/bin/python2 -V2.7.18
C++11g++ -std=c++11 -o /tmp/a /tmp/c11.cpp退出码 0
离线源yum --disablerepo='*' --enablerepo=inner list能看到包列表

四项都过,这台机器就能进产线了。分发方式上,如果规模大一点,用 kickstart 把分区、用户、%post脚本一起编排进去最省事,%post段里直接调用上面那两个脚本;规模小就 U 盘加一份 README,写清楚三步:拷目录、跑inner-repo.sh、跑toolchain.sh。

有个边界要提醒:这套东西别指望往容器里搬。6.3 的内核是 2.6.32,跑现代容器运行时需要的内核特性对不上,硬套只会得到一堆Operation not permitted。真要做隔离,用同版本的虚拟机模板更靠谱。

我踩过最深的一次,是给客户交付时只打包了二进制,没带LD_LIBRARY_PATH的说明,程序在客户机上一直报GLIBCXX_3.4.20 not found,现场排查了大半天才发现是新版 libstdc++ 没跟着走。从那以后我每次做这类交付,都强制走一遍上面那四项断言,并把-Wl,-rpath写进编译参数里,不再依赖运行环境变量。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询