【问题标题】:How to use Makefile from a very simple example [closed]如何从一个非常简单的示例中使用 Makefile [关闭]
【发布时间】:2019-11-06 18:22:28
【问题描述】:

我正在尝试了解 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)

【问题讨论】:

  • 您应该将包含保护添加到*.h 文件中,并将它们从makefile 中的依赖项中删除。并不是说它与您的问题有关
  • gcc -o justify.o line.o word.o -> gcc -o justify justify.o line.o word.o
  • 检查gcc -o 行。那不应该是gcc -o justify justify.o line.o word.o
  • 谢谢大家,包括你 Eugene Sh。 “包含守卫”非常有趣。
  • @tkausl 指出的问题虽然有效,但无法解释您看到的消息,所以发生了其他事情。看起来 line.o 是为另一个架构编译的。做一个objdump -f line.o。然后删除 .o 文件,并从命令行重新编译并再次检查。如果 makefile 产生的输出与命令行不同,请尝试从 shell 和 makefile 配方运行 which gcc 以查看路径是否存在问题。

标签: c gcc makefile


【解决方案1】:

没有双关语的意思,但你做的比它需要的更难。在您的源代码和标头都在同一目录中的情况下,使用通配符允许 make 处理其余部分非常简单。例如,在您的Makefile 中使用三个简单的变量声明,您可以告诉 make 您的源是什么、您的包含以及如何为每个不是应用程序名称的源文件生成目标文件。

对于初学者,请指定您的应用程序名称:

# 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

注意: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 做很多很多事情,但对于入门来说,这将使您的生活更轻松。

【讨论】:

  • 很难找到更好的解释...
【解决方案2】:

您可以大大简化您拥有的Makefile。 Make 提供了很多有用的变量。

$@ - target name
$< - first prequisite
$^ - all prequsites
justify: justify.o line.o word.o
        gcc -o $@ $^    # this one will turn into
                        # gcc -o justify justify.o line.o word.o 

justify.o: justify.c
        gcc -c $<       # this one will turn into
                        # gcc -c justify.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 if command fails;   
      useful in case you expect that something might be missing

【讨论】:

    【解决方案3】:

    您的制作文件中有错误。 make 目标 justify: 的命令缺少输出文件名。应该是这样的。

    gcc -o justify justify.o line.o word.o
    

    使用您当前的命令行,gcc 将尝试通过链接 line.o 和 word.o 来输出 justify.o,但它没有找到 line.o 和 word.o 中未定义的_main

    make 命令已经知道如何将.c 文件转换为.o,因此您无需在make 文件中告诉它再次make。请记住这一点,以下 make 文件足以满足您的测试用例。

    # Makefile 
    justify: justify.o line.o word.o
        gcc -o justify justify.o line.o word.o
    

    您可以通过使用 make 的内置自动变量来进一步简化此操作。 $@$^$@ 变量包含规则目标的名称。 $^ 包含规则的所有先决条件的名称。所以使用这两个变量你的make文件将是。

    justify: justify.o line.o word.o
            gcc -o $@ $^
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-26
      • 1970-01-01
      • 2014-05-10
      • 1970-01-01
      • 2017-05-31
      • 2022-01-15
      • 1970-01-01
      • 2015-03-14
      相关资源
      最近更新 更多