Makefile игнорирует включенные правила - PullRequest
0 голосов
/ 20 марта 2019

Я пытаюсь создать make-файл для очень простой программы на С ++.Я пытаюсь реализовать автоматическую генерацию зависимостей, запустив g ++ с флагом -M, сохранив этот вывод в файле .d, а затем включив эти файлы .d в мой основной make-файл.Содержимое make-файла ниже

CC=g++
CPPFLAGS=-Wall -Wextra -g -std=c++11

SOURCEDIR=src
SOURCES = $(wildcard $(SOURCEDIR)/*.cpp)

BUILDDIR=build
OBJDIR=$(BUILDDIR)/objs
OBJS=$(SOURCES:$(SOURCEDIR)/%.cpp=$(OBJDIR)/%.o)
DEP_FILES = $(OBJS:.o=.d)

OUTFILE=hello.out


$(OUTFILE) : $(OBJS)
    $(CC) -o $@ $^ $(CPPFLAGS)

include $(DEP_FILES)
$(OBJDIR)/%.d : $(SOURCEDIR)/%.cpp
    $(CC) $(CPPFLAGS) $< -MM -MT $(@:.d=.o) > $@

$(DEP_FILES) : | $(OBJDIR)
$(OBJS): | $(OBJDIR)

$(OBJDIR):
    mkdir -p $(OBJDIR)


.PHONY: clean
clean:
    rm -f $(BUILDDIR) -r
    rm -f *~ 
    rm -f $(OUTFILE)

Когда я запускаю make, создается каталог build/objs/ и файл .d с правилами в нем.Вот файл main.d:

build/objs/main.o: src/main.cpp src/main.h

А вот файл myfunc.d:

build/objs/myfunc.o: src/myfunc.cpp src/main.h

Вот проблема Поскольку я звоню, включите их.d-файлы, я ожидал бы, что затем будут созданы файлы .o, которые они указывают, а затем основной файл будет создан в качестве основного правила.Тем не менее, make создает файлы .d, а затем сразу переходит к основному этапу компиляции, не создавая никаких файлов .o:

g++ -o hello.out build/objs/myfunc.o build/objs/main.o -Wall -Wextra -g -std=c++11

Это происходит со следующей ошибкой, поскольку файлы .o никогда не создаютсясоздал:

g++: error: build/objs/myfunc.o: No such file or directory
g++: error: build/objs/main.o: No such file or directory
g++: fatal error: no input files

Как я могу использовать этот make-файл для генерации .o файлов, необходимых для g ++?Заранее благодарю за любую помощь!

Ответы [ 2 ]

1 голос
/ 21 марта 2019

Я видел, что ваш make-файл работает, но я просто хотел добавить несколько вещей, которые вы могли бы рассмотреть для будущих проектов. Я рекомендую использовать переменную vpath, а не указывать $(OBJDIR)/%.o в ваших рецептах make-файла. На самом деле я где-то читал, что это не «пушка» - создавать объектные файлы в отдельном каталоге, но в ходе простого поиска, который я проводил перед публикацией, я не смог найти документ.

Как говорится, я написал make-файл, который делает то, что вы хотели; он создает выходную папку, генерирует зависимости и компилирует программу. Я специально включил определение $(COMPILE.cpp), чтобы вы могли видеть, из чего оно состоит. $(CC) - это конкретно компилятор C, а $(CFLAGS) - это флаги для компилятора C. Очевидно, что это просто переменные, так что вы можете изменить их, как сделали, и это будет работать нормально, но главное, что нужно помнить, это то, что тот, кто использует ваши программы, будет ожидать, что он сможет настроить компиляцию так, как считает нужным. Это означает, что они установят $(CXX) и $(CXXFLAGS), ожидая установить компилятор C ++ и флаги. $(CPPFLAGS) обозначает флаги препроцессора C / C ++.

Это не самый чистый make-файл, и если бы я хотел что-то изменить, я бы просто скомпилировал объектные файлы на месте и избавил себя от этой головной боли. Это сокращает ненужный взлом, но для ответа на ваш вопрос, вот оно. В любом случае, я надеюсь, что это поможет вам, дайте мне знать, если у вас есть какие-либо вопросы.

<ч />

О да, я почти забыл; обратите внимание, что я изменил ваш make clean скрипт. Я использовал $(RM) вместо простого rm -f. Когда вы используете утилиты в ваших make-файлах, вы хотите использовать их как переменные . Опять же, это дает вашим пользователям как можно больше свободы и гибкости при компиляции вашей программы.

<ч />
vpath %.cpp src
vpath %.hpp include
vpath %.o build/objs
vpath %.d build/objs

.SUFFIXES:
.SUFFIXES: .cpp .hpp .o .d

SRCDIR          = src
INCLUDESDIR     = include
BUILDDIR        = build
OBJDIR          = $(BUILDDIR)/objs

SRCS            = $(wildcard $(SRCDIR)/*.cpp)
OBJS            = $(patsubst %.cpp, %.o, $(notdir $(SRCS)))
DEP_FILES       = $(patsubst %.o, %.d, $(OBJS))

INCLUDE_DIRS    = -I $(INCLUDESDIR)

CXX             = g++
CPPFLAGS        = 
CXXFLAGS        = -Wall -Wextra -g -std=c++11

PROGRAM         = hello.out

COMPILE.cpp     = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) $(TARGET_ARCH)

all: $(PROGRAM)

$(PROGRAM): %: $(OBJS)
    $(LINK.cpp) $(INCLUDE_DIRS) $(addprefix $(OBJDIR)/, $^) $(LOADLIBES) $(LDLIBS) -o $@

%.o: %.cpp
    $(COMPILE.cpp) -c -o $(OBJDIR)/$@ $<

%.d: %.cpp
    mkdir -p $(OBJDIR)
    $(COMPILE.cpp) $^ -MM -MT $(addprefix $(OBJDIR)/, $(@:.d=.o)) > $(OBJDIR)/$@

include $(DEP_FILES)

.PHONY: clean
clean:
    @echo $(RM)
    $(RM) $(BUILDDIR) -r
    $(RM) *~ 
    $(RM) $(PROGRAM)
0 голосов
/ 20 марта 2019

Для тех, у кого есть подобная проблема, вот правильное решение в комментариях.Здесь для удобства: включенные файлы .d генерируют зависимости, но не являются рецептом для создания файлов .o, и, поскольку я помещаю вещи в различные каталоги, правило по умолчанию здесь не работает, поэтому файлы .oне создано.Решением было добавить следующее правило в мой основной make-файл.

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

Спасибо Мэтту и Рено за ваши ответы!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...