使用 autotools 安装 systemd 服务

Install systemd service using autotools

我有一个 autotools 项目,它成功地构建和测试了一个应用程序 (https://github.com/goglecm/AutoBrightnessCam)。该应用程序安装在 bin 目录中(前面有用户指定的任何前缀)。这很简单。我现在需要制作一个 systemd 服务以在启动时启动它。我已经创建了服务文件并 运行 手动创建它并且工作正常。

最后一点是告诉 configure.ac 和 Makefile.am 使用正确的应用程序路径修补 *.service.in 文件(就像创建 config.h来自 config.h.in).

使用 AC_CONFIG_HEADERS 是否适合将 *.service.in 打补丁到 *.service 中? "non-headers" 是否还有另一个宏?

此外,我如何指定服务文件应该登陆(即安装)/etc/systemd/system?

是否有更好的方法在没有 systemd 的情况下在启动时启动此应用程序?

Will using AC_CONFIG_HEADERS be appropriate to patch *.service.in into *.service? Is there another macro used for "non-headers" perhaps?

没有。 AC_CONFIG_HEADERS 用于设置配置 headers 以支持您的构建。除了构建一个 config.h 记录 Autoconf 执行的某些测试的结果外,它很少用于其他用途,并且它不像该领域的其他选项那样灵活。

如果您有其他文件希望 Autoconf 从模板构建,那么您应该通过 AC_CONFIG_FILES 告知 Autoconf。示例:

AC_CONFIG_FILES([Makefile AutoBrightnessCam.service])

但是,如果您填充该模板的某些数据是安装目录,那么 Autoconf 可能根本不是执行此操作的正确位置,因为它规定安装前缀可以通过 make。您至少需要解决这个问题,但最好的办法是顺其自然,并在 make 的控制下构建 .service 文件。这并不难,而且有几个技术优势,即使没有任何安装目录替换需要担心,也有一些应用。

您可以采用与 configure 相同的方式,通过 运行 您已经通过 sed 使用的完全相同的模板,并使用适当的脚本。像这样的东西会出现在你的 Makefile.am:

SERVICE_SUBS = \
    s,[@]VARIABLE_NAME[@],$(VARIABLE_NAME),g; \
    s,[@]OTHER_VARIABLE[@],$(OTHER_VARIABLE),g

AutoBrightnessCam.service: AutoBrightnessCam.service.in
    $(SED) -e '$(SERVICE_SUBS)' < $< > $@

Also, how do I specify that the service file should land (i.e. installed) in /etc/systemd/system?

您使用Automake's standard mechanism for specifying custom installation locations。也许是这样的:

sytemdsysdir = $(sysconfdir)/systemd/system

systemdsys_DATA = AutoBrightnessCam.service

Is there perhaps a better way of starting this app at boot time without systemd?

在 systemd-based 机器上,systemd 控制启动时的内容。如果您希望机器在开机时自动启动您的应用程序,那么我认为您的选择仅限于

  • 正在配置 systemd 以启动它
  • 在最终由 systemd 启动的程序链中配置某些内容以启动它
  • 破解引导加载程序或内核以启动它

这里有不同意见的余地,但我认为第一个最干净,最future-proof,我不推荐最后一个。

How do I specify that the service file should land (i.e. installed) in /etc/systemd/system?

根据 Systemd 的 daemon man page:


正在安装 systemd 服务文件

在构建安装时(例如 make install 在包构建期间),建议包将其 systemd 单元文件安装在 pkg-config systemd --variable=systemdsystemunitdir(用于系统服务)或 [=17 返回的目录中=](用于用户服务)。这将使服务在明确请求时在系统中可用,但不会在引导期间自动激活它们。可选地,在软件包安装期间(例如 rpm -i 由管理员),符号链接应该通过 systemctl(1) 工具的启用命令在 systemd 配置目录中创建,以便在启动时自动激活它们。

建议使用autoconf(1)的包使用如下配置脚本摘录来确定源配置期间的单元安装路径:

PKG_PROG_PKG_CONFIG
AC_ARG_WITH([systemdsystemunitdir],
     [AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],,
     [with_systemdsystemunitdir=auto])
AS_IF([test "x$with_systemdsystemunitdir" = "xyes" -o "x$with_systemdsystemunitdir" = "xauto"], [
     def_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)

     AS_IF([test "x$def_systemdsystemunitdir" = "x"],
   [AS_IF([test "x$with_systemdsystemunitdir" = "xyes"],
    [AC_MSG_ERROR([systemd support requested but pkg-config unable to query systemd package])])
    with_systemdsystemunitdir=no],
   [with_systemdsystemunitdir="$def_systemdsystemunitdir"])])
AS_IF([test "x$with_systemdsystemunitdir" != "xno"],
      [AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])])
AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemdsystemunitdir" != "xno"])

此代码段允许在 systemd 机器上自动安装单元文件,并可选择允许在没有 systemd 的机器上安装它们。 (对用户单元目录的此片段的修改留作 reader 的练习。)

此外,为确保 make distcheck 继续工作,建议将以下内容添加到基于 automake(1) 的项目的顶级 Makefile.am 文件中:

AM_DISTCHECK_CONFIGURE_FLAGS = \
  --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)

最后,单元文件应安装在系统中,并带有如下所示的 automake 摘录:

if HAVE_SYSTEMD
systemdsystemunit_DATA = \
  foobar.socket \
  foobar.service
endif

...

看来您应该使用 systemdsystemunitdirsystemduserunitdir。 Autotools 对它的支持有多好,嗯...

使用 grep systemdsystemunitdir /bin/autoconfgrep -IR systemdsystemunitdir /usr/share 在 Fedora 31 上进行的快速 grep 显示尚无 Autotools 支持。 7 年还在继续......


Is there perhaps a better way of starting this app at boot time without systemd?

Systemd 应该可以启动您的应用程序。只需像往常一样使用 systemctl(1) 启用和启动它们。

基于您的 GitHub and autobrightnesscam.service.in,我不会为此使用 Autotools。您可能会浪费大量时间解决 Autotols 的缺点(根据经验)。

我的 configure.ac 脚本(只是一个 shell 脚本)会将 autobrightnesscam.service.in 复制到 autobrightnesscam.service,然后使用 sed 复制正确的目录和文件。然后,我会将更新后的 autobrightnesscam.service 复制到 AC_CONFIG_COMMANDS_POST 中的正确位置。也许是这样的:

SERVICE_FILE=autobrightnesscam.service
SYSTEMD_DIR=`pkg-config systemd --variable=systemdsystemunitdir`

# Use default if SYSTEMD_DIR is empty
if test x"$SYSTEMD_DIR" = "x"; then
    SYSTEMD_DIR=/etc/systemd/system
fi

AC_CONFIG_COMMANDS_POST([cp "$SERVICE_FILE" "$SYSTEMD_DIR"])
AC_CONFIG_COMMANDS_POST([systemctl enable "$SYSTEMD_DIR/$SERVICE_FILE"])
AC_CONFIG_COMMANDS_POST([systemctl start "$SERVICE_FILE"])