我正在尝试了解Makefile的工作原理,因此我决定通过一个非常简单的代码进行尝试。这是我写的:
/* justify.c */
#include <stdio.h>
#include "line.h"
#include "word.h"
int main(void) {
printf("I'm in the main.\n");
read_word();
write_line();
}
/* line.h */
void write_line(void);
/* line.c */
#include <stdio.h>
#include "line.h"
void write_line(void) {
printf("write_line\n");
}
/* word.h */
void read_word(void);
/* word.c */
#include <stdio.h>
#include "word.h"
void read_word(void) {
printf("read_word\n");
}
现在...如果我从终端执行所有操作,它将正常工作:
> gcc -c justify.c
> gcc -c line.c
> gcc -c word.c
> gcc -o justify justify.c line.c word.c
但是如果我尝试使用Makefile进行所有操作,则会给我一个错误:
# Makefile
justify: justify.o line.o word.o
gcc -o justify.o line.o word.o
justify.o: justify.c line.h word.h
gcc -c justify.c
line.o: line.c line.h
gcc -c line.c
word.o: word.c word.h
gcc -c word.c
> make justify
Undefined symbols for architecture x86_64:
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
无双关语,但您正在变得比需要的要难一些。对于源和标头都在同一目录中的情况,使用通配符让make处理其余部分非常简单。例如,在Makefile
中使用三个简单的变量声明,可以告诉您源文件是什么,包含文件以及如何为不是应用程序名称的每个源文件生成目标文件。
对于初学者,请指定您的应用程序名称:
# application name
APPNAME := justify
如果需要,请设置您的编译器变量,例如
# compiler
CC := gcc
CCLD := $(CC)
现在让您知道您的应用程序名称保存在APPNAME
中,您可以像访问Makefile
中的任何其他变量一样将其保存为$(APPNAME)
。
现在只需使用wildcard
来收集所有源并包括在变量中,然后让make
关联目标文件输出:
# source/include/object variables
SOURCES := $(wildcard *.c)
INCLUDES := $(wildcard *.h)
OBJECTS := $(SOURCES:%.c=%.o)
设置您的编译器/链接器/库标志:
# compiler and linker flags
CFLAGS := -Wall -Wextra -pedantic -finline-functions -std=c11 -Wshadow -Ofast
LDFLAGS :=
# libraries
LIBS :=
现在为make
创建默认目标(注意:在每个规则前面必须有一个[[制表符 '\t'
):
all: $(OBJECTS)
$(CCLD) -o $(APPNAME) $(OBJECTS) $(CFLAGS) $(LDFLAGS) $(LIBS)
将所有源编译为对象的规则:
$(OBJECTS): %.o : %.c $(CC) $(CFLAGS) -c -o $@ $<
((有关使用的自动变量的说明,请参见:What do the makefile symbols $@ and $< mean?)最后是
clean:
的目标
clean: rm -rf $(APPNAME) *.o
您的文件的完整示例为:
# application name APPNAME := justify # compiler CC := gcc CCLD := $(CC) # compiler and linker flags CFLAGS := -Wall -Wextra -pedantic -finline-functions -std=c11 -Wshadow -Ofast LDFLAGS := # libraries LIBS := # source/include/object variables SOURCES := $(wildcard *.c) INCLUDES := $(wildcard *.h) OBJECTS := $(SOURCES:%.c=%.o) # target for all all: $(OBJECTS) $(CCLD) -o $(APPNAME) $(OBJECTS) $(CFLAGS) $(LDFLAGS) $(LIBS) # strip only if -DDEBUG not set ifneq ($(debug),-DDEBUG) strip -s $(APPNAME) endif $(OBJECTS): %.o : %.c $(CC) $(CFLAGS) -c -o $@ $< clean: rm -rf $(APPNAME) *.o
((note:到
strip
的规则,可执行文件也已添加到all:
目标)示例构建
使用Makefile
源,并将文件包含在公共目录中,例如
$ ll total 24 -rw-r--r-- 1 david david 668 Nov 6 12:38 Makefile -rw-r--r-- 1 david david 161 Nov 6 12:31 justify.c -rw-r--r-- 1 david david 106 Nov 6 12:32 line.c -rw-r--r-- 1 david david 37 Nov 6 12:31 line.h -rw-r--r-- 1 david david 104 Nov 6 12:32 word.c -rw-r--r-- 1 david david 36 Nov 6 12:32 word.h
只需键入make
即可构建您的应用程序:
$ make gcc -Wall -Wextra -pedantic -finline-functions -std=c11 -Wshadow -Ofast -c -o word.o word.c gcc -Wall -Wextra -pedantic -finline-functions -std=c11 -Wshadow -Ofast -c -o line.o line.c gcc -Wall -Wextra -pedantic -finline-functions -std=c11 -Wshadow -Ofast -c -o justify.o justify.c gcc -o justify word.o line.o justify.o -Wall -Wextra -pedantic -finline-functions -std=c11 -Wshadow -Ofast strip -s justify
没有错误,您可以检查所有文件是否按预期创建:
$ ll total 44 -rw-r--r-- 1 david david 668 Nov 6 12:38 Makefile -rwxr-xr-x 1 david david 6312 Nov 6 13:01 justify -rw-r--r-- 1 david david 161 Nov 6 12:31 justify.c -rw-r--r-- 1 david david 1760 Nov 6 13:01 justify.o -rw-r--r-- 1 david david 106 Nov 6 12:32 line.c -rw-r--r-- 1 david david 37 Nov 6 12:31 line.h -rw-r--r-- 1 david david 1496 Nov 6 13:01 line.o -rw-r--r-- 1 david david 104 Nov 6 12:32 word.c -rw-r--r-- 1 david david 36 Nov 6 12:32 word.h -rw-r--r-- 1 david david 1496 Nov 6 13:01 word.o
测试可执行文件:
$ ./justifiy I'm in the main. read_word write_line
最后,使用make clean
清理构建目录,例如
$ make clean
并确认已删除所有构建文件。这是编写最少的make文件的最简单方法。您可以单独列出每个对象,并且必须包含支持它们的对象,但是为什么呢?自动变量将为您解决这一问题。您可以使用Makefile进行更多操作,但是对于入门而言,这将使您的生活更轻松。
Makefile
$@ - target name
$< - first prequisite
$^ - all prequsites
justify: justify.o line.o word.o
gcc -o $@ $^
justify.o: justify.c
gcc -c $<
line.o: line.c
gcc -c $<
word.o: word.c
gcc -c $<
添加clean
]也是一个好主意>
clean: -rm *.o justify
-rm - minus sign at the beginning will not produce error; useful in case you expect that something might be missing