6

installcheck构建库时如何实现 make目标?也就是说,我有一个check目标,它创建一个链接到创建的库的测试程序,由一些脚本调用以检查库代码是否正常运行,我希望执行相同的检查,但在它有之后链接到库已安装;我该如何实施?

4

1 回答 1

6

由于我找不到这方面的任何指南,我将介绍我想出的方法,该方法是通过阅读GNU automake 手册和一些一般性的试验和错误来修补的。它可能很难看,但它确实有效......

如果构建库的检查例程涉及将库链接到测试程序并查看该程序是否正常工作,那么要安装检查库,我们只需要做同样的事情,但将测试程序链接到已安装的库而不是本地构建的库图书馆。

让我们调用库alpha(因此我们将创建libalpha.so和/或libalpha.a)。假设 alpha 的源代码在 src 目录下的 alpha.cpp 文件中我们将照常创建src/Makefile.am :

# src/Makefile.am

lib_LTLIBRARIES = libalpha.la
libalpha_la_SOURCES = alpha.cpp
include_HEADERS = alpha.h

检查例程涉及创建链接到alpha的二进制betabeta的源代码在目录tests的beta.cpp文件中。自动生成文件tests/Makefile.am如下所示:

# tests/Makefile.am

check_PROGRAMS = beta
beta_SOURCES = beta.cpp
beta_CPPFLAGS = -I$(top_srcdir)/src
beta_LDADD = $(top_builddir)/src/libalpha.la

我们将通过在tests/Makefile.amcheck中创建“本地”目标来创建我们的和installcheck例程,如下所示:

# tests/Makefile.am

# ...

check-local:
    # recipe to run when 'make check' is called.

installcheck-local:
    # recipe to run when 'make installcheck' is called.

check和目标冲突,installcheck因为使用任何一个目标都会阻止另一个目标正确执行(一个目标“污染”另一个目标的构建树);为了使另一个目标正确执行,我们需要删除beta及其目标文件,并根据其性质(installcheck安装文件、check本地文件)重新编译和重新链接目标。

make clean我们可以通过简单地在两个目标的配方中运行来解决这个被污染的构建树的问题。这将清楚地删除受污染的构建,但过于热心,因为每当我们再次运行相同的目标时我们都不需要重新构建。仅当我们运行另一个目标时,构建树才会受到污染。

我们只能通过记住之前调用过的两个目标中的哪一个来解决这个复杂问题,我们可以通过创建/销毁中间文件(我们称之为taint)来解决这个问题。check只要文件taint存在,目标就会被污染,它通过清理、重建和删除taint来解决;installcheck当文件taint不存在时,目标被污染,它通过清理、重建和创建taint解决。

我们的目标将采取以下形式:

# tests/Makefile.am

# ...

check-local:
      # First, check to see if the build tree is tainted and rebuild if so
    test ! -f taint || $(MAKE) $(AM_MAKEFLAGS) check_rebuild
      # Then, run our check tests. Substitute with your shell scripts or testsuite files as appropriate
    ./beta

installcheck-local:
      # First, check to see if the build tree is tainted and rebuild if so
    test -f taint || $(MAKE) $(AM_MAKEFLAGS) installcheck_rebuild
      # Then, run our installcheck tests. Substitute with your shell scripts or testsuite files as appropriate
    ./beta

目标check_rebuild需要根据check运行方式进行重建,看起来像这样:

# tests/Makefile.am

# ...

.PHONY: check_rebuild
check_rebuild:
    $(MAKE) $(AM_MAKEFLAGS) clean          # remove tainted build tree
    $(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT)  # rebuild beta
    rm -f taint                            # mark build tree as untainted

目标installcheck_rebuild同样如下所示:

# tests/Makefile.am

# ...

.PHONY: installcheck_rebuild
installcheck_rebuild:
    $(MAKE) $(AM_MAKEFLAGS) clean          # remove tainted build tree
    $(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT) \
      beta_CPPFLAGS="-I$(DESTDIR)$(includedir)" \
      beta_LDADD="$(DESTDIR)$(libdir)/libalpha.la" \
      beta_DEPENDENCIES="$(DESTDIR)$(libdir)/libalpha.la"
    echo 1 > taint                         # mark build tree as untainted

请注意,现在重建beta需要installcheck_rebuild覆盖 automake 变量,以便它们指向已安装的库。

最后,我们需要添加 taint 文件,DISTCLEANFILES以便运行distcheck不会因“distclean 后遗留在构建目录中的文件”错误而失败。

应该就是这样。最终的测试/Makefile.am应该如下所示:

# tests/Makefile.am

check_PROGRAMS = beta
beta_SOURCES = beta.cpp
beta_CPPFLAGS = -I$(top_srcdir)/src
beta_LDADD = $(top_builddir)/src/libalpha.la

taint_file = .taint

check-local:
    test ! -f $(taint_file) || $(MAKE) $(AM_MAKEFLAGS) check_rebuild
    ./beta # substitute with your actual test routines

installcheck-local:
    test -f $(taint_file) || $(MAKE) $(AM_MAKEFLAGS) installcheck_rebuild
    ./beta # substitute with your actual test routines

.PHONY: check_rebuild
check_rebuild:
    $(MAKE) $(AM_MAKEFLAGS) clean
    $(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT)
    rm -f $(taint_file)

.PHONY: installcheck_rebuild
installcheck_rebuild:
    $(MAKE) $(AM_MAKEFLAGS) clean
    $(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT) \
      beta_CPPFLAGS="-I$(DESTDIR)$(includedir)" \
      beta_LDADD="$(DESTDIR)$(libdir)/libalpha.la" \
      beta_DEPENDENCIES="$(DESTDIR)$(libdir)/libalpha.la"
    echo 1 > $(taint_file)

DISTCLEANFILES = $(taint_file)

免责声明

这已在 Linux 上检查为“标准”构建,但它可能不适用于其他构建环境,或者您正在尝试做一些“异国情调”的事情。希望它应该,但这不是我费心去检查的东西。如果有错误,问题很可能是我上面的一个目标中缺少或误用的变量。

例如,check_rebuild目标具有以下行:

check_rebuild:
    # ...
    $(MAKE) $(AM_MAKEFLAGS) beta$(EXEEXT)
    # ...

变量$(AM_MAKEFLAGS)$(EXEEXT)是 automake 本身如何创建例程以填充它创建的 Makefile 的一部分,如果我在上面的目标中忽略了它们,那么它可能会导致构建失败(或者至少不能按预期运行)。

我试图确保我上面建议的目标同样是规范构建的,但我可能遗漏了一些东西。如果出现构建错误,最好的办法是在构建过程中打开 automake 自身生成的 Makefile,查看它是如何创建对象并在相应的 Makefile.am 文件中模仿这些结构的,就像我尝试做的那样。

另一个可能的问题可能是我在目标中构建beta二进制文件的“hackish”方式installcheck_rebuild。同样,诊断问题的最佳选择是查看 automake 在它生成的 Makefile 中是如何做事的,并尝试模仿它。否则,阅读 automake 手册是有必要的,如果做不到这一点,你可能需要比我更有知识的人的帮助。祝你好运。

于 2013-08-14T19:38:33.320 回答