我知道在互联网上有关于makefile的无限量的资源,但是我仍然不理解它。目前我有3个c文件PolyCalculatorMain.c PolyCalculator.c PolyCalculator.h和Polyfunctions.c
到目前为止我已经
了PolyCalculator: PolyCalculator.o PolyCalculatorMain.c
gcc -Wall -ggdb -o PolyCalculator PolyCalculatorMain.c PolyCalculator.o
PolyCalculator.o: PolyCalculator.c
gcc -Wall -ggdb -c PolyCalculator.c PolyCalculator.h
clean:
rm PolyCalculator *.o *~ *#
任何有关完成此文件的帮助或解释都将非常感激。 注意我只是开始所以我不想要任何复杂的代码,因为我不会理解它
答案 0 :(得分:1)
在编译命令中,您通常不指定.h文件。它们在遇到#include语句时被预处理器(在编译器之前运行)包含在内。这是我唯一能看到的东西。
.h文件确实在Makefile中显示为依赖项,因为对它们的更改可能需要重新编译使用它们的代码。
我会说基本规则是在依赖行中包含任何内容,如果它们发生了更改,将导致重新编译。
PolyCalculator: PolyCalculator.o PolyFunctions.o PolyCalculatorMain.c
gcc -Wall -ggdb -o PolyCalculator PolyCalculatorMain.c PolyCalculator.o PolyFunctions.o
PolyCalculator.o: PolyCalculator.c PolyCalculator.h
gcc -Wall -ggdb -c PolyCalculator.c
PolyFunctions.o: PolyFunctions.c PolyFunctions.h
gcc -Wall -ggdb -c PolyFunctions.c
clean:
rm PolyCalculator *.o *~ *#
Makefile允许您拥有可以重复使用的变量。例如,你可以拥有你的 变量中的编译器选项:
options=-Wall -ggdb
然后你用它们括号和美元符号
gcc ${options}
你也可以分手:
debug=-ggdb
warnings=-Wall
options=${warnings} ${debug}
您还可以将所有目标文件合并到一个变量中:
obj_files=PolyCalculator.o PolyFunctions.o
PolyCalculator: ${obj_files} PolyCalculatorMain.c
gcc -Wall -ggdb -o PolyCalculator PolyCalculatorMain.c ${obj_files}
PolyCalculator.o: PolyCalculator.c PolyCalculator.h
gcc -Wall -ggdb -c PolyCalculator.c
PolyFunctions.o: PolyFunctions.c PolyFunctions.h
gcc -Wall -ggdb -c PolyFunctions.c
clean:
rm PolyCalculator *.o *~ *#
答案 1 :(得分:1)
因为你没有给出你想要改变/修改的内容的真正清楚,我给你的是我将编写makefile的内容,如下所示,虽然有些人可能(会?)在某些地方不同意我。 我看到你编辑了原帖并提到了PolyFunctions.cpp(我猜那里 是一个PolyFunctions.h)
CC=gcc
CCFLAGS=-ansi -Wall -pedantic
INCS=
LK=gcc
LKFLAGS=
LIBS=
OBJS = PolyCalculator.o PolyCalculatorMain.o PolyFunctions.o
PROG = PolyCalculator
$(PROG) : $(OBJS)
$(LK) $(LKFLAGS) $(OBJS) $(LIBS) -o $(PROG)
rebuild : clean $(PROG)
PolyCalculatorMain.o : PolyCalculatorMain.cpp PolyCalculator.h PolyFunctions.h
$(GCC) -c $(CCFLAGS) $(INCS) PolyCalculatorMain.cpp -o PolyCalculatorMain.o
PolyCalculator.o : PolyCalculator.cpp PolyCalculator.h
$(GCC) -c $(CCFLAGS) $(INCS) PolyCalculator.cpp -o PolyCalculator.o
PolyFunctions.o : PolyFunctions.c PolyFunctions.h
$(GCC) -c $(CCFLAGS) $(INCS) PolyFunctions.cpp -o PolyFunctions.o
clean:
rm -f $(OBJS) $(PROG) *.o *~ *#
好的,我所做的更改(及其原因)
首先,我喜欢使用随着规则被触发而扩展的变量。我发现这是确保所有步骤使用相同设置的便捷方式。此外,如果您需要将标题添加到编译(即INCS
变量),我添加了可以使用的变量。我已经分析了链接器的命令和标志,LK
,LKFLAGS
和LIBS
变量。目前大多数都是空的。
我为创建的各种目标文件添加了一个变量,我喜欢这样做,因为如果我向项目中添加一个新的源文件,我必须做两件事,第一件事就是写一条规则它和第二个是将它添加到OBJS
变量。在我看来,添加新源文件时我需要做的事情越多,忘记某些事情的可能性就越大。
我为最终的程序名添加了一个变量。再一次,如果我想改变它就会变得简单......而且我很懒惰 - 键入$(PROG)
比键入PolyCalculator
更容易,更不容易出错:)
目标的排序是个人选择,我总是将目标重建为主程序作为makefile中的第一个(或默认)目标。这样,当我运行make
时,我只构建自上次构建以来发生了变化的内容。我在顶部附近放置了一个规则来完全重建应用程序,在上面这是rebuild
规则。运行make rebuild
在操作上等同于make clean; make
;但我更喜欢一个目标来完成这个
我使用第1点中定义的变量重新编写了规则。
我将-f
标记添加到rm
,因此即使无法找到文件,干净也会执行所有操作。同样,这往往是个人偏好。
答案 2 :(得分:1)
我确保广泛使用宏,因为如果需要,您可以在make
命令行上重新定义宏。还有许多标准宏,例如CC
用于C编译器的名称,CFLAGS用于传递给编译器的(大多数)标志。此外,make
还有许多操作的内置规则,例如将.c
文件转换为.o
文件。
make
背后的哲学是编译是昂贵的,所以你尽可能少地做,但尽可能多。因此,make
通常被命令构建目标文件,然后将目标文件与库链接以构建程序。
你说你有三个源文件和一个标题。所以,我的程序的makefile包括:
FILES.c = PolyCalculatorMain.c PolyCalculator.c Polyfunctions.c
FILES.o = ${FILES.c:.c=.o}
PROGRAM = PolyCalculator
CFLAGS = -Wall -ggdb
all: ${PROGRAM}
${PROGRAM}: ${FILES.o}
${CC} -o $@ ${CFLAGS} ${FILES.o} ${LDFLAGS} ${LDLIBS}
PolyCalculatorMain.o: PolyCalculator.h
PolyCalculator.o: PolyCalculator.h
Polyfunctions.o: PolyCalculator.h
clean:
rm -f ${PROGRAM} *.o *~ *# core a.out
$(XYZ)
和${XYZ}
之间的选择是任意的; 30年前我选择使用大括号,但没有理由改变。保持一致是最重要的。
FILES.c
宏(是的,宏名称可能包含点,尽管vim
没有将它们着色为宏)但是列出了一组三个文件名。如果我需要添加第四个,那么我将其添加到此列表中。如果列表对于单行来说太长,我会使用格式的宏:
FILES.c = \
PolyCalculatorMain.c \
PolyCalculator.c \
Polyfunctions.c
这允许编辑添加文件时受影响的一行,除非您在列表末尾添加它。我通常按排序顺序保留这些列表。
通过将后缀转换规则应用于FILES.o
宏来定义FILES.c
宏。 :
之后的部分是.c=.o
;这意味着在结尾处替换以.c
结尾的.o
的名称。
PROGRAM宏是我在单程序makefile中使用的。对于多程序makefile,每个程序都在所有大写中获得自己的宏。 (虽然make
宏不受所有大写限制,但对宏使用全部大写是正常的。)CFLAGS宏为C编译器设置所选的选项。使用-Wall
的好标记。我使用更严格的选项,例如-Wextra -Werror
并指定标准(-std=c11
),但-Wall
是一个良好的开端。
通常在makefile中使用名为all
的第一条规则。它说"当${PROGRAM}
是最新的"时,一切都是最新的。
下一条规则说该程序取决于目标文件。如果任何目标文件比程序更新,则使用显示的命令行重建程序。 $@
象形文字与此规则中的${PROGRAM}
相同。形式上,它是正在构建的目标的名称。它使命令行通用 - 除-o
之外的所有内容都是宏。这往往是makefiles
工作的方式;这些信息几乎都在宏中。 ${LDFLAGS}
和${LDLIBS}
宏是半标准的;它们允许您将选项传递给链接器(ld
,由C编译器调用),并用于指定与库相关的选项。例如,您可能有:
LDFLAGS = -L ${OTHERLIBDIR}
LDLIBS = -l${OTHERLIB}
链接不在/usr/lib
和其他标准位置的库。当然,OTHERLIBDIR
和OTHERLIB
中的宏将在makefile
中定义。
接下来的三行表示目标文件(注意它是目标文件,而不是源文件)取决于头文件。 make
能够推断出PolyCalculatorMain.o
是PolyCalculatorMain.c
构建的,因此您不必明确指定该依赖关系。它不能推断出头部依赖性,因此您必须指定它。请注意,我没有指定自定义命令,因此将使用默认命令。这通常是:
${CC} -c ${CFLAGS} $*.c
其中$*
是正在编译的文件的基名的简写。
我修改了clean
命令以使用rm -f
(如果参数丢失则不会抱怨),并将a.out
和core
添加到列表中碎片文件。
您可以向这样的基本makefile
添加无穷无尽的额外内容。您可以添加depend
规则以自动生成标头依赖项;当您的代码开始变得复杂多个标头,以及使用不同标头集的不同源文件时,这很有用。如果您有多语言源代码树,则必须担心多个文件列表。如果您有多个程序,则必须将特定于一个程序的文件与多个程序共用的文件分开,然后考虑是否将公共对象文件构建到本地便利库中,这样您就不必列出每个程序的确切依赖关系。
但是这个大纲会让你前进。
如果你正在使用GNU make
,你可能会添加一行:
.PHONY: all clean
这告诉GNU make
,我们不会创建名为all
和clean
的文件。
我顺便注意到Polyfunctions.c
这个名字与其他两个名字不一致; F
应该大写以保持一致性。
答案 3 :(得分:0)
这是适合您项目的GNU make
文件:
# set macro with list of source files in current directory using wildcard
# note: the ':=' states that the list is to only be generated once
# if only '=' were used, the the list would be re-generated each time referenced
SRCS := $(wildcard: *.c)
# set macro with list of object files using pattern substitution
OBJS := $(SRCS:.c=.o)
# set macro with list of header files in the current directory using wildcard
HDRS := $(wildcard: *.h)
# set macro with list of compiler flags
# there are many other very useful compiler flags
# but this list will result in:
# all warnings displayed
# compile only
# debug info being include
# (there are other forms of the -g parameter to get more debug info)
# no optimization
# look for some included files in the current directory
CFLAGS := -Wall -c -g -O0 -I.
# set macro with list of linker flags
# all warnings displayed
# debug info being included
LFLAGS := -Wall -g
# set macro with path+name of pre-processor/compiler/linker utility
# by convention, the utility is referenced by $(CC)
CC := /usr/bin/gcc
# by 'make' design, the make utility is referenced by $(MAKE)
# set macro with path+name of file deletion utility
# by convention, the utility is referenced by $(RM)
RM := /usr/bin/rm -f
# by convention, there are (at least) two phony target names
# tell 'make' that 'all' and 'clean' are targets that will NOT produce an output file
# with those names
.PHONY: all clean
# this is first target so will be performed if:
# user enters 'make' with no parameters
# or user enters 'make all'
# the PolyCalculator executable is stated to be a pre-requisite
all: PolyCalculator
# this is a real target
# state that this target has a pre-requisite of the files listed in the OBJS macro
# the executable name is defined by the '-o' and following name
# use the parameters listed in the LFLAGS macro
PolyCalculator: $(OBJS)
gcc $(LFLAGS) -o PolyCalculator $(OBJS)
# this is a real target (PolyCalculator.o)
# state that this target has a pre-requisite of file: PolyCalculator.c
# state that this target has a pre-requisite of the files listed in the HDRS macro
# use the parameters listed in the CFLAGS macro
# target 'PolyCalculator' lists PolyCalculator.o as a pre-requisite
# so it can be performed automatically
# it can also be performed directly when the user enters 'make PolyCalculator.o'
PolyCalculator.o: PolyCalculator.c $(HDRS)
gcc $(CFLAGS) -o PolyCalculator.o PolyCalculator.c
# this is a real target (PolyCalculatorMain.o)
# state that this target has a pre-requisite of file: PolyCalculatorMain.c
# state that this target has a pre-requisite of the files listed in the HDRS macro
# use the parameters listed in the CFLAGS macro
# target 'PolyCalculator' lists PolyCalculatorMain.o as a pre-requisite
# so it can be performed automatically
# it can also be performed directly when the user enters 'make PolyCalculatorMain.o'
PolyCalculatorMain.o: PolyCalculatorMain.c $(HDRS)
gcc $(CFLAGS) -o PolyCalculatorMain.o PolyCalculatorMain.c
# this is a real target (PolyFunctions.o)
# state that this target has a pre-requisite of file: PolyFunctions.c
# state that this target has a pre-requisite of the files listed in the HDRS macro
# use the parameters listed in the CFLAGS macro
# target 'PolyCalculator' lists PolyFunctions.o as a pre-requisite
# so it can be performed automatically
# it can also be performed directly when the user enters 'make PolyFunctions.o'
PolyFunctions.o: PolyFunctions.c $(HDRS)
gcc $(CFLAGS) -o PolyFunctions.o PolyFunctions.c
# this is a phony target (see .PHONY, above)
# it is performed when the user enters 'make clean'
clean:
$(RM) PolyCalculator *.o *~ *#