这是C语言中makefile的正确实现吗?

时间:2018-12-06 18:58:40

标签: c makefile

我正在研究一个项目,因此需要为其创建一个makefile

以下是我需要遵循的文件和约定:

  • program5.c //驱动程序代码
  • 列表项
  • data.h
  • list.c / .h
  • profile.c / .h(提供)
  • queue.c / .h
  • stack.c / .h
  • vector.c / .h
  • makefile

makefile中必须具有以下标签:

  • all-将所有代码编译成名为“ program4”的可执行文件(无扩展名)。不要运行。
  • 运行-必要时进行编译并运行
  • memcheck-仅在必要时进行编译并与Valgrind一起运行
  • clean-删除所有可执行文件和目标文件

全部:program5

program5: program5.o stack.o queue.o vector.o list.o profile.o
    gcc -g program5.o stack.o queue.o vector.o list.o profile.o -o program5

program5.o: program5.c stack.h queue.h vector.h list.h profile.h
    gcc -g -c program5.c -o program5.o

stack.o: stack.c stack.h
    gcc -g -c stack.c -o stack.o

queue.o: queue.c queue.h
    gcc -g -c queue.c -o queue.o

vector.o: vector.c vector.h
    gcc -g -c vector.c -o vector.o

list.o: list.c list.h
    gcc -g -c list.c -o list.o

profile.o: profile.c profile.h
    gcc -g -c profile.c -o profile.o

run: all
    ./program5

memcheck: all
    valgrind -v ./program5

clean:
    rm -f *.o program5

这是我在makefile文件中需要进行以下导入的program5.c的外观。我想知道我在makefile中写的内容是否正确?

例如,program5program5.o部分是正确的,还是我应该将它们拆散更多或其他?

#include "stack.h"
#include "stack.h"
#include "queue.h"
#include "queue.h"
#include "vector.h"
#include "vector.h"
#include "list.h"
#include "list.h"
#include "profile.h"
#include "profile.h"

2 个答案:

答案 0 :(得分:2)

首先,请阅读GNU make manual。阅读主要文档胜于猜测。

我没有发现任何错误,但可以肯定地将其简化了很多。

GNU make允许您使用各种隐式规则,而不是为每个目标编写一个显式规则。例如,make已经提供了一个隐式规则,可将任何*.c文件编译为*.o

%.o : %.c
        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

自动变量$<对应于先决条件(:的右侧),变量$@对应于目标。 CCCFLAGSCPPFLAGS是隐式规则使用的预定义变量名-您只需将它们设置为要使用的值即可:

CC = gcc
CFLAGS = -std=c99 -pedantic -Wall -Werror

因此,简化此操作的一种方法是

CC = gcc
CFLAGS = -std=c99 -pedantic -Wall -Werror
SRCS = program5.c stack.c queue.c vector.c list.c profile.c
OBJS = $(SRCS:.c=.o)

TARGET=program5

##
## rebuild the target if any of the object files are newer
##
$(TARGET) : $(OBJS)
        $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJS) -o $@

all : $(TARGET)

run : all
        ./$(TARGET)

memcheck: all
        valgrind -v $(TARGET)

clean:
        rm -rf $(TARGET) $(OBJS)

请注意,无需为单独的.o文件编写任何规则-再次,GNU Make已经提供了该规则。您只需要适当地设置CCCFLAGSCPPFLAGS

现在,此makefile做做的一件事是检查对头文件(.h)的依赖性。您可以通过添加如下内容来覆盖隐式规则:

