【问题标题】:Automake, GNU make, check, and (ignored) pattern rulesAutomake、GNU make、check 和(忽略的)模式规则
【发布时间】:2013-02-18 19:43:05
【问题描述】:

我有以下 Makefile.am,它应该从 foo.h(通过 Python 脚本)创建 foo.hdbfoo.cdb

TESTS = check_foo

check_PROGRAMS = check_foo

check_foo_SOURCES = check_foo.c $(top_builddir)/src/isti.h \
    foo.cdb foo.h foo.hdb
check_foo_CFLAGS = @CHECK_CFLAGS@ $(all_includes) -I../../clib/src/
check_foo_LDADD = $(top_builddir)/src/libcorm.la @CHECK_LIBS@ -lsqlite3

%.hdb %.cdb: %.h
    PYTHONPATH=$(top_builddir)/cgen/src python $(top_builddir)/cgen/src/isti/cgen/run.py $<

clean-local:
    rm -f *.hdb *.cdb

然而,虽然make foo.hdbmake foo.cdb 工作(调用Python 代码并从foo.h 生成foo.hdbfoo.cdb 文件),make clean check(或两个单独)不能(缺少@ 987654333@ - 没有这样的文件) - 不调用模式规则从 foo.h 生成 foo.hdb

换句话说:没有为 check_foo_SOURCES 中列出的文件调用模式规则

我怎样才能做到这一点?其余的 autotools 基础设施工作正常。通过查看 Makefile,我怀疑问题在于 autotools 如何扩展检查源。

这一切都在使用 Gnu make 的 Linux 上。这里是the Makefile

[略微更新以反映来自 MadScientist 的帮助]。

稍后更新

以下 Makefile(只是 make,而不是 autotools)工作正常,因此问题似乎与 autotools 和检查支持有关。

all: check_foo

CFLAGS=-I../../clib/src
LDFLAGS=-L../../clib/src/.libs

check_foo: check_foo.c foo.h corm_foo.h corm_foo.c
    gcc $(CFLAGS) $(LDFLAGS) $^ -o $@ -lcorm -lsqlite3

corm_%.h corm_%.c: %.h
    PYTHONPATH=../../cgen/src python ../../cgen/src/isti/cgen/run.py $<

clean:
    rm -f corm_*.h corm_*.c
    rm -f *.o

(请注意,我已从 xxx.hdb 切换到 corm_xxx.h 等,因此文件扩展名保持正常)。

更多详情

因为好像和CHECK宏有关,所以这里是configure.ac:

AC_INIT([corm], [0.1], [a.cooke@isti.com])
AC_CONFIG_MACRO_DIR([m4])
PKG_CHECK_MODULES([CHECK], [check >= 0.9.4]) 
AM_INIT_AUTOMAKE([-Wall foreign -Werror])
AC_PROG_CC_C99
AM_PROG_CC_C_O
LT_INIT
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([Makefile clib/Makefile clib/src/Makefile clib/tests/Makefile clib/docs/Makefile cgen/Makefile cgen/docs/Makefile example/Makefile example/src/Makefile])
AC_CHECK_PROGS([DOXYGEN], [doxygen], AC_MSG_WARN([Doxygen not found - continuing without Doxygen support]))
AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"])
AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([clib/docs/Doxyfile cgen/docs/Doxyfile])])

解决方案

好的,总结下面的各种事情,有两个重要问题(一旦我修复了文件扩展名 - 请参阅“普通”makefile 和 fceller 的答案),其中任何一个都足以让事情正常工作:

  1. (处理)头文件很复杂。由于自动依赖,以编程方式生成的头文件会破坏事物。解决方法是使用BUILT_SOURCES

  2. 但是(处理).c 文件并不复杂。因此,将 corm_foo.c 放在 check_foo.c 前面会触发该文件的生成。因为这也会生成 corm_foo.h,所以一切正常(因为 check_foo.c 现在可以包含 corm_foo.h)。

此外,fceller 对整洁的 makefile 有一些很好的一般观点,并解释了为什么“普通”makefile 可以工作。

【问题讨论】:

  • 你的Makefile 是什么?如果问题太大,您能否将其添加到粘贴箱中
  • 嗨 - 我已将它(pastebin 链接)添加到问题中,谢谢。
  • find . -name foo.hdb 输出什么?
  • make foo.hdb 创建 foo.hdb,但它被make clean check 中的clean 删除(请参阅 clean-local 目标)。所以,如果我在make clean 之后执行find,它什么也不会显示。也许我误解了你的问题,但我认为你走错了路(上面的 Makefile.am 位于没有子目录的目录中)。
  • 你试过加BUILT_SOURCES = foo.hdb吗?

标签: c makefile autotools check-framework


【解决方案1】:

线

%.cdb: %.hdb

什么都不做。查看 GNU make 手册,您会看到没有命令行的模式规则用于删除先前定义的具有相同模式的规则。由于没有以前的规则,这本质上是一个无操作。

如果您有一个命令使用一个规则调用创建两个输出文件,那么您需要将两个模式放在同一规则中,如下所示:

%.cdb %.hdb: %.h
        PYTHONPATH=$(top_builddir)/cgen/src python $(top_builddir)/cgen/src/isti/cgen/run.py $<

这将告诉 GNU make 两个目标都是通过一次调用规则生成的。意识到!此语法仅对模式规则具有此行为。具有多个目标的显式规则会做一些完全不同的事情(令人困惑)。

