概要

本文档采用glibc2.28版本作为示例,模拟内网环境无法访问github等开源社区

为精简docker容器镜像,采用Alpine镜像,需要手动编译glibc源代码

制作编译好的glibc二进制文件

获取glibc二进制文件构建工具

# 内网环境可下载该工具包手动上传到服务器
git pull https://github.com/sgerrand/docker-glibc-builder.git

该构建工具中需要采用wget命令从第三方仓库下载glibc源代码,由于内网环境无法访问第三方仓库,我们需要对构建工具做一些修改

修改Dockerfile

本例采用修改过的openeuler-x86镜像,在原生的基础上安装了一些常用的命令例如vimtartelnet

FROM euleros-x86:202405V1
ENV DEBIAN_FRONTEND=noninteractive \
GLIBC_VERSION=2.28 \
PREFIX_DIR=/usr/glibc-compat
COPY configparams /glibc-build/configparams
COPY builder /builder
# 内网环境 手动下载glibc源代码上传至根目录
COPY glibc-2.28.tar.gz /glibc-2.28.tar.gz
# gcc bison make m4 都是编译所必须的命令
RUN yum -y install gcc bison make m4
ENTRYPOINT ["/builder"]

修改bulider脚本

#!/usr/bin/env bash

set -eo pipefail; [[ "$TRACE" ]] && set -x

main() {
# 声明 version 和 prefix 如果不存在入参指定version和prefix就使用环境变量 GLIBC_VERSION 和 PREFIX_DIR
declare version="${1:-$GLIBC_VERSION}" prefix="${2:-$PREFIX_DIR}" : "${version:?}" "${prefix:?}" {
# 此处只删除了使用wget从第三方仓库下载glibc的步骤
tar zxf /glibc-$version.tar.gz
mkdir -p /glibc-build && cd /glibc-build
"/glibc-$version/configure" \
--prefix="$prefix" \
--libdir="$prefix/lib" \
--libexecdir="$prefix/lib" \
--enable-multi-arch \
--enable-stack-protector=strong
make && make install
tar --dereference --hard-dereference -zcf "/glibc-bin-$version.tar.gz" "$prefix"
} >&2 [[ $STDOUT ]] && cat "/glibc-bin-$version.tar.gz"
} main "$@"

构建编译glibc的镜像

# 首先进入Dockerfile文件同级目录
docker build -t "euler-glibc:2.28" .

运行 euler-glibc:2.28 镜像

# docker run --rm --env STDOUT=1 euler-glibc:2.28 {version} {prefix} > glibc-bin.tar.gz
# 上述命令的 {version} 和{prefix}即 builder脚本的入参,如果在Dockerfile中写好了环境变量,这两个值可以不要
# 直接运行该镜像,编译时间可能比较长,要稍微等待一段时间
docker run --rm --env STDOUT=1 euler-glibc:2.28 > glibc-bin.tar.gz
# 编译完成就会在当前文件夹内获得 名为 glibc-bin.tar.gz 的 libc二进制文件

制作alpine镜像apk包

获取apk包构建工具

# 内网环境同样手动下载 2.28 版本APKBUILD 有问题,建议直接使用2.35版本
git https://github.com/sgerrand/alpine-pkg-glibc.git

获取alpine镜像并配置apk源

构建apk包需要用的apk-sdk,apk是alpine的包管理工具,此处需要获取一个alpine镜像并配置apk仓库地址。

  1. 获取alpine镜像

    可以直接从dockerhub拉取一个和alpine镜像,也可以下载rootfs自己构建,此处不赘述拉取过程

  2. 配置apk源

    # 此处是我自己构建的alpine镜像所以tag是v1,具体名字根据实际的填写
    FROM alpine:v1
    RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && apk update && apk add build-base alpine-sdk

    编写完成Dockerfile之后构建该镜像并命名为 alpine:v2

修改APKBUILD文件

# Maintainer: Sasha Gerrand <alpine-pkgs@sgerrand.com>