%.o : %.c %.h
        $(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@

如果 file .c或 file .h较新,则会重建 file .o。但是有时多个.c文件包含相同的.h文件,因此,如果单个标头更改,则可能需要触发多个构建。

gcc可以选择生成Makefile规则列表。例如,如果program5.c包含上述所有标头,则gcc -MM program5.c将生成输出

program5.o : program5.c list.h profile.h queue.h stack.h vector.h

您可以将此输出写入文件,然后将该文件包含在主Makefile中。这是上面链接的GNU make手册中的一个示例:

##
## For each source file, create a .d file that explicitly lists the header
## dependencies.  
##
%.d : %.c
        @set -e; rm -f $@; \
        $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
        sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
        rm -rf $@.$$$$

然后在您添加clean目标之后

include $(SRCS:.c=.d)

包括生成的.d文件。

编辑

这是一个可行的示例(主要是为了确保我没有对你说谎)。我生成了一组.c和.h文件:

[fbgo448@n9dvap997]~/prototypes/make: ls
total 56
drwxrwxr-x   2 fbgo448 users  4096 2018-12-07 09:28 .
drwxrwxr-x 163 fbgo448 users 16384 2018-12-07 09:11 ..
-rw-rw-r--   1 fbgo448 users    52 2018-12-07 09:25 data.h
-rw-rw-r--   1 fbgo448 users    83 2018-12-07 09:12 list.c
-rw-rw-r--   1 fbgo448 users    58 2018-12-07 09:12 list.h
-rw-rw-r--   1 fbgo448 users   512 2018-12-07 09:28 Makefile
-rw-rw-r--   1 fbgo448 users    93 2018-12-07 09:14 profile.c
-rw-rw-r--   1 fbgo448 users    67 2018-12-07 09:13 profile.h
-rw-rw-r--   1 fbgo448 users   264 2018-12-07 09:24 program5.c
-rw-rw-r--   1 fbgo448 users    86 2018-12-07 09:14 queue.c
-rw-rw-r--   1 fbgo448 users    62 2018-12-07 09:14 queue.h
-rw-rw-r--   1 fbgo448 users    87 2018-12-07 09:15 stack.c
-rw-rw-r--   1 fbgo448 users    62 2018-12-07 09:15 stack.h
-rw-rw-r--   1 fbgo448 users    89 2018-12-07 09:16 vector.c
-rw-rw-r--   1 fbgo448 users    65 2018-12-07 09:16 vector.h

这些非常简单-它们只定义一个打印模块名称的函数,如下所示:

[fbgo448@n9dvap997]~/prototypes/make: more stack.*
::::::::::::::
stack.c
::::::::::::::
#include <stdio.h>
#include "stack.h"

void stack( void )
{
  printf( "stack\n" );
}

::::::::::::::
stack.h
::::::::::::::
#ifndef STACK_H
#define STACK_H

void stack( void );

#endif

program5除外,它会呼叫其他人:

[fbgo448@n9dvap997]~/prototypes/make: more program5.c
#include <stdio.h>
#include "data.h"
#include "list.h"
#include "profile.h"
#include "queue.h"
#include "stack.h"
#include "vector.h"

int main( void )
{
  printf( "g_data = %d\n", g_data ); // defined in data.h
  list();
  profile();
  queue();
  stack();
  vector();

  return 0;
}

这是makefile:

CC=gcc
CFLAGS= -std=c99 -pedantic -Wall -Werror
CPPFLAGS=

SRCS=program5.c list.c profile.c queue.c stack.c vector.c

##
## The following lines are examples of pattern substitions - the SRCS
## variable will be expanded, and each _file_.c will be replaced with
## a _file_.o for OBJS and _file_.d for DEPS.
##
OBJS=$(SRCS:.c=.o)
DEPS=$(SRCS:.c=.d)

TARGET=program5

##
## Build the dependency files
##
%.d : %.c
        set -e; rm -rf $@; \
        $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
        sed 's,\($*\)\.o[ :]*,\1.o $@ : , g' < $@.$$$$ > $@; \
        rm -rf $@.$$$$

$(TARGET) : $(OBJS)
        $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJS) -o $@

all: $(TARGET)

run: all
        ./$(TARGET)

memcheck: all
        valgrind -v $(TARGET)

clean:
        rm -rf $(TARGET) $(OBJS) $(DEPS)

##
## The '-' in front of the include directive will suppress a warning
## if any of the .d files cannot be found.  This will be the case the
## first time you run the makefile, or after running a 'make clean'.
##
-include $(DEPS)

这是运行make run的结果:

