By: fu linux
E-mail: fulinux@sina.com
Blog: https://blog.csdn.net/fulinus
喜欢的盆友欢迎订阅!
你的喜欢就是我写作的动力!

返回总目录 : Yocto开发讲解系列 - 总目录
概述
默认情况下,
yocto
项目(例如我们的
qemux86-64
机器)使用
sysvinit
作为系统
初始化管理器
,即系统首进程init。可是我们的
yocto
也可以支持你换成
systemd
,
systemd
可以完全替代
init
,它具有并行启动服务、减少
shell
开销等特性,而且也可以想sysvinit那样启动一个脚本,
相比之下,systemd 将组件视为
units
单元。与sysvinit管理和启动程序相比,使用
units
单元是一个更广泛的概念。一个单元包括几种不同类型的实体(比如服务或者程序),服务或程序是实体类型之一。
sysvinit
中的
运行级别
概念对应于
systemd
中
target目标
的概念,其中
target目标
也是一种支持的单元,即你启动一个目标可能就启动了很多的组件(程序或者服务)。
而且吧,这个
sysvinit
管理器还有很多的缺陷,比如不能实现程序并行启动,只能一个个顺序启动,不支持并行启动,还要写脚本,而且有的时候程序死掉了都不能让他重启。
我这两个系统初始化管理程序都用过,我推荐你使用
systemd
哈,现在
systemd
也流行起来了,现在
Ubuntu
系统都是
systemd
,而且它调试启动问题的工具也丰富,今后可能都是systemd的环境了,~
小技巧分享
本专栏开篇的时候,我就讲到qemux86-64虚拟机对于没有Ubuntu桌面环境的玩家而言也是可以运行的,为啥没有桌面环境? 因为我们某些小伙伴把Ubuntu桌面程序给停掉了,因为我们的电脑性能不足编译慢、或者是一台公司的服务器,又或者单纯的最求最强性能,不喜欢多余的开销0.0 怎么做呢?分享一下:
如何替换成systemd呢
前面我们说了默认都是使用sysvinit管理器,如果你是想继续使用sysvinit,就不用看本章了,如果想更换成systemd,如何替换呢?
meta-mylayer]$ vim recipes-sato/images/core-image-sato.bbappend
...
DISTRO_FEATURES_append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
- 1
- 2
- 3
- 4
还有,我们需要停了
sysvinit
,可以这样避免启用了
sysvinit
的部分功能,停止启用的方法:
#在上面的文件中追加这个
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
- 1
- 2
可以删除任意冗余的
sysvinit
脚本。
如果你想要从目标镜像文件系统中完全删除
initscripts
脚本文件,同时设置下面的语句:
VIRTUAL-RUNTIME_initscripts = ""
- 1
但是对于某些迷你型的(或者某些救急或者恢复模式的)镜像,我们可能还需要用到sysvinit的内容,因此,根据自己的需求,上面添加的最后两项也可以不使用,可以屏蔽,就只保留开始的两项语句。
编译验证systemd
编译前我们看下效果:
poky]$ source oe-init-build-env
build]$ bitbake -e core-image-sato | grep ^DISTRO_FEATURES=
DISTRO_FEATURES="acl alsa argp bluetooth ext2 ipv4 ipv6 largefile pcmcia usbgadget usbhost wifi xattr nfs zeroconf pci 3g nfc x11 vfat largefile opengl ptest multiarch wayland vulkan systemd pulseaudio gobject-introspection-data ldconfig"
- 1
- 2
- 3
是不是就少了
sysvinit
, 而多了
systemd
了,然后我们开始构建我们的目标镜像吧!
build]$ bitbake core-image-sato
- 1
但是很不好意思,并没有达到预期的目标。
init
进程依旧是
sysvinit
实例程序。
build]$ ls -l tmp/work/qemux86_64-poky-linux/core-image-sato/1.0-r0/rootfs/sbin/init
lrwxrwxrwx 1 peeta peeta 19 3月 9 2018 tmp/work/qemux86_64-poky-linux/core-image-sato/1.0-r0/rootfs/sbin/init -> /sbin/init.sysvinit
- 1
- 2
问题在哪里呢?通过单独编译
systemd
发现如下错误:
build]$ bitbake systemd
...
ERROR: Nothing PROVIDES 'systemd'
systemd was skipped: missing required distro feature 'systemd' (not in DISTRO_FEATURES)
- 1
- 2
- 3
- 4
但是我前面确实是在
DISTRO_FEATURES
中有添加了systemd的feature,但是先让没有生效,莫非要在conf等的配置文件中添加吗?
我们先尝试在local.conf中进行添加:
poky]$ vim build/conf/local.conf
...
# Use systemd init manager.
DISTRO_FEATURES_append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED += "sysvinit"
- 1
- 2
- 3
- 4
- 5
- 6
然后重新编译:
poky]$ source oe-init-build-env
build]$ bitbake core-image-sato -c cleanall
build]$ bitbake core-image-sato
- 1
- 2
- 3
编译完成后可以看到:
build]$ ls -l tmp-qemux86-64/work/qemux86_64-poky-linux/core-image-sato/1.0-r0/rootfs/sbin/init
lrwxrwxrwx 1 peeta peeta 22 3月 9 2018 tmp-qemux86-64/work/qemux86_64-poky-linux/core-image-sato/1.0-r0/rootfs/sbin/init -> ../lib/systemd/systemd #变成了systemd了
build]$ ls -l tmp-qemux86-64/work/qemux86_64-poky-linux/core-image-sato/1.0-r0/rootfs/etc/systemd/
total 48
-rw-r--r-- 1 peeta peeta 1052 3月 9 2018 journald.conf
-rw-r--r-- 1 peeta peeta 1072 3月 9 2018 logind.conf
drwxr-xr-x 2 peeta peeta 4096 3月 9 2018 network
-rw-r--r-- 1 peeta peeta 609 3月 9 2018 networkd.conf
-rw-r--r-- 1 peeta peeta 529 3月 9 2018 pstore.conf
-rw-r--r-- 1 peeta peeta 1035 3月 9 2018 resolved.conf
-rw-r--r-- 1 peeta peeta 790 3月 9 2018 sleep.conf
drwxr-xr-x 11 peeta peeta 4096 3月 9 2018 system
-rw-r--r-- 1 peeta peeta 1774 3月 9 2018 system.conf
-rw-r--r-- 1 peeta peeta 657 3月 9 2018 timesyncd.conf
drwxr-xr-x 2 peeta peeta 4096 3月 9 2018 user
-rw-r--r-- 1 peeta peeta 1197 3月 9 2018 user.conf
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
此时,可以将qemux86-64虚拟机运行起来看看哈。
手动添加systemd的启动脚本
我们以上一篇skeleton服务为例,来讲解如何在线手动创建systemd的启动脚本,以及如何实现开机自启动的。
首先我们登录qemux86-64虚拟机,继续以之前的然后通过vi命令创建一个systemd的service文件,参考如下:
root@qemux86-64:~# cd /lib/systemd/system
root@qemux86-64:/lib/systemd/system# vi skeleton.service
[Unit]
Description=Skeleton service
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/usr/bin/skeleton-test
RemainAfterExit=true
[Install]
WantedBy=multi-user.target
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
这里说明下
skeleton-test
程序很特别,他调用了
daemon()
函数,运行后脱离控制台,以守护进程形式在后台运行的程序,不像其他没有加’&'符号的进程那样,会一直占用控制台。因此,这里就需要告知
systemd
:它的类型是
oneshot
执行一次,而且程序退出了依旧认为程序在运行
RemainAfterExit = true
。当然读者盆友也可以尝试修改
service
文件,熟悉熟悉不同类型的启动方式,比如怎么通过它其他一个由脚本启动的程序,这里我就不过多的讲解systemd的相关知识了,感兴趣的盆友可以自行研究。编辑完成
service
后,我们尝试启动这个服务看看:
root@qemux86-64:~# systemctl start skeleton.service
root@qemux86-64:~# ps -ax | grep skeleton
271 ? Ss 0:00 /usr/sbin/skeleton-test
273 pts/0 S+ 0:00 grep skeleton
- 1
- 2
- 3
- 4
如上所示,已经成功了。
手动创建开机自启动
上面我们在
/lib/systemd/system
目录中创建了
skeleton.service
文件,只是添加了启动
skeleton-test
程序的启动规则,并没有实现是否需要开机自启动,如何实现呢?其实很简单,我们只需要在一个特定的目录中创建一个符号连接文件指向
skeleton.service
文件即可,参考如下:
root@qemux86-64:/lib/systemd/system# cd multi-user.target.wants/
root@qemux86-64:/lib/systemd/system/multi-user.target.wants# ln -sf ../skeleton.service
- 1
- 2
即在
multi-user.target.wants
目录中创建了一个指向它的符号连接文件即可实现开机自启动,大家可以reboot试试看,另外如果不想让他开机自启动了可以将该符号连接文件删除。
项目集成和验证
有了上面的操作经验之后我们就有了
systemd
实现自启动的理论基础了,说白了就是在特定目录中创建一个
service
文件和符号连接文件。
因此,将上面的工作整合到
yocto
的方法就很简单了,在bb文件中复制和连接即可。
- 首先创建service文件:
meta-mylayer]$ cd recipes-myapps/service/
service]$ vim service/skeleton.service.in #带个in表示模板文件的意思,其实也可以没有
[Unit]
Description=Skeleton service
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/usr/sbin/skeleton-test
RemainAfterExit=true
[Install]
WantedBy=multi-user.target
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
-
修改bb文件:
这里我想讲下,在yocto
中我们知道常见的两种启动方式就是sysvinit
和systemd
,两者启动文件等方式都不同,在yocto
中广泛的做法就是判断是否包含systemd
的feature
,并据此来安装sysvinit
或者systemd
的启动脚本,见下bb
文件:
meta-mylayer]$ cat recipes-myapps/service/service_0.1.bb
SUMMARY = "The canonical example of init scripts"
SECTION = "base"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://${WORKDIR}/COPYRIGHT;md5=349c872e0066155e1818b786938876a4"
SRC_URI = "file://skeleton \
file://skeleton.service.in \ #看这里
file://skeleton_test.c \
file://COPYRIGHT \
"
inherit update-rc.d systemd
INITSCRIPT_NAME = "skeleton"
INITSCRIPT_PARAMS = "defaults 99"
#INITSCRIPT_PARAMS = "start 99 2 3 4 5 . stop 09 0 5 6 1 ."
SYSTEMD_PACKAGES = "${PN}" #有了这三条语句,就不需要手动去创建符号连接文件了
SYSTEMD_SERVICE_${PN} = "skeleton.service"
SYSTEMD_AUTO_ENABLE = "enable"
do_compile () {
${CC} ${CFLAGS} ${LDFLAGS} ${WORKDIR}/skeleton_test.c -o ${WORKDIR}/skeleton-test
}
do_install () {
if ${@bb.utils.contains('DISTRO_FEATURES', 'sysvinit', 'true', 'false', d)}; then #如果有sysvinit,进入这个逻辑
install -d ${D}${sysconfdir}/init.d
cat ${WORKDIR}/skeleton | \
sed -e 's,/etc,${sysconfdir},g' \
-e 's,/usr/sbin,${sbindir},g' \
-e 's,/var,${localstatedir},g' \
-e 's,/usr/bin,${bindir},g' \
-e 's,/usr,${prefix},g' > ${D}${sysconfdir}/init.d/skeleton
chmod a+x ${D}${sysconfdir}/init.d/skeleton
fi
if ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)}; then #如果有systemd,进入这个逻辑
install -D -m 0644 ${WORKDIR}/skeleton.service.in ${D}${systemd_unitdir}/system/skeleton.service
#以前这里可能会有ln -sf xxx命令哈
fi
install -d ${D}${sbindir}
install -m 0755 ${WORKDIR}/skeleton-test ${D}${sbindir}/
}
RDEPENDS_${PN} = "initscripts"
CONFFILES_${PN} += "${sysconfdir}/init.d/skeleton"
FILES_${PN} += "${systemd_unitdir}" #看这里
FILES_${PN} += "${sbindir}" #看这里
PACKAGE_STRIP = "no"
INSANE_SKIP_${PN} := "installed-vs-shipped"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 单独编译验证:
build]$ bitbake service
build]$ ls tmp/work/core2-64-poky-linux/service/0.1-r0/image/lib/systemd/system/skeleton.service
tmp/work/core2-64-poky-linux/service/0.1-r0/image/lib/systemd/system/skeleton.service
- 1
- 2
- 3
-
全编译验证:
确定在multi-user.target.wants
目录中释放存在skeleton.service
的符号连接文件。
build]$ ls -l tmp/work/qemux86_64-poky-linux/core-image-sato/1.0-r0/rootfs/lib/systemd/system/multi-user.target.wants/
#不存在skeleton.service符号连接文件,还有一个地方,看下面
build]$ ls -l tmp/work/qemux86_64-poky-linux/core-image-sato/1.0-r0/rootfs/etc/systemd/system/multi-user.target.wants/
skeleton.service -> /lib/systemd/system/skeleton.service #存在
- 1
- 2
- 3
- 4
-
运行
qemux86-64
验证:
root@qemux86-64:~# ps -ax | grep skeleton
115 ? Ss 0:00 /usr/sbin/skeleton-test
- 1
- 2
运行成功!
至此我们的
systemd
的开机自启动完成!
谢谢阅读!您的点赞加收藏就是我持续更新的动力!