至于make clean 的行为,我不确定。 automake 生成的 makefile 太复杂了,我无法阅读它;它需要一些调试(运行它并跟踪发生了什么)。但是,我怀疑那里的规则设计不正确,无法允许clean 目标和构建目标在同一次 make 调用中运行。分别运行这两个命令,看看效果是否更好:

make clean
make check

【讨论】:

  • 感谢 hdb/cdb 的修复(我已按照显式规则的多个输出的说明进行操作)。但是,这不会影响主要问题(与清洁无关 - 单独执行它们有相同的问题)。很抱歉发布(回想起来)一个有两个问题的问题 - 我不想让它变得正确,因为它不能让事情正常工作(但有一个赞成!)。另外,我将更新问题以反映此答案。再次感谢。
【解决方案2】:

首先:您不需要在 *_SOURCES 中包含“*.h”。 automake 将生成代码来生成依赖项。来自手册: _SOURCES 定义中列出的头文件将包含在分发中,否则会被忽略

您在普通 Makefile 中所做的更改(“请注意,我已从 xxx.hdb 切换到 corm_xxx.h 等,因此文件扩展名保持正常”)是必不可少的。 automake 使用文件扩展名过滤 *_SOURCES 列表,以查看要调用的内容(CC、CXX、F77)。

以下 Makefile.am 将起作用:

TEST = check_foo

check_PROGRAMS = check_foo

check_foo_SOURCES = check_foo.c foo.db.c
check_foo_CFLAGS = 
check_foo_LDADD = 

%.db.c %.db.h: %.h
    echo "int i = 1;" > foo.db.c
    echo "int j;" > foo.db.h

clean-local:
    rm -f *.db.h *.db.c

【讨论】:

  • 没有解决问题 - 它需要交换 .c 文件的顺序,或者使用 BUILT_SOURCES。这是有道理的,但我不明白为什么我提供的“普通”makefile 有效。无论如何,感谢关于整理的一般建议。
  • 如果您不包含“foo.db.h”,则上述工作。如果在“check_foo.c”中包含“foo.db.h”,则需要 BUILT_SOURCE
  • 如果您不包含“foo.db.h”,则上述工作。如果你在“check_foo.c”中包含“foo.db.h”,你要么需要使用 BUILT_SOURCE,因为在你第一次做 make 时,依赖项还没有生成,所以 make 不知道“check_foo.c”需要“foo.db.h”(您会注意到,如果您执行一次“make -k”并生成 .deps 文件,它会起作用)。颠倒文件的顺序并没有帮助,因为“make -j 2”仍然会中断。
  • 您提供的 makefile 的工作方式不同:自动生成的 Makefile 会自行编译每个文件,允许并行生成。您的 makefile 在一个命令中编译所有内容 - 因此 make 必须在开始编译之前生成所有文件。
【解决方案3】:

您需要告诉 automake foo.hdb 是一个要构建的源文件。将以下内容添加到 Makefile.am:

BUILT_SOURCES = foo.hdb

【讨论】:

  • @fceller 非常有帮助,但正是这条评论让我明白了发生了什么。谢谢。
【解决方案4】:

让我尝试在现有的直接答案/讨论中添加一个间接答案/讨论。

我最近离开 make 的原因与您遇到的相同:它非常强大,但有时当事情不按预期进行时,调试起来有点困难。

我最近发现了pydoit,它非常有希望作为 make 的可调试替代构建工具。由于其中没有“模式规则”的概念,我提出了一个独立的包来完成这项工作:fprules

这就是您使用doitfprules 执行您在帖子中提到的相同任务的方式:

from fprules import file_pattern

# all: check_foo
DOIT_CONFIG = {'default_tasks': ['check_foo']}

CFLAGS = '-I../../clib/src'
LDFLAGS = '-L../../clib/src/.libs'

# check_foo: check_foo.c foo.h corm_foo.h corm_foo.c
#     gcc $(CFLAGS) $(LDFLAGS) $^ -o $@ -lcorm -lsqlite3
def task_check_foo():
    """
    Compiles the `check_foo` executable
    """
    src_files = ('check_foo.c', 'foo.h', 'corm_foo.h', 'corm_foo.c')
    dst_file = 'check_foo'
    return {

        'file_dep': src_files,
        'actions': ["gcc %s %s %s -o %s -lcorm -lsqlite3" % (CFLAGS, LDFLAGS, ' '.join(src_files), dst_file)],
        'verbosity': 2,
        'targets': [dst_file],
        'clean': True
    }

# corm_%.h corm_%.c: %.h
#     PYTHONPATH=../../cgen/src python ../../cgen/src/isti/cgen/run.py $<
def task_gen_corm():
    """
    Generates files `corm_%.h` and `corm_%.c`
    for each header file `%.h`.
    """
    for data in file_pattern('./*.h', dict(h_file='./corm_%.h', c_file='./corm_%.c')):
        yield {
            'name': data.name,
            'file_dep': [data.src_path],
            'actions': ["PYTHONPATH=../../cgen/src python ../../cgen/src/isti/cgen/run.py %s" % data.src_path],
            'verbosity': 2,
            'targets': [data.h_file, data.c_file],
            'clean': True
        }

# clean:
#     rm -f corm_*.h corm_*.c
#     rm -f *.o
# No need to create tasks for this: 
# with 'clean': True, `doit clean` will clean all target files

然后只需在文件夹中运行doit

如有需要,请随时在项目页面上提供反馈:例如,不支持多行命令,如果您也觉得缺少它们,可以为它们投票:https://github.com/pydoit/doit/issues/314

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-11
    • 1970-01-01
    • 1970-01-01
    • 2022-12-02
    相关资源
    最近更新 更多