Makefile с исходными файлами в разных каталогах
У меня есть проект, в котором структура каталогов выглядит следующим образом:
$projectroot
|
+---------------+----------------+
| | |
part1/ part2/ part3/
| | |
+------+-----+ +---+----+ +---+-----+
| | | | | | |
data/ src/ inc/ src/ inc/ src/ inc/
Как мне написать файл makefile, который был бы частично /src (или где бы он был на самом деле), который мог бы завершить/связать исходные файлы c/С++?/src?
Могу ли я сделать что-то вроде
-I $projectroot/part1/src -I $projectroot/part1/inc -I $projectroot/part2/src...
Если это сработает, есть ли более простой способ сделать это. Я видел проекты, в которых есть makefile в каждой из соответствующих частей? папки. [в этом посте я использовал знак вопроса, как в синтаксисе bash)
Ответы
Ответ 1
Традиционным способом является наличие Makefile
в каждом из подкаталогов (part1
, part2
и т.д.), что позволяет вам создавать их самостоятельно. Кроме того, в корневом каталоге проекта есть Makefile
, который строит все. "Root" Makefile
будет выглядеть примерно так:
all:
+$(MAKE) -C part1
+$(MAKE) -C part2
+$(MAKE) -C part3
Так как каждая строка в make-мишени запускается в своей собственной оболочке, нет необходимости беспокоиться о перемещении резервной копии дерева каталогов или других каталогов.
Я предлагаю взглянуть на GNU make manual section 5.7; это очень полезно.
Ответ 2
Если у вас есть код в одном подкаталоге, зависящем от кода в другом подкаталоге, вам, вероятно, лучше сделать один make файл на верхнем уровне.
См. Рекурсивный анализ считается вредным для полного обоснования, но в основном вы хотите получить полную информацию, необходимую для принятия решения о том, файл нужно перестроить, и у него не будет этого, если вы расскажете только о трети вашего проекта.
Ссылка выше, похоже, недоступна. Этот же документ доступен здесь:
Ответ 3
Вы можете добавить правила в свой корневой файл Makefile, чтобы скомпилировать необходимые файлы cpp в других каталогах. Приведенный ниже пример Makefile должен стать хорошим началом для вас, когда вы хотите быть.
CC=g++
TARGET=cppTest
OTHERDIR=../../someotherpath/in/project/src
SOURCE = cppTest.cpp
SOURCE = $(OTHERDIR)/file.cpp
## End sources definition
INCLUDE = -I./ $(AN_INCLUDE_DIR)
INCLUDE = -I.$(OTHERDIR)/../inc
## end more includes
VPATH=$(OTHERDIR)
OBJ=$(join $(addsuffix ../obj/, $(dir $(SOURCE))), $(notdir $(SOURCE:.cpp=.o)))
## Fix dependency destination to be ../.dep relative to the src dir
DEPENDS=$(join $(addsuffix ../.dep/, $(dir $(SOURCE))), $(notdir $(SOURCE:.cpp=.d)))
## Default rule executed
all: $(TARGET)
@true
## Clean Rule
clean:
@-rm -f $(TARGET) $(OBJ) $(DEPENDS)
## Rule for making the actual target
$(TARGET): $(OBJ)
@echo "============="
@echo "Linking the target [email protected]"
@echo "============="
@$(CC) $(CFLAGS) -o [email protected] $^ $(LIBS)
@echo -- Link finished --
## Generic compilation rule
%.o : %.cpp
@mkdir -p $(dir [email protected])
@echo "============="
@echo "Compiling $<"
@$(CC) $(CFLAGS) -c $< -o [email protected]
## Rules for object files from cpp files
## Object file for each file is put in obj directory
## one level up from the actual source directory.
../obj/%.o : %.cpp
@mkdir -p $(dir [email protected])
@echo "============="
@echo "Compiling $<"
@$(CC) $(CFLAGS) -c $< -o [email protected]
# Rule for "other directory" You will need one per "other" dir
$(OTHERDIR)/../obj/%.o : %.cpp
@mkdir -p $(dir [email protected])
@echo "============="
@echo "Compiling $<"
@$(CC) $(CFLAGS) -c $< -o [email protected]
## Make dependancy rules
../.dep/%.d: %.cpp
@mkdir -p $(dir [email protected])
@echo "============="
@echo Building dependencies file for $*.o
@$(SHELL) -ec '$(CC) -M $(CFLAGS) $< | sed "s^$*.o^../obj/$*.o^" > [email protected]'
## Dependency rule for "other" directory
$(OTHERDIR)/../.dep/%.d: %.cpp
@mkdir -p $(dir [email protected])
@echo "============="
@echo Building dependencies file for $*.o
@$(SHELL) -ec '$(CC) -M $(CFLAGS) $< | sed "s^$*.o^$(OTHERDIR)/../obj/$*.o^" > [email protected]'
## Include the dependency files
-include $(DEPENDS)
Ответ 4
Опция VPATH может пригодиться, что говорит о том, какие каталоги искать в исходном коде. Однако вам все равно нужна опция -I для каждого пути включения. Пример:
CXXFLAGS=-Ipart1/inc -Ipart2/inc -Ipart3/inc
VPATH=part1/src:part2/src:part3/src
OutputExecutable: part1api.o part2api.o part3api.o
Это автоматически найдет соответствующие файлы partXapi.cpp в любом из указанных каталогов VPATH и скомпилирует их. Однако это более полезно, когда ваш каталог src разбит на подкаталоги. Для того, что вы описали, как говорили другие, вам, вероятно, будет лучше с make файлом для каждой части, особенно если каждая часть может стоять одна.
Ответ 5
Если источники распространены во многих папках, и имеет смысл иметь индивидуальные Make файлы, то, как было предложено ранее, рекурсивный make является хорошим подходом, но для небольших проектов мне легче перечислить все исходные файлы в Makefile с помощью их относительный путь к Makefile:
# common sources
COMMON_SRC := ./main.cpp \
../src1/somefile.cpp \
../src1/somefile2.cpp \
../src2/somefile3.cpp \
Затем я могу установить VPATH
следующим образом:
VPATH := ../src1:../src2
Затем я создаю объекты:
COMMON_OBJS := $(patsubst %.cpp, $(ObjDir)/%$(ARCH)$(DEBUG).o, $(notdir $(COMMON_SRC)))
Теперь правило прост:
# the "common" object files
$(ObjDir)/%$(ARCH)$(DEBUG).o : %.cpp Makefile
@echo creating [email protected] ...
$(CXX) $(CFLAGS) $(EXTRA_CFLAGS) -c -o [email protected] $<
И создание выхода еще проще:
# This will make the cbsdk shared library
$(BinDir)/$(OUTPUTBIN): $(COMMON_OBJS)
@echo building output ...
$(CXX) -o $(BinDir)/$(OUTPUTBIN) $(COMMON_OBJS) $(LFLAGS)
Можно даже создать генерацию VPATH
с помощью:
VPATH := $(dir $(COMMON_SRC))
Или используя тот факт, что sort
удаляет дубликаты (хотя это не имеет значения):
VPATH := $(sort $(dir $(COMMON_SRC)))
Ответ 6
Я думаю, что лучше указать, что использование Make (рекурсивное или нет) - это то, чего обычно вы можете избежать, потому что по сравнению с сегодняшними инструментами его трудно изучать, поддерживать и масштабировать.
Это замечательный инструмент, но его прямое использование должно считаться устаревшим в 2010 году.
Если, конечно, вы не работаете в специальной среде, то есть с унаследованным проектом и т.д.
Используйте IDE, CMake, или, если вы сильно вывернуты, Autotools.
(отредактирован из-за downvotes, ty Honza для указания)
Ответ 7
Сообщение RC было SUPER полезным. Я никогда не думал об использовании функции $(dir [email protected]), но он сделал именно то, что мне было нужно.
В parentDir у вас есть куча каталогов с исходными файлами в них: dirA, dirB, dirC. Различные файлы зависят от объектных файлов в других каталогах, поэтому я хотел иметь возможность сделать один файл из одного каталога и сделать его зависимым, вызвав make файл, связанный с этой зависимостью.
По существу, я сделал один Makefile в parentDir, который (среди многих других) использовал общее правило, подобное RC:
%.o : %.cpp
@mkdir -p $(dir [email protected])
@echo "============="
@echo "Compiling $<"
@$(CC) $(CFLAGS) -c $< -o [email protected]
Каждый подкаталог включал этот файл верхнего уровня для того, чтобы наследовать это общее правило. В каждом подкаталоге Makefile я написал собственное правило для каждого файла, чтобы я мог отслеживать все, на что зависел каждый отдельный файл.
Всякий раз, когда мне нужно было создать файл, я использовал (по существу) это правило для рекурсивного создания любых/всех зависимостей. Отлично!
ПРИМЕЧАНИЕ: есть утилита под названием "makepp", которая, похоже, делает эту задачу еще более интуитивно, но ради мобильности и не зависит от другого инструмента, я решил сделать это таким образом.
Надеюсь, это поможет!
Ответ 8
Рекурсивное использование Make
all:
+$(MAKE) -C part1
+$(MAKE) -C part2
+$(MAKE) -C part3
Это позволяет make
разбиваться на задания и использовать несколько ядер
Ответ 9
Я предлагаю использовать autotools
:
//##
Поместите созданные объектные файлы (.o) в тот же каталог, что и их исходные файлы, чтобы избежать коллизий при использовании нерекурсивного make.
AUTOMAKE_OPTIONS = subdir-objects
просто включив его в Makefile.am
с другим довольно простым материалом.
Вот учебник.