简介这份资源面向在 openSUSE 12.3 系统上需要安装或修复 GCC 编译环境的开发者与运维人员尤其适合仍在使用该老版本发行版、受限于离线环境或软件源失效而无法正常安装编译工具链的用户。资源包共 86 个文件以 gz 压缩包、asc 签名文件、key 密钥文件为主另含 patterns、media、content 及 xml 等元数据整体约 22.53MB覆盖 32 位与 64 位两套目录结构。其核心价值在于将 var.cache.zypp.raw 下的仓库缓存完整打包包含 openSUSE-12.3-1.7、repo-oss、repo-non-oss、repo-update 及 repo-update-non-oss 等仓库的 repodata 与签名信息读者只需将其拷贝至 /var/cache/zypp/raw 即可借助 zypper 完成 GCC 安装省去联网配置源的繁琐步骤。目前已有 911 人学习下载适合需要快速恢复编译环境、排查依赖缺失问题的用户参考使用。1. openSUSE 12.3 上装 GCC一个被 32 位和 64 位同时卡住的真实场景openSUSE 12.3 是 2013 年发布的版本官方早已停止维护源地址大面积失效。现在还在碰它的多半是维护老旧工控设备、跑遗留编译链或者接手了一套只能在特定内核上编译的代码。问题往往出在同一台机器上主系统是 64 位但目标程序要出 32 位产物于是gcc和gcc-32bit得同时装好缺一个就报skipping incompatible。更麻烦的是默认的在线仓库已经连不上zypper install gcc直接超时。这篇笔记就围绕 openSUSE 12.3 这个特定版本把 32 位与 64 位 GCC 的安装资源、离线源配置、多架构编译验证讲清楚适合手里还压着这台老系统、又必须让它继续出包的工程师。2. 先搞清楚 openSUSE 12.3 的 GCC 资源到底在哪2.1 为什么在线源基本不可用必须走离线或本地镜像openSUSE 12.3 的生命周期在 2015 年就结束了官方download.opensuse.org上对应版本的仓库目录早已被清理。你如果直接执行zypper refresh大概率会看到Repository openSUSE-12.3-Update is invalid或者连接超时。这不是网络问题是源本身没了。常见做法是找当年完整的 DVD ISO 或者归档镜像站里的repo/oss目录把它挂载到本地或者拷到硬盘上再用zypper ar添加为本地仓库。我一般会优先用 ISO 挂载因为 DVD 里已经包含了gcc、gcc-32bit、gcc-c以及对应的glibc-devel静态库省得一个个补依赖。需要留意的点是openSUSE 12.3 的 32 位支持并不是单独一个gcc-32bit包就完事。它依赖glibc-devel-32bit、libstdc-devel-32bit这一整套。如果你只装gcc-32bit而不装对应的 32 位开发库编译时会在链接阶段报cannot find -lc或者cannot find -lstdc。所以资源清单里必须同时包含这两类包。2.2 32 位与 64 位 GCC 在 openSUSE 12.3 上的包名差异在 openSUSE 12.3 的仓库里64 位 GCC 的主包名就是gcc它默认提供 64 位编译能力。而 32 位编译能力由gcc-32bit提供这个包本身不包含完整的编译器前端它依赖主gcc包只是补上了 32 位的crtbegin.o、crtend.o以及libgcc.a的 32 位版本。换句话说你不能只装gcc-32bit就指望能编 32 位程序必须两个都装。另外如果你要编 C对应的包是gcc-c和gcc-c-32bit。这里有个容易翻车的点gcc-c-32bit在部分镜像里可能缺失因为当年 32 位 C 开发库的打包并不总是完整。如果确实找不到退而求其次的做法是手动从 32 位 ISO 里提取libstdc-devel-32bit但这条路比较绕后面避坑章节会细说。2.3 用 zypper 添加本地 ISO 源的最小命令假设你已经把 openSUSE 12.3 的 DVD ISO 放到了/root/openSUSE-12.3-DVD-x86_64.iso下面这套命令可以直接抄# 创建挂载点 mkdir -p /mnt/opensuse123 # 挂载 ISO注意用 loop 模式 mount -o loop /root/openSUSE-12.3-DVD-x86_64.iso /mnt/opensuse123 # 添加本地仓库名称随便起但后面要引用 zypper ar -f file:///mnt/opensuse123 openSUSE-12.3-Local # 刷新仓库此时应该不再走网络 zypper refresh # 查看仓库里有没有 gcc 和 gcc-32bit zypper search gcc | grep -E ^gcc|gcc-32bit这段逻辑的核心是file://协议它让 zypper 直接读挂载目录不碰网络。-f表示启用自动刷新但本地源其实刷不刷都一样。执行完zypper search后你应该能看到gcc、gcc-32bit、gcc-c、gcc-c-32bit这几个包名。如果gcc-32bit没出现说明你挂的 ISO 是纯 64 位版需要换一张包含 32 位包的 DVD 或者额外挂 32 位 ISO。提示openSUSE 12.3 的 DVD ISO 通常同时包含 32 位和 64 位包但文件名里带x86_64的镜像不一定全。如果搜不到先确认 ISO 来源。3. 安装 GCC 与 32 位支持从 zypper 到手动补包3.1 一条命令装齐 64 位和 32 位 GCC 的依赖树在本地源可用的情况下安装命令本身不复杂# 安装 64 位 GCC、C 前端以及 32 位支持包 zypper install gcc gcc-c gcc-32bit gcc-c-32bit glibc-devel-32bit libstdc-devel-32bit这里每个包的作用需要说清楚。gcc是 64 位编译器主体gcc-c提供g前端。gcc-32bit补上 32 位的启动文件和libgccgcc-c-32bit补 32 位 C 启动文件。glibc-devel-32bit提供 32 位的crt1.o、crti.o以及libc.so链接脚本没有它32 位链接必挂。libstdc-devel-32bit则是 32 位 C 标准库的开发文件。如果 zypper 提示某个包找不到先别急着放弃。用zypper search -s gcc-32bit看看是不是包名有细微差别比如有些镜像里叫gcc32或者gcc-32bit-devel。openSUSE 12.3 的包命名整体还算规范但第三方重建的镜像可能改过名。3.2 验证 64 位编译一个最小 C 程序加file检查装完之后不要假设它一定能用先编一个 64 位程序验证/* test64.c */ #include stdio.h int main(void) { printf(hello 64-bit\n); return 0; }编译并检查产物架构gcc -m64 test64.c -o test64 file test64file的输出里应该出现ELF 64-bit LSB executable, x86-64。如果出现ELF 32-bit说明你的gcc默认被配成了 32 位这通常是因为环境变量或者 spec 文件被改过。可以用gcc -v看Target:那一行正常应该是x86_64-suse-linux。3.3 验证 32 位编译-m32参数与常见链接错误32 位验证用同一个源码但加-m32gcc -m32 test64.c -o test32 file test32预期输出是ELF 32-bit LSB executable, Intel 80386。如果这一步报错最常见的两类是第一类fatal error: bits/libc-header-start.h: No such file or directory。这说明glibc-devel-32bit没装好或者头文件搜索路径没包含 32 位目录。openSUSE 12.3 的 32 位头文件通常在/usr/include/gnu和/usr/include/bits下但 32 位版本可能放在/usr/include/gnu-32之类的路径需要确认包是否完整。第二类cannot find -lgcc或者cannot find -lc。这是链接器找不到 32 位库。用gcc -m32 -print-file-namelibgcc.a看看它返回的路径是否存在。如果返回的只是一个文件名而不是绝对路径说明gcc-32bit没装或者装的位置不对。3.4 用gcc -print-multi-lib看多架构支持是否完整openSUSE 12.3 的 GCC 支持--print-multi-lib这个命令能直接告诉你当前编译器支持哪些架构变体gcc -print-multi-lib正常输出应该包含两行类似.; 32;m32第一行.表示默认 64 位第二行32;m32表示通过-m32可以切换到 32 位。如果只有.一行说明 32 位支持没装进去。这个检查比编程序更快适合装完先跑一下。注意有些 openSUSE 12.3 的 GCC 版本在-print-multi-lib里显示的是32;m32但实际链接时仍然缺库。所以这个命令只能作为初步判断最终还是要用-m32编一个真实程序。4. 避坑与排查openSUSE 12.3 装 GCC 时最容易翻车的 5 个点4.1 现象zypper install gcc报错Package gcc not found原因本地源没添加成功或者 ISO 挂载后目录结构不对。openSUSE 12.3 的 DVD 里仓库根目录通常是/mnt/opensuse123/suse/x86_64/和/mnt/opensuse123/suse/i686/但 zypper 需要的是包含repodata的目录。如果你直接挂到/mnt/opensuse123而repodata在子目录里zypper 就找不到包。解决用find /mnt/opensuse123 -name repodata -type d找到正确路径然后重新zypper ar指向那个目录。或者直接挂载到包含repodata的那一层。4.2 现象32 位编译时报skipping incompatible /usr/lib64/libc.so原因链接器默认去 64 位库目录找 32 位库当然找不到。这通常是因为gcc-32bit装了但glibc-devel-32bit没装导致 32 位的libc.so链接脚本缺失。解决确认glibc-devel-32bit已安装然后用gcc -m32 -print-file-namelibc.so看它返回什么。如果返回/usr/lib64/libc.so说明搜索路径错了。可以手动加-L/usr/lib试试但根本办法还是补装 32 位开发库。4.3 现象gcc -m32提示unrecognized command line option -m32原因你装的gcc是一个纯 64 位构建没有启用多架构支持。这在某些第三方重建的 openSUSE 12.3 镜像里会出现因为打包者编译 GCC 时没加--enable-multiarch或者没装 32 位目标库。解决换用官方 DVD ISO 里的gcc包或者从 32 位 ISO 里提取gcc-32bit手动安装。如果实在找不到可以考虑用gcc -m32的替代方案装一个 32 位的交叉编译器但 openSUSE 12.3 仓库里不一定有。4.4 现象装完gcc-32bit后gcc -v显示的版本和之前不一样原因gcc-32bit可能依赖一个特定版本的gcc而你的系统里已经装了另一个版本。zypper 在解决依赖时可能降级或升级了主gcc包导致版本变化。解决用rpm -qa | grep gcc列出所有 gcc 相关包确认版本一致。如果出现两个不同版本的gcc和gcc-32bit用zypper install --force gcc-32bit强制对齐或者手动指定版本号安装。4.5 现象编译 32 位 C 程序时链接阶段报undefined reference to std::__cxx11::...原因libstdc-devel-32bit没装或者装了但版本和 64 位的libstdc不一致。openSUSE 12.3 的 GCC 4.7 默认使用旧 ABI但如果你混用了不同来源的库就可能出现 ABI 不匹配。解决确认libstdc-devel-32bit已安装并且版本号和gcc-c一致。用rpm -qa | grep libstdc检查。如果还是报错尝试在编译时加-D_GLIBCXX_USE_CXX11_ABI0强制使用旧 ABI。5. 进阶用--sysroot隔离 32 位与 64 位头文件避免互相污染5.1 为什么要用 sysroot 而不是直接-m32在 openSUSE 12.3 上32 位和 64 位的头文件都装在/usr/include下但有些头文件会根据架构做条件编译。如果你在同一个 shell 里交替编 32 位和 64 位程序偶尔会遇到头文件缓存或者宏定义冲突尤其是gnu/stubs.h这种会根据__x86_64__切换的文件。虽然 GCC 本身会处理大部分情况但如果你手动改过CFLAGS或者用了pkg-config就可能翻车。一个更干净的做法是准备一个 32 位的 sysroot 目录把 32 位头文件和库都放进去编译时用--sysroot指定。这样 32 位编译完全不会碰到 64 位的头文件。5.2 构建最小 32 位 sysroot 的步骤# 创建 sysroot 目录结构 mkdir -p /opt/sysroot32/usr/include mkdir -p /opt/sysroot32/usr/lib mkdir -p /opt/sysroot32/lib # 从已安装的 32 位包中拷贝头文件注意用 rpm 查询文件列表 rpm -ql glibc-devel-32bit | grep \.h$ | while read f; do # 去掉前缀拷到 sysroot 对应位置 dest/opt/sysroot32${f} mkdir -p $(dirname $dest) cp -a $f $dest done # 拷贝 32 位库文件 rpm -ql glibc-32bit | grep \.so | while read f; do dest/opt/sysroot32${f} mkdir -p $(dirname $dest) cp -a $f $dest done这段脚本的逻辑是用rpm -ql列出 32 位包里的所有头文件和库文件然后按原路径拷贝到/opt/sysroot32下。这样 sysroot 里就有一套完整的 32 位开发环境。编译时用gcc -m32 --sysroot/opt/sysroot32 test64.c -o test32注意--sysroot会改变 GCC 查找头文件和库的根目录所以 sysroot 里必须包含usr/include和usr/lib的完整结构。如果缺了某个子目录编译会报找不到头文件。5.3 验证 sysroot 是否生效用-v看搜索路径gcc -m32 --sysroot/opt/sysroot32 -v test64.c -o test32 21 | grep search starts here输出里应该出现/opt/sysroot32/usr/include和/opt/sysroot32/usr/lib而不是系统的/usr/include。如果还是出现系统路径说明--sysroot没被正确识别检查 GCC 版本是否支持这个选项openSUSE 12.3 的 GCC 4.7 是支持的。5.4 一个容易忽略的细节动态链接器路径用 sysroot 编译出来的 32 位程序默认的动态链接器路径可能是/lib/ld-linux.so.2这个在 openSUSE 12.3 上通常是存在的。但如果你把程序拷到另一台机器而对方没有 32 位运行库就会报No such file or directory。可以用readelf -l test32 | grep interpreter查看实际路径必要时用-Wl,--dynamic-linker指定。我自己的习惯是在 openSUSE 12.3 上编 32 位程序时先跑一遍gcc -print-multi-lib确认多架构支持再用--sysroot隔离编译最后用file和readelf双重检查产物。这套流程走了几年基本没再因为 32/64 位混装翻过车。希望帮到你。本文还有配套的精品资源点击获取