创建一个make文件

时间:2014-11-27 14:14:20

标签: c makefile

我知道在互联网上有关于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 *~ *#

任何有关完成此文件的帮助或解释都将非常感激。 注意我只是开始所以我不想要任何复杂的代码,因为我不会理解它

4 个答案:

答案 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 *~ *#

好的,我所做的更改(及其原因)

  1. 首先,我喜欢使用随着规则被触发而扩展的变量。我发现这是确保所有步骤使用相同设置的便捷方式。此外,如果您需要将标题添加到编译(即INCS变量),我添加了可以使用的变量。我已经分析了链接器的命令和标志,LKLKFLAGSLIBS变量。目前大多数都是空的。

  2. 我为创建的各种目标文件添加了一个变量,我喜欢这样做,因为如果我向项目中添加一个新的源文件,我必须做两件事,第一件事就是写一条规则它和第二个是将它添加到OBJS变量。在我看来,添加新源文件时我需要做的事情越多,忘记某些事情的可能性就越大。

  3. 我为最终的程序名添加了一个变量。再一次,如果我想改变它就会变得简单......而且我很懒惰 - 键入$(PROG)比键入PolyCalculator更容易,更不容易出错:)

  4. 目标的排序是个人选择,我总是将目标重建为主程序作为makefile中的第一个(或默认)目标。这样,当我运行make时,我只构建自上次构建以来发生了变化的内容。我在顶部附近放置了一个规则来完全重建应用程序,在上面这是rebuild规则。运行make rebuild在操作上等同于make clean; make;但我更喜欢一个目标来完成这个

  5. 我使用第1点中定义的变量重新编写了规则。

  6. 我将-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和其他标准位置的库。当然,OTHERLIBDIROTHERLIB中的宏将在makefile中定义。

接下来的三行表示目标文件(注意它是目标文件,而不是源文件)取决于头文件。 make能够推断出PolyCalculatorMain.oPolyCalculatorMain.c构建的,因此您不必明确指定该依赖关系。它不能推断出头部依赖性,因此您必须指定它。请注意,我没有指定自定义命令,因此将使用默认命令。这通常是:

${CC} -c ${CFLAGS} $*.c

其中$*是正在编译的文件的基名的简写。

我修改了clean命令以使用rm -f(如果参数丢失则不会抱怨),并将a.outcore添加到列表中碎片文件。

您可以向这样的基本makefile添加无穷无尽的额外内容。您可以添加depend规则以自动生成标头依赖项;当您的代码开始变得复杂多个标头,以及使用不同标头集的不同源文件时,这很有用。如果您有多语言源代码树,则必须担心多个文件列表。如果您有多个程序,则必须将特定于一个程序的文件与多个程序共用的文件分开,然后考虑是否将公共对象文件构建到本地便利库中,这样您就不必列出每个程序的确切依赖关系。

但是这个大纲会让你前进。

如果你正在使用GNU make,你可能会添加一行:

.PHONY: all clean

这告诉GNU make,我们不会创建名为allclean的文件。

我顺便注意到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 *~ *#