Как написать Makefile (для проекта C++) с заголовком в родительском каталоге?

В настоящее время я борюсь с make, любой совет или учебник очень ценятся. Структура папок моего проекта выглядит так:

/project
  bar.hpp
  /folder1
    main.cpp // #include "foo.hpp"  #include "bar.hpp"
    foo.cpp  // #include "foo.hpp"  #include "bar.hpp"
    foo.hpp  // #include "bar.hpp"
    Makefile

Это компилируется при вызове из папки1.

g++-10 -std=c++2a -O3 -fno-pic -no-pie -Wall -I../ main.cpp foo.cpp

Я написал следующий Makefile, но он не работает так, как я ожидал:

CXX = g++-10
CXXFLAGS = -std=c++2a -O3 -fno-pic -no-pie -Wall
CPPFLAGS = -I../

.PHONY : all clean distclean

EXE = a.out
SRC = main.cpp foo.cpp
OBJ = $(SRC: .cpp=.o)
INC = $(wildcard *.hpp) ../bar.hpp

all : $(EXE)

clean :
    $(RM) *.o

distclean : clean
    $(RM) $(EXE)

$(EXE) : $(OBJ)
    $(CXX) $(CXXFLAGS) $^ -o $@

$(OBJ) : $(INC) // I hope this means that all object files depend on all header files?

%.o : %.cpp $(INC)
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@ 

Я вызываю make all из папки1, но это не работает.

Я попытался найти учебники по созданию С++, но не смог найти ни одного с подробными неявными и шаблонными правилами.

Это ошибка, которую я получаю

g++-10 -std=c++2a -O3 -fno-pic -no-pie -Wall main.cpp foo.cpp -o a.out
main.cpp:1:10: fatal error: bar.hpp: No such file or directory
    1 | #include "bar.hpp"
      |          ^~~~~~~~~
compilation terminated.
In file included from foo.cpp:1:
foo.hpp:1:10: fatal error: bar.hpp: No such file or directory
    1 | #include "bar.hpp"
      |          ^~~~~~~~~
compilation terminated.

Я попытался в папке1 запустить эти команды, и они правильно компилируются.

g++-10 -std=c++2a -O3 -fno-pic -no-pie -Wall -c foo.cpp -o foo.o -I../
g++-10 -std=c++2a -O3 -fno-pic -no-pie -Wall -c main.cpp -o main.o -I../
g++-10 -std=c++2a -O3 -fno-pic -no-pie -Wall -o main main.o foo.o

Вы говорите, что это не работает. Не могли бы вы поделиться сообщением об ошибке? Это может помочь нам диагностировать проблему

ibarrond 26.12.2020 19:01

g++-10 -std=c++2a -O3 -fno-pic -no-pie -Wall main.cpp foo.cpp -o a.out Он пытается выполнить эту строку и говорит, что bar.hpp не может быть найденный. Я не понимаю, почему он пытается построить a.out из файлов .cpp, пропуская файлы .o.

lucmobz 26.12.2020 19:22
Стоит ли изучать 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
2
139
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Эта строка неверна:

OBJ = $(SRC: .cpp=.o)

Добавляя пробел перед .cpp, вы говорите, что OBJ должен заменить все слова в переменной SRC, которые заканчиваются на « .cpp», на окончание .o. Но в переменной SRC нет слов, оканчивающихся на « .cpp», поэтому никаких изменений не производится, и значение OBJ совпадает со значением SRC.

Итак, ваше правило:

a.out : main.cpp foo.cpp

поэтому файлы .o не создаются, потому что ваша цель не зависит от них.

Уберите пробел:

OBJ = $(SRC:.cpp=.o)

Большое спасибо, есть ли какой-нибудь учебник или справочник, чтобы понять правила, подобные этому? Также излишне ли добавлять $(INC) в определение шаблона %o : %.cpp $(INC)?

lucmobz 26.12.2020 19:40

Есть руководство по созданию GNU. При написании ваших make-файлов вы должны использовать описание операций именно так, как показано здесь: добавление пробелов там, где их раньше не было, может изменить смысл вещей. Да, это избыточно, потому что вы уже указали $(OBJ) : $(INC), поэтому вам это не нужно в правиле шаблона.

MadScientist 26.12.2020 19:42

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