Makefile 如何在一个生成文件中包含多个生成?

Makefile 如何在一个生成文件中包含多个生成?,makefile,cs50,Makefile,Cs50,我创建了一个makefile来编译hello.c,它如下所示: 1 #the compiler to use 2 CC = clang 3 4 #compiler flags: 5 # -g adds debugging information to the executable file 6 # -Wall turns on most, but not all, compiler warnings 7 CFLAGS = -g -Wa

我创建了一个makefile来编译hello.c,它如下所示:

    1 #the compiler to use
    2 CC = clang
    3
    4 #compiler flags:
    5 # -g    adds debugging information to the executable file
    6 # -Wall turns on most, but not all, compiler warnings
    7 CFLAGS = -g -Wall
    8
    9 #files to link:
   10 LFLAGS = -lcs50
   11
   12 #the name to use for both the target source file and the output file:
   13 TARGET = hello
   14
   15 all: $(TARGET)
   16 $(TARGET): $(TARGET).c
   17     $(CC) $(CFLAGS) -o $(TARGET) $(TARGET).c $(LFLAGS)
# The compiler to use
CC = clang

# Compiler flags:
# -g    adds debugging information to the executable file
# -Wall turns on most, but not all, compiler warnings
CFLAGS = -g -Wall

# Files to link:
LFLAGS = -lcs50

# Find all the files ending with .c using the shell command
SOURCEFILES = $(shell find . -type f -name "*.c")

# Convert all of these files to have .o as their suffix with a substitution
OUTPUTFILES = ${SOURCEFILES:.c=.o}

# Our "PHONY" rules; all make targets correspond with a produced file 
# (This is how it can be clever about knowing when it can skip rules
# if no files have changed.  We never make a file called "all" or "clean"
# as these are rules for our convenience - aka PHONY rules.)
.PHONY: all clean

# Build all our output files (.o files)
all: ${OUTPUTFILES}

# Remove all our output files
clean:
        rm -v ${OUTPUTFILES}

# The rule that tells us how to make a .o file from a .c file.
$.o: %.c
        $(CC) $(CFLAGS) -o $@ $^ $(LFLAGS)
我还有另外两个程序名为:int.c和float.c,我希望将它们包含在目标中,但我得到了以下结果:

  make: Circular hello <- hello dependency dropped.
  make: Circular int <- hello dependency dropped.
  make: Circular int <- int dependency dropped.
  clang -g -Wall -o hello int float hello int float.c -lcs50
  clang: error: no such file or directory: 'int'
  clang: error: no such file or directory: 'float'
  clang: error: no such file or directory: 'hello'
  clang: error: no such file or directory: 'int'
  make: *** [int] Error 1

make:Circular hello因此您的想法大致正确,但执行并不十分完美!关于可能出错的最大线索是输出中的以下行:

clang -g -Wall -o hello int float hello int float.c -lcs50
正如您所看到的,它只是在“hellointfloat”中被替换了两次,一次是在末尾添加了“.c”。那么我们能做些什么呢


虽然不太常见,但使用由空格分隔的变量列表(即
TARGET=hello int float
)是有效的,并且您的规则(
${TARGET}:…
)确实会对列表中的每个项计算一次。有很多方法可以将
.c
后缀添加到列表中的每个项目(函数),但是我们可以用一种更“Make-y”的方式来完成

模式规则与自动变量 为了确定我们如何引用目标定义中的内容,您需要的是和。模式规则允许我们制定非常通用的规则,并遵循特定的模式,而自动变量允许我们在命令运行时引用部分规则定义

...
all: ${TARGETS}
%: %.c
        $(CC) $(CFLAGS) -o $@ $^ $(LFLAGS)
我们在这里做了两件事,首先我们用
%:%.c
替换了规则。也就是说,有一个具有某个名称的目标,它依赖于某个文件,该文件与末尾带有
.c
的文件相同

其次,我们用自动变量替换make命令中对
${TARGET}
的引用
$@
指的是目标名称,
$^
指的是依赖项列表(在本例中,只有一个)


一些进一步的改进 使用模式规则的一种稍微传统的方法是在输出上也有一个后缀:

TARGETS = hello.o int.o float.o
all: ${TARGETS}
%.o: %.c
        $(CC) $(CFLAGS) -o $@ $^ $(LFLAGS)
但是,我们喜欢懒惰,因此我们可以通过我评论过的其他一些技巧进一步自动化此操作,生成一个类似以下内容的makefile:

    1 #the compiler to use
    2 CC = clang
    3
    4 #compiler flags:
    5 # -g    adds debugging information to the executable file
    6 # -Wall turns on most, but not all, compiler warnings
    7 CFLAGS = -g -Wall
    8
    9 #files to link:
   10 LFLAGS = -lcs50
   11
   12 #the name to use for both the target source file and the output file:
   13 TARGET = hello
   14
   15 all: $(TARGET)
   16 $(TARGET): $(TARGET).c
   17     $(CC) $(CFLAGS) -o $(TARGET) $(TARGET).c $(LFLAGS)
