У меня есть некоторые ограниченные знания о make-файле GNU, которые в настоящий момент меня подвели.
У меня есть файл объявления класса: mdfTree.h, реализация класса mdfTree.cpp и файл mdfTree_x.cpp с основным, где я создаю объект класса mdfTree и вызываю его открытые функции, которые в свою очередь вызывают некоторый закрытый член переменные mdfTree.
Я собираю его с Makefile:
CXX=g++
CXXFLAGS=-g -Wall -W -Wconversion -Wshadow -Wcast-qual -Wwrite-strings $(shell root-config --cflags --gl\
ibs)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
mdfTree_x: mdfTree_x.o
g++ $(LDFLAGS) -o mdfTree_x mdfTree_x.o $(LDLIBS)
mdfTree_x.o: mdfTree_x.cpp
g++ $(LDFLAGS) $(CXXFLAGS) -c mdfTree_x.cpp
mdfTree.cpp и mdfTree_x.cpp имеет #include mdfTree.h
в этом. Нужно ли mdfTree_x.cpp #include mdfTree.cpp
также?
Я думаю, что мой Makefile неправильный, потому что публичная функция из класса mdfTree не может видеть приватную переменную того же класса, когда я пытаюсь скомпилировать. Кроме того, когда я вставляю синтаксическую ошибку в mdfTree.h, компилятор не принимает ее. Как мне сказать Makefile, что mdfTree_x должен использовать / compile mdfTree.h / .cpp?
Вам нужно будет явно добавить все зависимости, в этом случае ваш исполняемый файл зависит от созданного mdfTree.o, а mdfTree.o и mdfTree_x.o зависят от mdfTree.h. Ваши зависимости должны быть как
mdfTree_x:mdfTree_x.o mdfTree.o
mdfTree.o:mdfTree.cpp mdfTree.h
mdfTree_x.o:mdfTree_x.cpp mdfTree.h
Некоторые компиляторы (например, GNU & intel) умеет автоматически перечислять зависимости заголовка в формате make. Например, этот make-файл будет восстанавливать исполняемый файл, когда любой из mdfTree_x.cpp
, mdfTree.cpp
или же mdfTree.h
изменено:
# Compiler flags...
CPPFLAGS+=-MMD -MP
mdfTree_x:mdfTree_x.o mdfTree.o
-include mdfTree_x.d mdfTree.d
CPPFLAGS создаст файл .d с зависимостями заголовка при компиляции, строка -include попытается включить их в make-файл, если он присутствует (если их нет, исходный файл все равно будет перекомпилирован, поэтому дополнительные зависимости не нужны). не имеет значения). Содержимое файла .d будет примерно таким
mdfTree.o:mdfTree.h
Кроме того, вам не нужно явно писать make-правила в большинстве случаев — например, если у вас есть файл foo.o
перечислены в качестве зависимостей правила GNU Make по умолчанию для запуска
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o foo.o foo.cpp
(и аналогично для других языков). Аналогично, связывание происходит автоматически, если имя исполняемого файла совпадает с одним из объектных файлов, например,
foo:foo.o
будет работать (обратите внимание, что CC не CXX)
$(CC) $(LDFLAGS) -o foo foo.o $(LDLIBS)
Использование правил по умолчанию упрощает make-файлы, а также позволяет использовать переменные окружения для настройки компилятора по умолчанию.
Нет, вам нужно настроить файл make для компиляции и связать mdfTree.cpp.
Что-то вроде этого
mdfTree.o: mdfTree.cpp
g++ $(LDFLAGS) $(CXXFLAGS) -c mdfTree.cpp
и измените шаг ссылки на
mdfTree_x: mdfTree_x.o mdfTree.o
g++ $(LDFLAGS) -o mdfTree_x mdfTree_x.o mdfTree.o $(LDLIBS)
У меня есть файл объявления класса: mdfTree.h, реализация класса mdfTree.cpp и файл mdfTree_x.cpp с основным, где я создаю объект класса mdfTree и вызываю его открытые функции, которые в свою очередь вызывают некоторый закрытый член переменные mdfTree.
Ваша программа нуждается в возможностях, определенных как в mdfTree.cpp, так и в mdfTree_x.cpp. Поэтому вам нужно скомпилировать оба этих файла, а ваша ссылка должна включать как mdfTree.o, так и mdfTree_x.o.
Вы можете написать два правила: одно для компиляции mdfTree.cpp, другое для компиляции mdfTree_x.cpp. Это быстро выйдет из-под контроля. Будь злым. Одно правило, чтобы построить их всех, одно правило, чтобы найти их, одно правило, чтобы привести их всех и в темноте связать их.
objects = mdfTree_x.o mdfTree.o
$(objects): %.o: %.cpp
g++ $(CXXFLAGS) -c $<
Обратите внимание, что нет $(LDFLAGS)
в приведенном выше правиле компиляции. Вы не должны указывать параметры ссылок при компиляции.
Вам необходимо связать объекты, чтобы сформировать исполняемый файл:
mdfTree_x: $(objects)
g++ $(LDFLAGS) -o $@ $^ $(LDLIBS)
Обратите внимание, что теперь вам нужно указать параметры компоновщика; Вы связываете.
Один последний пункт перед следующим шагом: порядок, в котором вы указываете правила в make-файле в общем, не имеет значения. Однако есть одно исключение. Самое первое правило — это правило по умолчанию, которое будет использоваться, если вы вообще не указали цель в make
команда. Это хорошая идея, чтобы явно поместить правило по умолчанию в самый верх make-файла. Например, поместите следующее где-то в верхней части вашего make-файла, следуя любым другим правилам:
default: mdfTree_x
В mdfTree.cpp и mdfTree_x.cpp есть #include mdfTree.h. Нужно ли mincTree_x.cpp #include mdfTree.cpp?
Никогда #include
исходный файл. Никогда. Пусть линкер сделает это.
Однако здесь чего-то не хватает. Предположим, вы изменили mdfTree.h. Вам нужно восстановить. Makefile пока не будет этого делать. Чего не хватает, так это зависимости от mdfTree.h. В этом случае есть простое решение этой проблемы зависимости: просто укажите зависимость.
$(objects): mdfTree.h
В общем, эта проблема зависимости заголовка является очень сложной проблемой. Лучше не помещать эти зависимости заголовочного файла в make-файл. Пусть какой-то автоматизированный инструмент, такой как makedepend
выяснить эти зависимости для вас.