2

我怀疑手册实际上是在说我做错了什么,但我真的看不到解决方案;当 .c 文件和要构建的 .o 文件不在同一个目录中时,就会出现问题,并且 .c 文件对必须动态生成的 .h 文件具有自动依赖关系。该问题可能可以通过手动设置 .c 和 .h 文件之间的依赖关系来解决,但我想避免这种情况。

我有以下目录结构:

weird/
    Jamfile
    b.c
    src/
        a.c
        c.c

src/ac 文件是这样的:

#include "src/a.h"

int main(int argc, char *argv[])
{
    return 0;
}

bc 文件是这样的:

#include "src/b.h"

int main(int argc, char *argv[])
{
    return 0;
}

src/cc 文件是这样的:

#include "c.h"

int main(int argc, char *argv[])
{
    return 0;
}

Jamfile 是:

rule CreateHeader
{
    Clean clean : $(1) ;
}

actions CreateHeader
{
    echo "int x = 10;" > $(1)
}

Object a.o : src/a.c ;
Object b.o : b.c ;
Object c.o : src/c.c ;

CreateHeader src/a.h ;
CreateHeader src/b.h ;
CreateHeader src/c.h ;

以下命令正确创建 bo 和 src/bh:

jam b.o

下面的命令创建了src/ah,但是后来gcc创建ao失败了;原因很明显,ac 中的#include 提到了 src/ah,而实际上应该只是指 ah:

jam a.o

以下命令完全失败,甚至没有创建 ch;原因可能是 Jam 在分析 cc 时会生成对 ch 而不是 src/ch 的依赖,并且在 Jamfile 中没有生成 ch 的规则:

jam c.o

如果我在请求 co 之前明确要求生成 src/ch,则此命令可以正确编译:

jam src/c.h
jam c.o

在我看来,果酱 src/ch 不应该是必要的。这里有什么问题?查看Jam 手册以获取更多信息,特别是在标题文件扫描部分下。

在我接受答案后添加

我一直在对已接受答案的作者建议的结构进行一些试验,我将在此处发布结果。在此设置中,您可以键入:

jam app

并且应用程序将链接到 bin/app 下。不幸的是,我在设置 LOCATE_TARGET 时必须使用 UNIX 路径,我的理解是这并不是一个好的做法。

目录结构:

project/
    Jamfile
    src/
        main.c
    gen/
    bin/
        obj/

文件 Jamfile:

SubDir TOP ;

rule CreateHeader
{
    MakeLocate $(1) : $(LOCATE_SOURCE) ;
    Clean clean : $(1) ;
}

actions CreateHeader
{
    BUILD_DATE=`date`
    echo "char build_date[] = \"$BUILD_DATE\";" > $(1)
}

SEARCH_SOURCE = src ;
LOCATE_TARGET = bin/obj ;
SubDirHdrs gen ;
Object main.o : main.c ;

LOCATE_TARGET = bin ;
MainFromObjects app : main.o ;

LOCATE_SOURCE = gen ;
CreateHeader info.h ;

文件 src/main.c

src/main.c
#include <stdio.h>
#include "info.h"

int main(int argc, char *argv[])
{
    printf("Program built with Jam on %s.\n", build_date);

    return 0;
}
4

1 回答 1

2

更改所有 #include 指令以省略路径(即 '#include "ah' 等)并将 Jamfile 更改为以下内容将解决您的问题:

SubDir TOP ;

SEARCH_SOURCE += [ FDirName $(SUBDIR) src ] ;
LOCATE_SOURCE = [ FDirName $(SUBDIR) src ] ;

rule CreateHeader
{
    MakeLocate $(1) : $(LOCATE_SOURCE) ;
    Clean clean : $(1) ;
}

actions CreateHeader
{
    echo "int x = 10;" > $(1)
}

Object a.o : a.c ;
Object b.o : b.c ;
Object c.o : c.c ;

CreateHeader a.h ;
CreateHeader b.h ;
CreateHeader c.h ;

以下是详细信息:

  • SubDir 应始终在 Jamfile 中调用。它设置了几个有用的(在某些情况下是必要的)变量,包括此处使用的 SUBDIR、SEARCH_SOURCE 和 LOCATE_SOURCE。
  • 将“src”子目录添加到 SEARCH_SOURCE 允许您在对象规则调用中省略源文件的“src/”部分。SEARCH_SOURCE 也会自动添加到包含目录中,这就是#include 目录可以缩短的原因。
  • LOCATE_SOURCE 是放置生成的源文件(例如生成的 yacc 源和头文件)的目录。为保持一致性,CreateHeader 使用此变量。请注意,这允许(并要求)您在 CreateHeader 调用中省略“src/”部分。

因此,这些更改的主要目的是从 Jamfile 中使用的目标名称中省略“src/”部分。通常建议在 Jamfiles 中省略目录组件(并使用 grist 来消除歧义)。重要的是要注意 Jam 的工作方式 名称为“src/ah”和“ah”的目标是不同的目标,即使前者被认为位于“.”中。后者在“./src”中(例如,通过目标搜索或定位变量)。使用您在以下包含依赖项中提供 Jam 标头扫描结果的文件(这些是目标名称):

src/a.c : src/a.h
b.c     : src/b.h
src/c.c : c.h

这使得干扰“co”失败的原因很明显:目标“ch”是未知的,因为您声明要生成的标头的目标名称是“src/ch”。因此 jam 忽略了 include 依赖。“jam ao”失败的原因是您怀疑的原因。

我建议的更改需要调整源文件中的#include 指令,这在您的实际用例中可能是不可取的/不可能的。这种情况还是可以挽救的。例如,您可以按照建议更改 Jamfile,但扩展 CreateHeader 规则:

rule CreateHeader
{
    MakeLocate $(1) : $(LOCATE_SOURCE) ;
    Clean clean : $(1) ;
    Depends src/$(1) : $(1) ;
    NotFile src/$(1) ;
}

这显然是一个黑客攻击。它将目标“src/ah”和朋友定义为伪目标,每个都取决于相应的实际目标(“ah”等)。这样,Jam 的标头扫描将产生一个已知目标,无论它是否具有“src/”前缀。

不过,不太棘手的解决方案是显式声明包含关系:

Includes a.c : a.h ;
Includes b.c : b.h ;
于 2012-10-25T10:28:02.347 回答