Это правильная реализация `makefile` в C? - PullRequest
0 голосов
/ 06 декабря 2018

Я работаю над проектом, и мне нужно создать для него makefile.

Вот файлы и соглашения, которым я должен следовать:

  • program5.c // Код драйвера
  • Элемент списка
  • data.h
  • list.c / .h
  • profile.c / .h (предоставляется)
  • queue.c / .h
  • stack.c / .h
  • vector.c / .h
  • makefile

В вашем make-файле должны быть следующие метки:

  • all - чтобы скомпилировать весь ваш код в исполняемый файл с именем 'program4' (без расширения).Не запускать.
  • run - компилировать при необходимости и запускать
  • memcheck - компилировать только при необходимости и запускать с Valgrind
  • clean - удалять все исполняемые файлы и объектные файлы

all: 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, правильным или нет?

Например, части program5 и program5.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 голосов
/ 07 декабря 2018

Сначала прочитайте руководство по сборке GNU .Читать основную документацию лучше, чем угадывать.

Я ничего не вижу очевидно неправильно, но вы, конечно, можете немного упростить это.

GNU make позволяет вам использовать множество неявных правил , а не писать явное правило для каждой цели.Например, make уже предоставляет неявное правило для компиляции любого файла *.c в *.o:

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

Автоматическая переменная $< соответствует предварительному условию (правая часть :), а переменная $@ соответствует цели.CC, CFLAGS и CPPFLAGS - предопределенные имена переменных, используемые неявными правилами - вы просто устанавливаете для них значения, которые хотите использовать:

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

Таким образом, один способ упростить этоbe

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 уже предоставляет это правило.Вам просто нужно установить CC, CFLAGS и CPPFLAGS соответственно.

Теперь, одна вещь, которую этот make-файл не делает , - это проверка зависимостей от файлов заголовка (.h).Вы можете переопределить неявное правило, добавив что-то вроде следующего:

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

Это перестроит file .o, если либо file .c, либо file .h новее.Но иногда несколько файлов .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;
}

Вот make-файл:

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.c и program5.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

Надеюсь, это поможет.Опять же, покопайтесь в руководстве по сборке, которое я связал выше, вы можете сделать с ним действительно классные вещи.

0 голосов
/ 06 декабря 2018

Я не знаю, работает ли ваш 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...