【问题标题】:Install systemd service using autotools使用 autotools 安装 systemd 服务
【发布时间】:2020-01-20 20:50:18
【问题描述】:

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

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

使用 AC_CONFIG_HEADERS 是否适合将 *.service.in 修补到 *.service 中?是否有另一个宏用于“非标题”?

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

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

【问题讨论】:

  • 关于您的评论,“出于某种原因,它用 ${exec_prefix}/bin 替换了@bindir@”,这是应该发生的。请参阅 GNU Coding Standards7.2.5 Variables for Installation Directories。您可以为--prefix--exec_prefix(或--sysconfdir)指定不同的值,但问题的根本原因是不同的。问题是由于编码标准和 Autotools 的限制。它不能同时处理系统和用户安装的软件。
  • 也许你需要两个 makefile。第一次在/usr/local/opt/<package> 中构建并安装您的软件。第二个在/etc 中安装系统计时器和服务。我不知道 Autotools 是否会更好地处理双 makefile。 Autotools 实在是太有限了,而且漏洞百出。考虑一下,Fedora 在 2013 年切换到 Systemd,在 2015 年切换到 Debian。Autotools 的人已经有 7 年的时间来解决这个问题,但他们完全没有做任何事情。
  • 另见Install binaries into /bin, /sbin, /usr/bin and /usr/sbin, interactions with --prefix and DESTDIR,这似乎与您的问题非常相似。 @WilliamPursell 的回答看起来像是采用了“拆分”的方法,但我没有详细研究过。最后,你想出的双 makefile、Purcell 的 hack 和其他回转是由于编码标准的不足和 Autotools 中的错误。如果一切都完全指定,你就不会有这些麻烦。
  • 我知道你已经在你自己的 repo 中修复了这个问题,但是为了将来的问题读者的利益:你根本不应该在 /etc/systemd/ 中安装 systemd 单元文件。它们应该安装在 systemd 单元目录中,很可能是 ${libdir}/systemd/system/${libdir}/systemd/user/systemctl enable 命令将使符号链接成为/etc/systemd/(system|user)。如果安装了systemd.pc,您可以使用pkg-config --variable=systemd_system_unit_dir systemdpkg-config --variable=systemd_user_unit_dir systemd 或它们的自动工具等效项查询路径。

标签: systemd autotools


【解决方案1】:

如何指定服务文件应该登陆(即安装)在 /etc/systemd/system 中?

根据Systemd的daemon man page


安装 systemd 服务文件

在构建安装时(例如,在包构建期间make install),建议将包安装在pkg-config systemd --variable=systemdsystemunitdir(用于系统服务)或pkg-config systemd --variable=systemduserunitdir(用于用户服务)返回的目录中。这将使系统中的服务在明确请求时可用,但不会在引导期间自动激活它们。可选地,在软件包安装过程中(例如管理员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"])

这个 sn-p 允许在 systemd 机器上自动安装单元文件,并且可以选择允许在缺少 systemd 的机器上安装它们。 (对用户单元目录的这个sn-p的修改留给读者练习。)

另外,为确保 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 对它的支持如何,嗯...

在 Fedora 31 上使用 grep systemdsystemunitdir /bin/autoconfgrep -IR systemdsystemunitdir /usr/share 快速 grep 显示尚不支持 Autotools。 7 年了……


有没有更好的方法在没有 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"])

【讨论】:

    【解决方案2】:

    使用 AC_CONFIG_HEADERS 是否适合将 *.service.in 修补到 *.service 中?是否有另一个宏用于“非标题”?

    没有。 AC_CONFIG_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)' < $< > $@
    

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

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

    sytemdsysdir = $(sysconfdir)/systemd/system
    
    systemdsys_DATA = AutoBrightnessCam.service
    

    有没有更好的办法 在没有 systemd 的情况下在启动时启动此应用?

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

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

    这里有不同意见的余地,但我认为其中第一个是最干净和最适合未来的,我不推荐最后一个。

    【讨论】:

    • 使用 make 使用 sed 构建服务文件听起来是一个非常好的主意。到目前为止,我设法告诉 autoconf 进行替换,但由于某种原因,它用 ${exec_prefix}/bin 替换了@bindir@,然后我可以通过 make 修复它。 (或者只使用@prefix@/bin,虽然这不是那么便携)。
    • 是的,@John,这正是我要说的。
    • 感谢您提供统一命名方案的链接。这就是我需要为我的脚本定义一个自定义安装目录。
    猜你喜欢
    • 2017-02-28
    • 2020-04-25
    • 1970-01-01
    • 1970-01-01
    • 2017-10-03
    • 2018-12-23
    • 1970-01-01
    • 1970-01-01
    • 2019-12-13
    相关资源
    最近更新 更多