pkgname="glibc"
pkgver="2.28"
_pkgrel="0"
pkgrel="0"
pkgdesc="GNU C Library compatibility layer"
arch="x86"
url="https://github.com/sgerrand/alpine-pkg-glibc"
license="LGPL"
source="$pkgname-bin.tar.gz
nsswitch.conf
ld.so.conf"
subpackages="$pkgname-bin $pkgname-dev $pkgname-i18n"
triggers="$pkgname-bin.trigger=/lib:/usr/lib:/usr/glibc-compat/lib" package() {
echo "----------------------------package start"
echo "$pkgdir $srcdir $builddir"
mkdir -p "$pkgdir/lib" "$pkgdir/usr/glibc-compat/lib/locale" "$pkgdir"/usr/glibc-compat/lib64 "$pkgdir"/etc
cp -a "$srcdir"/usr "$pkgdir"
cp "$srcdir"/ld.so.conf "$pkgdir"/usr/glibc-compat/etc/ld.so.conf
rm "$pkgdir"/usr/glibc-compat/etc/rpc
rm -rf "$pkgdir"/usr/glibc-compat/bin
rm -rf "$pkgdir"/usr/glibc-compat/sbin
rm -rf "$pkgdir"/usr/glibc-compat/lib/gconv
rm -rf "$pkgdir"/usr/glibc-compat/lib/getconf
rm -rf "$pkgdir"/usr/glibc-compat/lib/audit
rm -rf "$pkgdir"/usr/glibc-compat/share
rm -rf "$pkgdir"/usr/glibc-compat/var
ln -s /usr/glibc-compat/lib/ld-linux-x86-64.so.2 ${pkgdir}/lib/ld-linux-x86-64.so.2
ln -s /usr/glibc-compat/lib/ld-linux-x86-64.so.2 ${pkgdir}/usr/glibc-compat/lib64/ld-linux-x86-64.so.2
ln -s /usr/glibc-compat/etc/ld.so.cache ${pkgdir}/etc/ld.so.cache
echo "----------------------------package end"
} bin() {
echo "----------------------------bin start"
depends="$pkgname libgcc"
mkdir -p "$subpkgdir"/usr/glibc-compat
cp -a "$srcdir"/usr/glibc-compat/bin "$subpkgdir"/usr/glibc-compat
cp -a "$srcdir"/usr/glibc-compat/sbin "$subpkgdir"/usr/glibc-compat
echo "----------------------------bin end"
} i18n() {
echo "----------------------------i18n start"
depends="$pkgname-bin"
arch="noarch"
mkdir -p "$subpkgdir"/usr/glibc-compat
cp -a "$srcdir"/usr/glibc-compat/share "$subpkgdir"/usr/glibc-compat
echo "----------------------------i18n end"
}

编写构建apk包的Dockerfile

FROM alpine:v2
LABEL maintainer="su.yingjun" email="i9xswanan@gmail.com"
VOLUME ["/home/docker/alpine-pkg-glibc","/tmp"]
# 创建构建用户
RUN adduser -D packager && addgroup packager abuild && echo 'packager ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers.d/packager && chmod o+w /tmp
#RUN adduser -D -s /bin/sh build && echo "build:build2024" | chpasswd && adduser build abuild && apk add alpine-sdk build-base abuild cmake git
COPY APKBUILD /home/packager/APKBUILD
COPY glibc-bin.tar.gz /home/packager/glibc-bin.tar.gz
COPY glibc-bin.trigger /home/packager/glibc-bin.trigger
COPY ld.so.conf /home/packager/ld.so.conf
COPY nsswitch.conf /home/packager/nsswitch.conf
USER packager
WORKDIR /home/packager
RUN abuild-keygen -n --append --install

dockerbuild -t alpine-apk-build:v1 .

运行构建apk包容器

