Нет правила для создания цели в Makefile GCC

Речь идет о следующем Makefile:

#
# Compiler flags
#
CC     = gcc
CFLAGS = -Wall -Werror -Wextra 

#
# Project files
# example - 
# SRCS = hash_table.c linked_list.c utils.c common.c business_logic.c user_interface.c
# SRCS = test/gc_test.c src/gc.c
SRCS := $(shell find . -name "*")
OBJS = $(SRCS:.c=.o)
EXE  = output.out

FILENAMES := $(shell find . -type f -name "*.c" -printf "%f\n")
FILENAMES_OUT = $(FILENAMES:.c=.o)
#
# Default build settings
#
BUILDDIR = build
BUILDCFLAGS = -g -O0
BUILDEXE = $(BUILDDIR)/$(EXE)
BUILDOBJS = $(addprefix $(BUILDDIR)/, $(FILENAMES_OUT))


# Rules for default build
all: clean build

build: $(BUILDEXE)

$(BUILDEXE): $(BUILDOBJS)
    $(CC) $(CFLAGS) $(BUILDCFLAGS) -o $(BUILDEXE) $^ -lcunit

$(BUILDDIR)/%.o: %.c
    $(CC) $(CFLAGS) $(BUILDCFLAGS) -c $< -o $@


memtest: $(BUILDEXE) 
    valgrind --leak-check=full ./$<


#
# Other rules
#
clean:
    mkdir -p $(BUILDDIR)

ПРОБЛЕМА -> make: *** No rule to make target `build/gc_test.o', needed by `build/output.out'. Stop.

ДЕРЕВО ПРОЕКТА

.
├── build
├── doc
│   └── design.md
├── Makefile
├── proj
│   ├── code_quality_report.md
│   ├── deviations.md
│   ├── individual_reflection.md
│   ├── team_reflection.md
│   └── test_report.md
├── README.md
├── src
│   ├── gc.c
│   └── headers
│       └── gc.h
└── tests
    └── gc_test.c

Сама проблема возникает в $(BUILDEXE): $(BUILDOBJS), где находятся зависимости gc_test.c gc.c. Эти зависимости ДОЛЖНЫ попасть в функцию под ней, потому что входными данными являются все файлы .c в каталоге build. Эти файлы ДОЛЖНЫ быть правильно сопоставлены, а затем скомпилированы в файлы .o, которые затем должны подняться вверх по дереву и создать исполняемый файл. Я в замешательстве, потому что $(BUILDOBJS) должно быть таким же, как $(BUILDDIR)/%.o.

Я новичок в создании файлов Makefile, но хочу стать лучше. Пожалуйста, укажите лучшие соглашения об именах или терминологию, которые можно было бы лучше использовать для этого поста. Спасибо!

Будет ли это работать, если вы сделаете эту строку явно (то есть с именами файлов, жестко заданными вручную) вместо того, чтобы пытаться волшебным образом найти все файлы .c? FILENAMES := $(shell find . -type f -name "*.c" -printf "%f\n"). Насколько я знаю, такое подстановка часто является проблемой для make-настроек.

Yunnosch 15.12.2020 14:12

Пробовал, не получилось. Показывает ту же ошибку. Это очень странно.

Richard 15.12.2020 14:48

Вы заявляете "...because it's input is all the .c files in the build directory" о правиле $(BUILDDIR)/%.o: %.c . Это неправильно. Зависимость (в данном случае gc_test.c) будет искаться в текущем каталоге (или в любых соответствующих vpath местах), поскольку %.c расширяется до gc_test.c.

G.M. 15.12.2020 14:50

... и gc_test.c отсутствует в текущем каталоге. Если вы хотите продолжить создание объектов в специальном отдельном каталоге, а не в том же каталоге, что и их исходники, или в параллельном дереве сборки, вам потребуется отдельное правило для каждой папки, содержащей исходники, которые вы хотите скомпилировать. Честно говоря, я никогда не понимал, почему так много людей настаивают на этом. Он более хрупок и требует больше работы для обслуживания, и я не вижу, чего он достигает, чего нельзя достичь с помощью сборки VPATH или даже хорошего «чистого» правила.

John Bollinger 15.12.2020 15:04
vpath является хорошим решением этой проблемы. (Я бы ответил, но @G.M. упомянул об этом за 40 минут до того, как я пришел.)
Beta 15.12.2020 15:31

Проблема не в создании объектов в другом каталоге. это легко поддерживать и очень удобно по многим причинам: например, вы можете иметь разные каталоги объектов для кода, созданного с разными флагами (отладка, оптимизация, SAN и т. д.), а также упрощает очистку объектов. Проблема заключается в попытке использовать для объектов другую структуру каталогов, чем для источников; часто люди пытаются поместить все объектные файлы в один каталог, даже если исходные тексты находятся в нескольких каталогах. ЭТО раздражает и сложно поддерживать.

MadScientist 15.12.2020 21:13

Если вы сделаете структуру каталогов объектов идентичной структуре исходных каталогов, только с префиксом OBJDIR или подобным, то это будет очень просто реализовать.

MadScientist 15.12.2020 21:14
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
7
707
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема здесь:

FILENAMES := $(shell find . -type f -name "*.c" -printf "%f\n")

Это неправильно, потому что -printf "%f\n" печатает только имена файлов без пути. Вы теряете всю информацию о пути, по которому находятся файлы, так как же их найти?

Вы должны изменить это на просто -print, тогда это сработает.

Другие вопросы по теме