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

#c #makefile #compilation #linker #gnu-make

#c #makefile #Сборник #компоновщик #gnu-make

Вопрос:

В настоящее время я борюсь с 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
 

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

 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

lt; -o $@

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

Я попытался найти учебные пособия по c make, но не смог найти ни одного с подробными неявными и шаблонными правилами.

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

 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.
 

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

 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
 

Комментарии:

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

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

Ответ №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)
 

Комментарии:

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

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