[fbgo448@n9dvap997]~/prototypes/make: make run
set -e; rm -rf vector.d; \
gcc -MM  vector.c > vector.d.$$; \
sed 's,\(vector\)\.o[ :]*,\1.o vector.d : , g' < vector.d.$$ > vector.d; \
rm -rf vector.d.$$
set -e; rm -rf stack.d; \
gcc -MM  stack.c > stack.d.$$; \
sed 's,\(stack\)\.o[ :]*,\1.o stack.d : , g' < stack.d.$$ > stack.d; \
rm -rf stack.d.$$
set -e; rm -rf queue.d; \
gcc -MM  queue.c > queue.d.$$; \
sed 's,\(queue\)\.o[ :]*,\1.o queue.d : , g' < queue.d.$$ > queue.d; \
rm -rf queue.d.$$
set -e; rm -rf profile.d; \
gcc -MM  profile.c > profile.d.$$; \
sed 's,\(profile\)\.o[ :]*,\1.o profile.d : , g' < profile.d.$$ > profile.d; \
rm -rf profile.d.$$
set -e; rm -rf list.d; \
gcc -MM  list.c > list.d.$$; \
sed 's,\(list\)\.o[ :]*,\1.o list.d : , g' < list.d.$$ > list.d; \
rm -rf list.d.$$
set -e; rm -rf program5.d; \
gcc -MM  program5.c > program5.d.$$; \
sed 's,\(program5\)\.o[ :]*,\1.o program5.d : , g' < program5.d.$$ > program5.d; \
rm -rf program5.d.$$
gcc -std=c99 -pedantic -Wall -Werror    -c -o program5.o program5.c
gcc -std=c99 -pedantic -Wall -Werror    -c -o list.o list.c
gcc -std=c99 -pedantic -Wall -Werror    -c -o profile.o profile.c
gcc -std=c99 -pedantic -Wall -Werror    -c -o queue.o queue.c
gcc -std=c99 -pedantic -Wall -Werror    -c -o stack.o stack.c
gcc -std=c99 -pedantic -Wall -Werror    -c -o vector.o vector.c
gcc -std=c99 -pedantic -Wall -Werror    program5.o list.o profile.o queue.o stack.o vector.o -o program5
./program5
g_data = 0
list
profile
queue
stack
vector

下面是生成的.d和.o文件的列表:

[fbgo448@n9dvap997]~/prototypes/make: ls
total 96
drwxrwxr-x   2 fbgo448 users  4096 2018-12-07 09:50 .
drwxrwxr-x 163 fbgo448 users 16384 2018-12-07 09:11 ..
-rw-rw-r--   1 fbgo448 users    52 2018-12-07 09:25 data.h
-rw-rw-r--   1 fbgo448 users    83 2018-12-07 09:12 list.c
-rw-rw-r--   1 fbgo448 users    30 2018-12-07 09:50 list.d
-rw-rw-r--   1 fbgo448 users    58 2018-12-07 09:12 list.h
-rw-rw-r--   1 fbgo448 users  1480 2018-12-07 09:50 list.o
-rw-rw-r--   1 fbgo448 users   974 2018-12-07 09:48 Makefile
-rw-rw-r--   1 fbgo448 users    93 2018-12-07 09:14 profile.c
-rw-rw-r--   1 fbgo448 users    42 2018-12-07 09:50 profile.d
-rw-rw-r--   1 fbgo448 users    67 2018-12-07 09:13 profile.h
-rw-rw-r--   1 fbgo448 users  1480 2018-12-07 09:50 profile.o
-rwxrwxr-x   1 fbgo448 users 10070 2018-12-07 09:50 program5
-rw-rw-r--   1 fbgo448 users   264 2018-12-07 09:24 program5.c
-rw-rw-r--   1 fbgo448 users    84 2018-12-07 09:50 program5.d
-rw-rw-r--   1 fbgo448 users  1864 2018-12-07 09:50 program5.o
-rw-rw-r--   1 fbgo448 users    86 2018-12-07 09:14 queue.c
-rw-rw-r--   1 fbgo448 users    34 2018-12-07 09:50 queue.d
-rw-rw-r--   1 fbgo448 users    62 2018-12-07 09:14 queue.h
-rw-rw-r--   1 fbgo448 users  1480 2018-12-07 09:50 queue.o
-rw-rw-r--   1 fbgo448 users    87 2018-12-07 09:15 stack.c
-rw-rw-r--   1 fbgo448 users    34 2018-12-07 09:50 stack.d
-rw-rw-r--   1 fbgo448 users    62 2018-12-07 09:15 stack.h
-rw-rw-r--   1 fbgo448 users  1480 2018-12-07 09:50 stack.o
-rw-rw-r--   1 fbgo448 users    89 2018-12-07 09:16 vector.c
-rw-rw-r--   1 fbgo448 users    38 2018-12-07 09:50 vector.d
-rw-rw-r--   1 fbgo448 users    65 2018-12-07 09:16 vector.h
-rw-rw-r--   1 fbgo448 users  1480 2018-12-07 09:50 vector.o

make clean将删除所有生成的文件:

[fbgo448@n9dvap997]~/prototypes/make: make clean
rm -rf program5 program5.o list.o profile.o queue.o stack.o vector.o program5.d list.d profile.d queue.d stack.d vector.d
[fbgo448@n9dvap997]~/prototypes/make: ls
total 56
drwxrwxr-x   2 fbgo448 users  4096 2018-12-07 09:51 .
drwxrwxr-x 163 fbgo448 users 16384 2018-12-07 09:11 ..
-rw-rw-r--   1 fbgo448 users    52 2018-12-07 09:25 data.h
-rw-rw-r--   1 fbgo448 users    83 2018-12-07 09:12 list.c
-rw-rw-r--   1 fbgo448 users    58 2018-12-07 09:12 list.h
-rw-rw-r--   1 fbgo448 users   974 2018-12-07 09:48 Makefile
-rw-rw-r--   1 fbgo448 users    93 2018-12-07 09:14 profile.c
-rw-rw-r--   1 fbgo448 users    67 2018-12-07 09:13 profile.h
-rw-rw-r--   1 fbgo448 users   264 2018-12-07 09:24 program5.c
-rw-rw-r--   1 fbgo448 users    86 2018-12-07 09:14 queue.c
-rw-rw-r--   1 fbgo448 users    62 2018-12-07 09:14 queue.h
-rw-rw-r--   1 fbgo448 users    87 2018-12-07 09:15 stack.c
-rw-rw-r--   1 fbgo448 users    62 2018-12-07 09:15 stack.h
-rw-rw-r--   1 fbgo448 users    89 2018-12-07 09:16 vector.c
-rw-rw-r--   1 fbgo448 users    65 2018-12-07 09:16 vector.h

感谢自动生成的依存关系,如果我更新data.h,应该会触发program5.c的构建:

[fbgo448@n9dvap997]~/prototypes/make: touch data.h
[fbgo448@n9dvap997]~/prototypes/make: make
set -e; rm -rf program5.d; \
gcc -MM  program5.c > program5.d.$$; \
sed 's,\(program5\)\.o[ :]*,\1.o program5.d : , g' < program5.d.$$ > program5.d; \
rm -rf program5.d.$$
gcc -std=c99 -pedantic -Wall -Werror    -c -o program5.o program5.c
gcc -std=c99 -pedantic -Wall -Werror    program5.o list.o profile.o queue.o stack.o vector.o -o program5

类似地,如果我更新stack.h,则应该触发stack.cprogram5.c的重建:

[fbgo448@n9dvap997]~/prototypes/make: touch stack.h
[fbgo448@n9dvap997]~/prototypes/make: make
set -e; rm -rf stack.d; \
gcc -MM  stack.c > stack.d.$$; \
sed 's,\(stack\)\.o[ :]*,\1.o stack.d : , g' < stack.d.$$ > stack.d; \
rm -rf stack.d.$$
set -e; rm -rf program5.d; \
gcc -MM  program5.c > program5.d.$$; \
sed 's,\(program5\)\.o[ :]*,\1.o program5.d : , g' < program5.d.$$ > program5.d; \
rm -rf program5.d.$$
gcc -std=c99 -pedantic -Wall -Werror    -c -o program5.o program5.c
gcc -std=c99 -pedantic -Wall -Werror    -c -o stack.o stack.c
gcc -std=c99 -pedantic -Wall -Werror    program5.o list.o profile.o queue.o stack.o vector.o -o program5

希望这会有所帮助。再次,深入研究我上面链接的制作手册,您可以使用它做一些非常酷的事情。

答案 1 :(得分:1)

我不知道您的makefile是否有效,但是请注意,您并不需要所有的-o

gcc -g -c vector.c -o vector.o

应该是

gcc -g -c vector.c

无论如何,您可以使用一些指令来改进它:

CC = gcc
CFLAGS = -g
OBJECTS = program5.o stack.o queue.o vector.o list.o profile.o

all: program5

program5: $(OBJECTS)
    $(CC) $(OBJECTS) -o program5

program5.o: program5.c stack.h queue.h vector.h list.h profile.h
    $(CC) $(CFLAGS) -c program5.c

stack.o: stack.c stack.h
    $(CC) $(CFLAGS) -c stack.c

queue.o: queue.c queue.h
    $(CC) $(CFLAGS) -c queue.c

vector.o: vector.c vector.h
    $(CC) $(CFLAGS) -c vector.c

list.o: list.c list.h
    $(CC) $(CFLAGS) -c list.c

profile.o: profile.c profile.h
    $(CC) $(CFLAGS) -c profile.c

run: all
    ./program5

memcheck: all
    valgrind -v ./program5

clean:
    rm -f *.o program5

编译警告信息是一个好主意:

CFLAGS = -pedantic -Wall -Wextra -W -g

代替

CFLAGS = -g