kernel rpm 制作与过程探索

制作kernel rpm步骤:

1.安装工具
yum install rpm-devel;rpmdevtools
yum groupinstall "Development Tools"

 

2.rpmdev-setuptree #在当前用户根目录下生成rpmbuild目录
rpmbuild/
├── BUILD
├── BUILDROOT
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS

 

3.下载kernel package,并解压
wget http://mirrors.ustc.edu.cn/kernel.org/linux/kernel/v5.x/Linux-5.7.1.tar.gz
tar -zxvf linux-5.7.1.tar.gz

 

4.生成rpm
cd linux-5.7.1/
make rpm-pkg
可以看到如下信息
Wrote: /root/rpmbuild/SRPMS/kernel-5.7.1-1.src.rpm
Wrote: /root/rpmbuild/RPMS/x86_64/kernel-5.7.1-1.x86_64.rpm
Wrote: /root/rpmbuild/RPMS/x86_64/kernel-headers-5.7.1-1.x86_64.rpm
Wrote: /root/rpmbuild/RPMS/x86_64/kernel-devel-5.7.1-1.x86_64.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.4aODom
+ umask 022
+ cd /root/rpmbuild/BUILD
+ cd kernel-5.7.1
+ rm -rf /root/rpmbuild/BUILDROOT/kernel-5.7.1-1.x86_64
+ exit 0
到这里就ok了,可以看到/root/rpmbuild/RPMS/下生成了kernel,kernel-header,kernel-devel的rpm包,以及SRPMS/下会生成kernel-src的rpm包

 

命令超级简单,瞧瞧生成rpm 过程:
1.当我们在linux-5.7.1/下执行make help可以看到:

Kernel packaging:
  rpm-pkg             - Build both source and binary RPM kernel packages
  binrpm-pkg          - Build only the binary kernel RPM package
  deb-pkg             - Build both source and binary deb kernel packages
  bindeb-pkg          - Build only the binary kernel deb package
  snap-pkg            - Build only the binary kernel snap package
                        (will connect to external hosts)
  dir-pkg             - Build the kernel as a plain directory structure
  tar-pkg             - Build the kernel as an uncompressed tarball
  targz-pkg           - Build the kernel as a gzip compressed tarball
  tarbz2-pkg          - Build the kernel as a bzip2 compressed tarball
  tarxz-pkg           - Build the kernel as a xz compressed tarball
  perf-tar-src-pkg    - Build perf-5.7.1.tar source tarball
  perf-targz-src-pkg  - Build perf-5.7.1.tar.gz source tarball
  perf-tarbz2-src-pkg - Build perf-5.7.1.tar.bz2 source tarball
  perf-tarxz-src-pkg  - Build perf-5.7.1.tar.xz source tarball

这些参数告诉我们可以去build什么样的packages

当我们进一步打开linux-5.7.1/Makefile可以看到有下面信息:

%src-pkg: FORCE
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.package $@
%pkg: include/config/kernel.release FORCE
        $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.package $@

%是通配符,不管我们build %src-pkg 或者%pkg,都要去调用Makefile.package文件
因此,可以打开Makefile.package看一下

PHONY += rpm-pkg
rpm-pkg:
        $(MAKE) clean
        $(CONFIG_SHELL) $(MKSPEC) >$(objtree)/kernel.spec
        $(call cmd,src_tar,$(KERNELPATH),kernel.spec)
        +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz \
        --define='_smp_mflags %{nil}'

