在并行 automake 中使用 help2man

Posted

技术标签:

【中文标题】在并行 automake 中使用 help2man【英文标题】:Use help2man in parallel automake 【发布时间】:2017-12-15 23:26:53 【问题描述】:

我正在开发一个使用 GNU 自动工具(autoconf、automake)构建的项目。它确实运行良好,但我遇到了 help2man 的问题:在构建并行 (MAKEFLAGS=-j3) 时,项目被构建了两次 - 一次使用“正常”目标,一次使用 foo.1 进行调用。

以下是来自Makefile.am的相关部分:

foo.1 : $(top_srcdir)/man/foo.x $(top_srcdir)/src/main.c $(top_srcdir)/configure.ac
    $(MAKE) $(AM_MAKEFLAGS) foo$(EXEEXT)
    -$(HELP2MAN) -o $@ --include $< $(top_builddir)/foo

所以,我的问题是如何编写Makefile.am 来支持以下内容:

    分发foo.1 以支持没有help2man 的系统 不要抛出错误 必要时重建联机帮助页

期待你的回答

【问题讨论】:

有什么想法吗? 【参考方案1】:

foo.1 需要正确的先决条件。 AIUI,help2man 只需要构建可执行二进制文件:

foo.1 : $(top_srcdir)/man/foo.x $(top_srcdir)/configure.ac $(top_builddir)/foo
        -$(HELP2MAN) -o $@ --include $< $(top_builddir)/foo

那就是 3)

不明白你想要从 2) 中得到什么,这通常是不可能的。

dist_man_MANS = foo.1

这是 1)

【讨论】:

我已经尝试过这个想法,但最终用户需要安装 help2man,因为即使源不更改,联机帮助页也会重建 用户不需要安装help2man,如果使用AC_CHECK_PROG搜索,AC_CHECK_PROG测试也可以通过@987654331conditional排除上面的foo.1规则@ 未安装。 但是,无论如何都要进行 distcheck faiks,因为手册页是在最终用户处重建的(如果可能的话),但不仅是在必要时。见gnu.org/software/automake/manual/html_node/… 添加CLEANFILES += $(dist_man_MANS) 使make distcheck(与foo.1 规则的条件相同)使用此方法通过。您可能想查看使用此方法的变体的GNU Hello(特别是 hello-2.10)。他们还在configure 期间测试交叉编译(help2man 在交叉编译期间会失败)。 是的,hello 解决方案有效。虽然它也经常反弹。我想我已经找到了另一个解决方案,我会稍后发布【参考方案2】:

这个问题似乎没有简单的解决方案;以下对我有用。

configure.ac,你必须检查 help2man。如果交叉编译,你不能运行 help2man,因为可执行文件会被运行。因此包含以下 sn-p:

# Man pages
AS_IF([test "$cross_compiling" = "no"], [
    AM_MISSING_PROG([HELP2MAN], [help2man])
], [
    HELP2MAN=:
])

对于建筑,有两个层次的概念。首先,检查联机帮助页是否比可执行文件新;如果是这样,为了禁止不必要的联机帮助页重建,您可以使用联机帮助页本身最后一次更改的临时文件检查源。所以,Makefile.am 包含:

dist_man_MANS = foo.1
EXTRA_DIST += $(dist_man_MANS:.1=.x) common.x
MOSTLYCLEANFILES += $(dist_man_MANS:=-t)
MAINTAINERCLEANFILES += $(dist_man_MANS)

common_dep = $(top_srcdir)/common.x $(top_srcdir)/configure.ac $(top_srcdir)/.version
common_indirect_dep = $(top_srcdir)/common.x $(top_srcdir)/configure $(top_srcdir)/.version
foo.1 : $(common_indirect_dep) $(top_builddir)/foo$(EXEEXT)
foo.1-t : $(common_dep) $(top_srcdir)/main-helpversion.c

SUFFIXES += .x .1 .1-t
.x.1:
    test -f $@ || if test -f $(top_srcdir)/`echo $@ | $(SED) -e 's,.*/,,'`; then \
        touch -r $(top_srcdir)/`echo $@ | $(SED) -e 's,.*/,,'` $@; \
    else \
        touch -d @0 $@; \
    fi
    touch -r $@ $@-t
    $(MAKE) $(AM_MAKEFLAGS) $@-t
    if test -s $@-t; then \
        mv -f $@-t $@; \
    else \
        rm -f $@-t; \
        if test -s $@; then touch $@; else rm -f $@; fi; \
    fi
.x.1-t:
    $(HELP2MAN) -o $@ -I $< -I $(top_srcdir)/common.x -s 1 foo$(EXEEXT)

【讨论】:

其中一个缺点是 make -j3 重新引入了 foo$(EXEEXT) 的构建竞赛,你说你最初试图避免...... 你确定吗?我认为,我的(GNU)make 解决了这个问题。想象一下目标 A 和 B 是并行构建的,而 B 依赖于 A(这是上面的示例简化);据我所知,make 可以正确解决这个问题 使用 GNU make 4.0.您重新引入了原始示例的递归构造(具有更多保护)。在干净的状态下,这种保护不存在,我得到了两次调用来构建foo$(EXEXT)

以上是关于在并行 automake 中使用 help2man的主要内容,如果未能解决你的问题,请参考以下文章

在 automake 中使用条件

如何在 autoconf/automake 中使用协议缓冲区?

在 automake 中使用通配符

有没有办法在 Automake 中引用库?

Automake:使用 make dist 删除配置脚本检查

在 Makefile.am(automake) 中使用 if 语句