1

我有以下 Makefile.am 应该创建foo.hdbfoo.cdb来自foo.h(通过 Python 脚本):

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.hdbandmake foo.cdb工作(调用 Python 代码并从 生成foo.hdbandfoo.cdb文件foo.h),make clean check(或两者分开)不能(缺少foo.hdb- 没有这样的文件) - 不调用模式规则foo.hdbfoo.h.

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

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

这都是在带有 Gnu make 的 Linux 上。这是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 可以工作。

4

4 回答 4

2

线

%.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
于 2013-02-19T22:51:30.673 回答
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
于 2013-02-22T18:44:20.830 回答
1

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

BUILT_SOURCES = foo.hdb
于 2013-02-23T21:01:12.680 回答
0

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

我最近离开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

于 2019-08-01T16:58:02.147 回答