# binrpm-pkg
# ---------------------------------------------------------------------------
PHONY += binrpm-pkg
binrpm-pkg:
        $(MAKE) -f $(srctree)/Makefile
        $(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/binkernel.spec
        +rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \
                $(UTS_MACHINE) -bb $(objtree)/binkernel.spec
.............

这里告诉我们要去build package需要执行的步骤,例如build rpm-pkg

变量定义自己去找,下面翻译每个步骤:
步骤1:make clean
步骤2:./scripts/package/mkspec >./kernel.spec #生成spec文档
步骤3:rpmbuild --target x86_64 -ta kernel-5.7.1.tar.gz --define='_smp_mflags %{nil}'
步骤1,2好懂,来具体看看步骤3:
首先看下主目录下Makefile:

        ifeq ("$(origin V)", "command line")
            KBUILD_VERBOSE = $(V)
        endif
        ifndef KBUILD_VERBOSE
            KBUILD_VERBOSE = 0
        endif

        ifeq ($(KBUILD_VERBOSE),1)
            quiet =
            Q =
        else
            quiet=quiet_
        Q = @
        endif
        

origin的语法:$(origin <variable>;) 函数origin并不操作变量的值,只是告诉你你的这个变量是哪里来的。
origin的返回值如下:
(1)返回值为"undefine"时,这个变量没有被定义过;
(2)返回值为“command line”时,这个变量是被命令行定义的;
(3)返回值为“environment”时,这个变量是定义为环境变量;
(4)返回值为“file”时,这个变量是定义在Makefile中;
(5)返回值为“default”时,变量是默认定义的;
(6)返回值为“override”时,被override指示符重新定义;
(7)返回值为“automatic”时,是一个命令运行中自动化变量

如果是指定V的值,make V=【0|1|2】,0表示quiet build,1表示verbose build,2表示give reason for build,则KBUILD_VERBOSE = V;
否则KBUILD_VERBOSE = 0;决定了quiet和Q的值
在这里显然是KBUILD_VERBOSe = 0,quiet=quiet_;Q=@

 

再看下cmd和src_tar的定义,scripts/Kbuild.include:

echo-cmd = $(if $($(quiet)cmd_$(1)),\
        echo '  $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
# printing commands
cmd = @set -e; $(echo-cmd) $(cmd_$(1))

quiet_cmd_src_tar = TAR     $(2).tar.gz
      cmd_src_tar = \
set -e; \
if test "$(objtree)" != "$(srctree)"; then \
        echo >&2; \
        echo >&2 "  ERROR:"; \
        echo >&2 "  Building source tarball is not possible outside the"; \
        echo >&2 "  kernel source tree. Don't set KBUILD_OUTPUT, or use the"; \
        echo >&2 "  binrpm-pkg or bindeb-pkg target instead."; \
        echo >&2; \
        false; \
fi ; \
$(srctree)/scripts/setlocalversion --save-scmversion; \
tar -cz $(RCS_TAR_IGNORE) -f $(2).tar.gz \
        --transform 's:^:$(2)/:S' $(TAR_CONTENT) $(3); \
rm -f $(objtree)/.scmversion

 

@set -e: @意思是不回显command,只回显结果,set -e意思是,如果执行结果不是true则退出
escsq的作用是将单引号'替换成\' ,避免在echo 声明中使用单引号
echo-why:需要KBUILD_VERBOSE=2时才有效,告诉为什么target被build
echo-cmd作用是打印该命令,以及为什么built target,但echo-why 只在make V=2时才enable
echo的作用是打印该命令,并且执行该命令
就cmd定义的结构来看
cmd = @set -e;             $(echo-cmd)                            $(cmd_$(1))
          打开set -e功能    打印quiet_cmd_${1},           执行命令
            前提是quiet_cmd_${1}有定义


$(call cmd,src_tar,$(KERNELPATH),kernel.spec),这里${1}是src_tar,${2}是${KERNELPATH},${3}是kernel.spec,但是在quiet_src_tar是没有用到kernel.spec这个参数,在src_tar时才用到。
因此翻译过来就是TAR kernel-5.7.1.tar.gz

 

对于步骤4:+rpmbuild $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz --define='_smp_mflags %{nil}'
先了解下几个特殊字符:
+ : 执行命令时不受到make的-n -t -q 三个参数的影响
make:
-n : 仅打印命令而不执行,通常用在需要看自己编写的makefile是否错误,命令是否正确的情况下
-t : 跟新目标文件的时间,只把目标文件变成已经编译的状态,而不是真正的编译目标,伪编译
-q : 检查目标文件是否需要跟新
- : 任何命令行的非零退出状态都被忽略,不会因为执行错误,退出状态为非零而退出
@ : 不显示命令本身而只显示结果
$ : 打印makefile中定义的变量
$$ : 打印makefile中定义的shell变量
$@ : 目标文件
$^ : 所有的依赖文件
$< : 第一个依赖文件

-ta的意思:build binary and source package with tarball
--defile='_smp_mflags ${nil}'是优化选项,目前还没搞懂什么意思~

这句命令翻译过来就是rpmbuild --target x86_64 -ta kernel-5.7.1.tar.gz --define='_smp_mflags %{nil}'

 

 

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

整个make rpm-pkg的过程就是创建kernel.spec,然后执行rpmbuild,我跳过make rpm-pkg过程,直接用rpmbuild也可以,步骤如下:
1.安装工具
yum install rpm-devel;rpmdevtools
yum groupinstall "Development Tools"

2.rpmdev-setuptree #在当前用户根目录下生成rpmbuild目录
rpmbuild/
├── BUILD
├── BUILDROOT
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS

3.下载kernel package,并解压
wget http://mirrors.ustc.edu.cn/kernel.org/linux/kernel/v5.x/Linux-5.7.1.tar.gz
tar -zxvf linux-5.7.1.tar.gz

4.cd linux-5.7.1
1).make menuconfig #生成.config文件,只需要点击save即可
2).修改.config:
CONFIG_SYSTEM_TRUSTED_KEYS="certs/rhel.pem" => #CONFIG_SYSTEM_TRUSTED_KEYS="certs/rhel.pem"
CONFIG_DEBUG_INFO_BTF=y => CONFIG_DEBUG_INFO_BTF=n
不然编译会报错

3.修改 scripts/package/mkspec,因为跳过了make,所以不能继承Makefile里面的变量
KERNELRELEASE=5.7.1
MAKE=make
export RCS_TAR_IGNORE=“--exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg --exclude .git”
然后./scripts/package/mkspec > ./kernel.spec

4.生成.config和kernel.spec后
mv linux-5.7.1 kernel-5.7.1 #这个不是必要的,只是kernel.spec里写的name是kernel,当然也可以把name改成linux,但是一般是kernel开头吧
tar -zcvf kernel-5.7.1.tar.gz kernel-5.7.1 #生成tarball

5.rpmbuild --target x86_64 -ta kernel-5.7.1.tar.gz --define='_smp_mflags %{nil}'

只是帮助理解过程,实际中还是make rpm-pkg一个指令就搞定啦

有两点疑问
1.TAR kernel-5.7.1.tar.gz这个TAR实在找不到哪里来的
2.--define='_smp_mflags %{nil}' 还没理解

 

上一篇:从.src.rpm包中提取出完整的源码的方法


下一篇:Linux 内核编译笔记