1、问题背景
XX原有的应用软件已经适配了特定的软件编译环境,但该环境与openEuler社区发行版差异较大,该问题长时间未得到解决,直接影响到业务。鉴于此,openEuler社区派出多名技术专家耗时2周帮助XX完成定制编译环境,节省了数十人月的人力。
2、定制过程
第一步 编译环境选型
glibc和gcc是系统最核心的两个软件组件,系统上其他所有软件几乎都直接或间接依赖于这两个软件,因此首先选择正确的gcc和glibc版本。
XX的众多应用的编译构建都是基于定制的gcc及glibc,所以在服务器操作系统切换到openEuler之后,需要构建一个欧拉底包+定制的gcc和glibc混杂而成的构建环境,这样既能保障操作系统的连续性,也能让应用迁移的过程尽量平滑。
当前选型的是gcc12.3和glibc2.33。如前所述,它是系统最核心的组件,依赖它们的还有包括systemd、nss等超过30款的软件。所以XX计划在openEuler社区发行版22.03版本上继续沿用原来的gcc12.3、glibc2.33等软件,但是当前所有的openEuler社区发行版本均未适配过glibc2.33版本。如表1所示:
只有openEuler 22.03支持glibc2.34,与目标版本最靠近,于是选择在openEuler22.03上面编译glibc2.33,但多次编译均不成功,导致后续依赖包编译动作无法执行,进而影响自研软件的直接移植。方案如下图所示:
原因分析:由于glibc编译时需要依赖编译环境,且只能基于高于目标版本或与目标相同版本的****glibc 环境 ,因此XX在glibc2.34环境上编译glibc2.33无法成功。
鉴于openEuler 20.03上支持glibc 2.28,满足升级glibc的向后兼容的条件,于是和沟通了解的核心目标是要在****openEuler 上面运行现有的业务软件和自研库,业务软件和自研库需要有glibc2.33 、gcc12.3 和一些依赖软件包的环境,对openEuler 版本无特别要求 ,只要保证业务软件能正常运行即可。即接受从openEuler22.03变更为openEuler20.03;如下图所示:
基于以上思考和选择,最终的编译基座定为openEuler20.03+glibc2.33+gcc12.3 ;其他库和软件基于此之上进行编译适配,整体编译方案如下图所示:
第二步 glibc和gcc的编译
编译步骤如下:
- 基于openEuler 20.03 版本(原生支持glibc2.28和gcc7.3),升级glibc版本2.28到2.33,编译glibc2.33:
i.选定编译系统为openEuler20.03 之后,编译glibc2.33过程中需要编译工程文件,因glibc 2.33没有适配过任何版本的openEuler,所以需要针对glibc 2.33制作对应的工程文件;
ii. openEuler22.03已有的glibc2.34与glibc2.33版本接近,因此选择使用glibc2.34的工程文件;glibc2.34工程文件中包含245个patch,这些patch文件是针对glibc2.34生成的,不能用于glibc2.33,因为glibc2.33与glibc2.34代码的行数存在差异。因此需要删除工程文件中以patch结尾的文件,然后删除工程文件中引入patch的行的代码;
iii. glibc2.34与glibc2.33的源码文件存在差异,需要逐个修改工程文件中对差异文件的处理方法;
编译后的新环境为:
openEuler 20.03 +glibc2.33+gcc7.3,其中glibc2.33基于gcc7.3编译;
2)基于1的环境,升级gcc7.3为gcc12.3,编译gcc12.3。
编译后的新环境为:
openEuler 20.03 +glibc2.33+gcc12.3,其中gcc12.3基于glibc2.33编译;
3)基于2中的环境重新编译glibc2.33,
编译后的新环境为:
openEuler 20.03 +glibc2.33+gcc12.3;其中glibc2.33基于gcc12.3编译。
4)基于3中的环境重新编译gcc12.3,完成这两个软件包的循环编译
循环编译原因:gcc和glibc相互依赖,为了保证新生成的gcc和glibc都不依赖原操作系统上的glibc2.28和gcc7.3,需要进行循环编译。
编译的最终效果为:确保glibc和gcc都是在glibc2.33和gcc12.3的环境上编译出来的并且得出一个正确的编译环境: openEuler 20.03 +glibc2.33+gcc12.3 。
第三步 30+基础软件编译
完成了glibc和gcc的编译之后,接着需要将编译成功得到的glibc和gcc的源码和工程文件上传到gitee个人仓库中,同时将软件信息填入下方的表2-软件仓库信息。接着,对systemd等30+基础软件进行编译。
挑战:
基础软件编译的过程工作量巨大,单个软件往往与其他库和软件存在复杂的依赖关系,某些软件甚至需要循环编译。下图以libselinux为例进行说明,通过梳理目标软件libselinux与周边软件的依赖关系发现,对其进行成功编译需要同时处理20+条依赖,其中还存在libselinux->gcc->glibc->systemd->libselinux这样的多层循环依赖,人工处理极其复杂,且本次需要编译的目标软件包数量达到30以上。
解决办法:
引入openEuler社区的构建平台–EulerMaker来解决复杂的依赖关系和巨大的工作量问题。
编译思路:
编译流程说明如下:
1)基础软件的编译大部分都依赖于上一步构建好的glibc、gcc,需要编译成功所使用的glibc和gcc的源码和工程文件上传到gitee个人仓库中,同时将软件信息填入下方的表2-软件仓库信息。
2)先从openEuler官方gitee仓库中依次找到如下表3-待编译软件清单中的软件,拉取代码到gitee个人仓库并整理填入表2-软件仓库信息,其中分支默认填写openEuler-20.03 ;
3)注册并登录EulerMaker,继承一个openEuler20.03的工程;
4)在刚继承的EulerMaker工程上使用表2-软件仓库信息添加软件包并进行构建;
5)查看EulerMaker构建失败的软件包日志,修改gitee个人仓库的工程文件,如果修改spec文件仍然有问题,可以修改软件包代码分支(比如openEuler22.03或24.03等),然后EulerMaker使用新分支代码进行构建,直到EulerMaker构建通过;
6)刷新表2-软件仓库信息,EulerMaker最后全部构建成功的软件包仓库信息即为表4—最终软件仓库信息。
下表即为EulerMaker最后全部构建成功的32个软件包仓库信息:
序列 | 包名 | 分支版本 | 个人仓库 |
---|---|---|---|
1 | attr | openEuler-20.03 | huanglg/attr |
2 | avahi | openEuler-20.03 | huanglg/avahi |
3 | bzip2 | openEuler-20.03 | huanglg/bzip2 |
4 | curl | openEuler-20.03 | huanglg/curl |
5 | cyrus-sasl | openEuler-20.03 | huanglg/cyrus-sasl |
6 | dbus | openEuler-20.03 | huanglg/dbus |
7 | dmidecode | openEuler-20.03 | huanglg/dmidecode |
8 | e2fsprogs | openEuler-20.03 | huanglg/e2fsprogs |
9 | elfutils | openEuler-24.03-LTS | huanglg/elfutils |
10 | keyutils | openEuler-20.03 | huanglg/keyutils |
11 | krb5 | openEuler-20.03 | huanglg/krb5 |
12 | libcap | openEuler-22.03 | huanglg/libcap |
13 | libgcrypt | openEuler-20.03 | huanglg/libgcrypt |
14 | libgpg-error | openEuler-20.03 | huanglg/libgpg-error |
15 | libidn | openEuler-20.03 | huanglg/libidn |
16 | libpciaccess | openEuler-20.03 | huanglg/libpciaccess |
17 | libselinux | openEuler-20.03 | huanglg/libselinux |
18 | libsepol | openEuler-20.03 | huanglg/libsepol |
19 | libssh2 | openEuler-20.03 | huanglg/libssh2 |
20 | libtirpc | openEuler-20.03 | huanglg/libtirpc |
21 | libxml2 | openEuler-20.03 | huanglg/libxml2 |
22 | lvm2 | openEuler-24.03-LTS | huanglg/lvm2 |
23 | lz4 | openEuler-20.03 | huanglg/lz4 |
24 | nspr | openEuler-24.03-LTS | huanglg/nspr |
25 | nss | openEuler-20.03 | huanglg/nss |
26 | nss-util | openEuler-20.03 | 包含在nss包中 |
27 | openldap | openEuler-20.03 | huanglg/openldap |
28 | pcre | openEuler-20.03 | huanglg/pcre |
29 | systemd | openEuler-22.03 | huanglg/systemd |
30 | xz | openEuler-20.03 | huanglg/xz |
31 | yajl | openEuler-20.03 | huanglg/yajl |
32 | openssl | openEuler-20.03 | huanglg/openssl |
小结:
glibc+gcc+30多个基础软件的构建,且涉及到glibc和gcc的循环编译,工作量很大,但是在提前测试好之后再通过EulerMaker构建平台只需要3个小时左右就能完成一次全部的构建工作,大大提高了编译效率,方便使用和后续的工程化构建。
如需进一步了解EulerMaker,可以访问openEuler开源社区:
第四步 测试
新开一台主机(或虚拟机)安装openEuler20.03系统且保障主机可以上网,只配置一个eulermaker的repo源,重建yum缓存后,使用yum update来更新系统,重启主机后,检查glibc、gcc和30+个基础软件的版本和基础命令的使用是否报错。具体操作步骤如下:
1)配置一个eulermaker的repo源,如下所示:
# cat /etc/yum.repos.d/eulermaker.repo
[eulermaker]
name=eulermaker
baseurl=https://eulermaker.compass-ci.openeuler.openatom.cn/api/ems3/repositories/2003sp4-20241029/openEuler%3A20.03/aarch64/
enabled=1
gpgcheck=0
2)然后重建缓存:
# yum clean all && yum makecache
3)接着更新包:
# yum update -y
4)最后回显如下:
这里升级成功的软件和之前EulerMaker构建好的软件版本是对应的。
Upgraded:
cpp-12.3.1-35.oe2003sp4.aarch64
curl-7.71.1-37.oe2003sp4.aarch64
cyrus-sasl-2.1.27-16.oe2003sp4.aarch64
cyrus-sasl-lib-2.1.27-16.oe2003sp4.aarch64
dbus-1:1.12.16-23.oe2003sp4.aarch64
dbus-common-1:1.12.16-23.oe2003sp4.noarch
dbus-daemon-1:1.12.16-23.oe2003sp4.aarch64
dbus-libs-1:1.12.16-23.oe2003sp4.aarch64
dbus-tools-1:1.12.16-23.oe2003sp4.aarch64
device-mapper-8:1.02.195-11.oe2003sp4.aarch64
device-mapper-event-8:1.02.195-11.oe2003sp4.aarch64
e2fsprogs-1.45.6-21.oe2003sp4.aarch64
e2fsprogs-help-1.45.6-21.oe2003sp4.noarch
elfutils-0.190-4.oe2003sp4.aarch64
elfutils-default-yama-scope-0.190-4.oe2003sp4.noarch
elfutils-libelf-0.190-4.oe2003sp4.aarch64
elfutils-libs-0.190-4.oe2003sp4.aarch64
gcc-12.3.1-35.oe2003sp4.aarch64
glibc-2.33-2.oe2003sp4.aarch64
glibc-common-2.33-2.oe2003sp4.aarch64
glibc-devel-2.33-2.oe2003sp4.aarch64
krb5-1.18.2-14.oe2003sp4.aarch64
krb5-libs-1.18.2-14.oe2003sp4.aarch64
libcap-2.61-7.oe2003sp4.aarch64
libcurl-7.71.1-37.oe2003sp4.aarch64
libfdisk-2.35.2-16.oe2003sp4.aarch64
libgcc-12.3.1-35.oe2003sp4.aarch64
libgomp-12.3.1-35.oe2003sp4.aarch64
libgpg-error-1.38-3.oe2003sp4.aarch64
libstdc+±12.3.1-35.oe2003sp4.aarch64
lvm2-8:2.03.21-11.oe2003sp4.aarch64
lvm2-help-8:2.03.21-11.oe2003sp4.noarch
nspr-4.35.0-3.oe2003sp4.aarch64
openldap-2.4.50-9.oe2003sp4.aarch64
openssl-1:1.1.1f-36.oe2003sp4.aarch64
openssl-help-1:1.1.1f-36.oe2003sp4.noarch
openssl-libs-1:1.1.1f-36.oe2003sp4.aarch64
systemd-249-86.oe2003sp4.aarch64
systemd-help-249-86.oe2003sp4.noarch
systemd-libs-249-86.oe2003sp4.aarch64
systemd-udev-249-86.oe2003sp4.aarch64
xz-5.2.5-4.oe2003sp4.aarch64
xz-libs-5.2.5-4.oe2003sp4.aarch64Complete!
5)重启主机:
# reboot
6)对已更新的软件进行测试:
# gcc --version
gcc (GCC) 12.3.1 (openEuler 12.3.1-35.oe2003sp4)
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.# ldd --version
ldd (GNU libc) 2.33
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.# curl --version
curl 7.71.1 (aarch64-openEuler-linux-gnu) libcurl/7.71.1 OpenSSL/1.1.1f-fips zlib/1.2.11 brotli/1.0.7 libidn2/2.3.0 libpsl/0.21.1 (+libidn2/2.3.0) libssh/0.9.4/openssl/zlib nghttp2/1.41.0
Release-Date: 2020-07-01
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS brotli GSS-API HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP UnixSockets# rpm -qa|grep dbus
dbus-libs-1.12.16-23.oe2003sp4.aarch64
dbus-common-1.12.16-23.oe2003sp4.noarch
dbus-1.12.16-23.oe2003sp4.aarch64
dbus-tools-1.12.16-23.oe2003sp4.aarch64
dbus-daemon-1.12.16-23.oe2003sp4.aarch64# openssl version
OpenSSL 1.1.1f 31 Mar 2020
后面不再逐一罗列,主要检查软件版本和基础命令使用是否会报错。
第五步 输出成果
向提供如下成果:
- EulerMaker构建好的rpm包,提供仓库地址给使用;
见如下链接:
https://eulermaker.compass-ci.openeuler.openatom.cn/api/ems3/repositories/2003sp4-20241029/openEuler%3A20.03/aarch64/ - 提供编译过程中的FAQ文档;
- 分配EulerMaker工程的权限,方便后续构建;
- 提供已构建好的软件包信息(包括包名、仓库及分支等信息)。
见表4-最终软件仓库信息
3、 附件1 FAQ
1)gcc编译报debugsource.txt为空文件
解决办法:
在spec文件的开头添加如下行:
%global debug_package %{nil}
2)编译glibc报Werror-use-after-free
解决办法:
按下图内容修改spec文件。
3)编译glibc报C.utf8找不到
解决办法:
按下图内容修改spec文件。
4)编译libnsl报错
解决办法:
按下图内容修改spec文件。
5)编译systemd报错
解决办法:
参考Issues · msys2/MINGW-packages · GitHub 的最新版本进行构建
6)编译systemd报错:debugsourcefiles.list报空文件
解决办法:
在spec文件的开头添加如下行:
%global debug_package %{nil}
7)编译nss报错
解决办法:
参考:
https://groups.google.com/g/linux.debian.maint.glibc/c/L164IF-7_oI
Patch1: posix-Fix-attribute-access-mode-on-getcwd-BZ-27476.patch
给glibc打上这个Patch,然后重新编译nss解决。
8)编译libcap报错
解决办法:
在spec文件的开头添加如下行:
%global debug_package %{nil}