# The compiler to use
CC = clang

# Compiler flags:
# -g    adds debugging information to the executable file
# -Wall turns on most, but not all, compiler warnings
CFLAGS = -g -Wall

# Files to link:
LFLAGS = -lcs50

# Find all the files ending with .c using the shell command
SOURCEFILES = $(shell find . -type f -name "*.c")

# Convert all of these files to have .o as their suffix with a substitution
OUTPUTFILES = ${SOURCEFILES:.c=.o}

# Our "PHONY" rules; all make targets correspond with a produced file 
# (This is how it can be clever about knowing when it can skip rules
# if no files have changed.  We never make a file called "all" or "clean"
# as these are rules for our convenience - aka PHONY rules.)
.PHONY: all clean

# Build all our output files (.o files)
all: ${OUTPUTFILES}

# Remove all our output files
clean:
        rm -v ${OUTPUTFILES}

# The rule that tells us how to make a .o file from a .c file.
$.o: %.c
        $(CC) $(CFLAGS) -o $@ $^ $(LFLAGS)

现在我们可以添加任何.c文件,它将使用您设置的选项进行编译!更改
TARGET
变量现在已经成为过去

所以您的想法大致正确,但执行并不十分完美!关于可能出错的最大线索是输出中的以下行:

clang -g -Wall -o hello int float hello int float.c -lcs50
正如您所看到的,它只是在“hellointfloat”中被替换了两次,一次是在末尾添加了“.c”。那么我们能做些什么呢


虽然不太常见,但使用由空格分隔的变量列表(即
TARGET=hello int float
)是有效的,并且您的规则(
${TARGET}:…
)确实会对列表中的每个项计算一次。有很多方法可以将
.c
后缀添加到列表中的每个项目(函数),但是我们可以用一种更“Make-y”的方式来完成

模式规则与自动变量 为了确定我们如何引用目标定义中的内容,您需要的是和。模式规则允许我们制定非常通用的规则,并遵循特定的模式,而自动变量允许我们在命令运行时引用部分规则定义

...
all: ${TARGETS}
%: %.c
        $(CC) $(CFLAGS) -o $@ $^ $(LFLAGS)
我们在这里做了两件事,首先我们用
%:%.c
替换了规则。也就是说,有一个具有某个名称的目标,它依赖于某个文件,该文件与末尾带有
.c
的文件相同

其次,我们用自动变量替换make命令中对
${TARGET}
的引用
$@
指的是目标名称,
$^
指的是依赖项列表(在本例中,只有一个)


一些进一步的改进 使用模式规则的一种稍微传统的方法是在输出上也有一个后缀:

TARGETS = hello.o int.o float.o
all: ${TARGETS}
%.o: %.c
        $(CC) $(CFLAGS) -o $@ $^ $(LFLAGS)
但是,我们喜欢懒惰,因此我们可以通过我评论过的其他一些技巧进一步自动化此操作,生成一个类似以下内容的makefile:

    1 #the compiler to use
    2 CC = clang
    3
    4 #compiler flags:
    5 # -g    adds debugging information to the executable file
    6 # -Wall turns on most, but not all, compiler warnings
    7 CFLAGS = -g -Wall
    8
    9 #files to link:
   10 LFLAGS = -lcs50
   11
   12 #the name to use for both the target source file and the output file:
   13 TARGET = hello
   14
   15 all: $(TARGET)
   16 $(TARGET): $(TARGET).c
   17     $(CC) $(CFLAGS) -o $(TARGET) $(TARGET).c $(LFLAGS)
# The compiler to use
CC = clang

# Compiler flags:
# -g    adds debugging information to the executable file
# -Wall turns on most, but not all, compiler warnings
CFLAGS = -g -Wall

# Files to link:
LFLAGS = -lcs50

# Find all the files ending with .c using the shell command
SOURCEFILES = $(shell find . -type f -name "*.c")

# Convert all of these files to have .o as their suffix with a substitution
OUTPUTFILES = ${SOURCEFILES:.c=.o}

# Our "PHONY" rules; all make targets correspond with a produced file 
# (This is how it can be clever about knowing when it can skip rules
# if no files have changed.  We never make a file called "all" or "clean"
# as these are rules for our convenience - aka PHONY rules.)
.PHONY: all clean

# Build all our output files (.o files)
all: ${OUTPUTFILES}

# Remove all our output files
clean:
        rm -v ${OUTPUTFILES}

# The rule that tells us how to make a .o file from a .c file.
$.o: %.c
        $(CC) $(CFLAGS) -o $@ $^ $(LFLAGS)

现在我们可以添加任何.c文件,它将使用您设置的选项进行编译!更改
TARGET
变量现在已经成为过去

失败的
Makefile
到底是什么样子的?失败的
Makefile
到底是什么样子的?