如何通过一个非常简单的示例使用Makefile

问题描述 投票:0回答:2

我正在尝试了解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)
c gcc makefile
2个回答
0
投票

无双关语,但您正在变得比需要的要难一些。对于源和标头都在同一目录中的情况,使用通配符让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进行更多操作,但是对于入门而言,这将使您的生活更轻松。


0
投票
您可以大大简化您拥有的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
© www.soinside.com 2019 - 2024. All rights reserved.