# 此处挂载目录的原因是方便取出apk包和公钥文件,也可以使用docker cp取出
docker run --rm -it -v /home/docker/alpine-pkg-glibc:/tmp alpine-apk-build:v1 sh
# 下方为登录容器后的命令 保证处于 /home/packager 目录下
abuild checksum
abuild -r
# 执行完成之后会在构建目录下出现 packages目录,该目录中存放打包好的apk文件,公钥文件存放在当前用户家目录下的.abuild 文件夹中,执行cp命令拷贝到挂载的目录中
cp ~/.abuild/*.rsa.pub ~/packages/glibc*.apk /tmp
# 退出容器
exit

参考资料

  1. GNU下载地址
  2. https://github.com/sgerrand/alpine-pkg-glibc
  3. https://github.com/sgerrand/docker-glibc-builder
  4. Alpine apk源
  5. Alpine Wiki
  6. https://www.youtube.com/watch?v=ibeqoQpO33w&t=697s

附录

abuild -r 构建流程

abuild 是 Alpine Linux 的构建工具,用于构建 APK 包。执行 abuild -r 命令的全流程涉及多个步骤,包括准备构建环境、构建包、运行测试和创建最终的 APK 包。以下是 abuild -r 的详细流程:

1. 准备构建环境

更新并安装依赖

  • abuild 会根据 APKBUILD 文件中的依赖定义安装构建所需的包。

初始化环境变量

  • 设置必要的环境变量,如 srcdirbuilddirpkgdir 等。

2. 提取源代码

  • 下载源代码:根据 APKBUILD 文件中的 source 字段下载源代码和补丁文件。
  • 校验文件完整性:通过校验和文件(如 sha512sums)验证下载的文件是否完整。
  • 解压源代码:将下载的源代码文件解压到 srcdir

3. 运行构建流程

prepare() 函数

  • 这是一个可选的函数,用于在实际构建之前应用补丁或进行其他准备工作。

build() 函数

  • 执行构建过程。这通常包括配置、编译和链接源代码。
  • 具体步骤由 APKBUILD 文件中的 build() 函数定义。例如,可能使用 ./configure 脚本、make 命令等。

4. 安装步骤

package() 函数

  • 安装构建好的文件到 pkgdir
  • 设置文件的权限和属性。
  • 安装文档文件(如 READMELICENSE 等)。

5. 创建 APK 包

  • abuild 会将 pkgdir 中的内容打包成一个 APK 文件。
  • 生成的 APK 文件会放在 packages 目录下。

6. 签名 APK 包

  • 如果你有签名密钥,abuild 会对生成的 APK 包进行签名。签名密钥通常存储在 ~/.abuild/ 目录中。

7. 运行测试(可选)

  • abuild 也可以运行测试(如果定义了 check() 函数)。这通常在构建后执行,用于验证包的正确性。

8. 清理

  • 清理临时文件和目录,确保构建环境干净。

01.Alpine编译glibc的更多相关文章

  1. alpine编译安装tengine,并使用supervisor启动

    Alpine是一个小型的linux系统,官方docker镜像只有不到5MB,非常适合作为容器镜像. Alpine Linux is a security-oriented, lightweight L ...

  2. uboot-2012.04.01移植编译前准备

    一:准备移植1.从下面的官网下载uboot-2012.04.012.建立sourceinsight工程 a.解压并在E:\colin weidongshan\transplant_u-boot-201 ...

  3. uboot 2013.01 s3c6400编译失败

    通常我们对s3c6410平台开发u-boot是在s3c6400的基础上修改而成的,但是从uboot 2013.01这个版本之后的版本都把smdk6400对应的配置给删除了. 这是因为该版本smdk64 ...

  4. [笔记]Modelsim系列01:编译Altera库的方法

    意义:一劳永逸,不用每次对那些包含Quartus II生成文件的工程进行功能仿真时,都需要重新编译一堆东西.节约时间成本. 版本:ModelSim SE 6.5d 打开Modelsim软件,默认会打开 ...

  5. 深入理解Java虚拟机 #01# 自己编译JDK

    x 首先用书上的脚本尝试,失败. 之后根据源文件的 README 编译,抛出: root@linux:/opt/openjdk# sh ./get_source.sh ERROR: Need init ...

  6. 在openwrt 17.01上编译最新nginx 1.14.2的笔记

    openwrt 17.01源码对应的nginx版本是1.10.2,有些新功能没有,所以需要升级到nginx 1.14.2最新的稳定版 https://github.com/macports/macpo ...

  7. 如何使用新的glibc来编译自己的程序

    http://www.sysnote.org/2015/08/25/use-new-glibc/ 通常情况下我们都是直接使用glibc提供的一些库函数,但是某些特殊的情况,比如要修改glibc的一些代 ...

  8. 009全志R16平台tinav3.0下编译不过的问题

    009全志R16平台tinav3.0下编译不过的问题 2018/11/13 11:39 版本:V1.0 开发板:SC3817R SDK:tina v3.0 1.01原始编译全志r16平台tinav3. ...

  9. 编译软件基础知识(1/2) via LinuxSir

    内容来自LinuxSir: 如果不出意外的话,会出现say.so => not found. 这时的./test是不能运行的.但至少说明程序运行时是需要这个库的.那为什么找不到这个库呢?那就让我 ...

  10. X86上搭建交叉工具链,来给龙芯笔记本编译本地工具链(未完待续)

    故事的背景是,我买了一台龙芯2F的笔记本来装B. 为什么说是装B呢?因为不但操作系统是Linux,而且CPU还是龙芯的. 一般人有这么酷的装备吗?简直是装B大圣啊. 这里一定要申明一点,本人不是IT技 ...

随机推荐

  1. 重新整理数据结构与算法(c#系列)—— 树的前中后序遍历查找[十七]

    前言 树的前中后序遍历 是根据前中后序的顺序来查找,找到了则弹出. 正文 节点模型: public class HeroNode { private int no; private string na ...

  2. HarmonyOS 性能优化

    如何合理使用动效来获得更好的性能 组件转场动画使用 transition: 推荐使用转场动画(transition)而不是组件动画(animateTo),因为 transition 只需要在条件改变时 ...

  3. 这10款VS Code神仙插件,嵌入式程序员必备

    大家好,我是知微! 嵌入式软件开发工程师平时可能更多的是使用Source Insight.Keil.IAR来阅读代码,写代码. VSCode大家都听说过,功能十分强大,而且免费! 或许是因为这款软件上 ...

  4. 力扣1083(MySQL)-销售分析Ⅲ(简单)

    题目: Table: Product Table: Sales 编写一个SQL查询,报告2019年春季才售出的产品.即仅在2019-01-01至2019-03-31(含)之间出售的商品. 以 任意顺序 ...

  5. C++ 访问说明符详解:封装数据,控制访问,提升安全性

    C++ 访问说明符 访问说明符是 C++ 中控制类成员(属性和方法)可访问性的关键字.它们用于封装类数据并保护其免受意外修改或滥用. 三种访问说明符: public:允许从类外部的任何地方访问成员. ...

  6. RocketMQ 端云一体化设计与实践

    简介:本文首先介绍了端云消息场景一体化的背景,然后重点分析了终端消息场景特点,以及终端消息场景支撑模型,最后对架构和存储内核进行了阐述.我们期望基于 RocketMQ 统一内核一体化支持终端和服务端不 ...

  7. Java编程技巧之样板代码

    简介: 在日常编码的过程中,可以总结出很多"样板代码",就像"活字印刷术中的"活字"一样.当我们编写新的代码时,需要用到这些"活字" ...

  8. Effective Java 在工作中的应用总结

    简介: <Effective Java>是一本经典的 Java 学习宝典,值得每位 Java 开发者阅读.笔者将书中和平日工作较密切的知识点做了部分总结. ​ 作者 | 宜秋 来源 | 阿 ...

  9. [FE] 浅谈 Chakra UI 的现代化浅封装 - 语义化大行其道

      Web2.0 发展至今,网页元素越来越丰富和多样化,数据越来越多. 从需求上来说,也已经不再是展示简单个静态网页,高效的开发交互.打通后端数据,产生了 React 和 Vue 两个著名框架. Re ...

  10. [Gin] gin-jwt 中间件的请求流程与使用思路

    gin-jwt 中间件是对 jwt-go 的封装以适应 gin 框架.gin-jwt 对不同的请求流程有不同的 handler: 登录请求流程 是用 LoginHandler. 需要 jwt 令牌的后 ...