我有一个目录结构如下的项目:
$projectroot
|
+---------------+----------------+
| | |
part1/ part2/ part3/
| | |
+------+-----+ +---+----+ +---+-----+
| | | | | | |
data/ src/ inc/ src/ inc/ src/ inc/
我应该如何编写部分/ src(或其他任何地方)的makefile,它可以补充/链接部分?/ src中的c / c ++源文件?
我能做点什么吗? -I $ projectroot / part1 / src -I $ projectroot / part1 / inc -I $ projectroot / part2 / src ...
如果这样可行,是否有更简单的方法。我看过每个相应部分都有makefile的项目?文件夹。 [在这篇文章中我使用了像bash语法中的问号]
答案 0 :(得分:95)
传统方法是在每个子目录(Makefile
,part1
等)中都有part2
,允许您独立构建它们。此外,在项目的根目录中有一个Makefile
来构建所有内容。 “root”Makefile
类似于以下内容:
all:
+$(MAKE) -C part1
+$(MAKE) -C part2
+$(MAKE) -C part3
由于make目标中的每一行都在自己的shell中运行,因此无需担心遍历目录树或其他目录。
我建议看看GNU make manual section 5.7;这非常有帮助。
答案 1 :(得分:83)
如果一个子目录中的代码依赖于另一个子目录中的代码,那么最好使用顶层的单个makefile。
有关完整的基本原理,请参阅Recursive Make Considered Harmful,但基本上您希望make获得确定是否需要重建文件所需的完整信息,如果您只是告诉它,则不会有大约三分之一的项目。
上面的链接似乎无法访问。可在此处访问相同的文档:
答案 2 :(得分:30)
VPATH选项可能派上用场,它告诉make要查找源代码的目录。但是,对于每个包含路径,您仍然需要-I选项。一个例子:
CXXFLAGS=-Ipart1/inc -Ipart2/inc -Ipart3/inc
VPATH=part1/src:part2/src:part3/src
OutputExecutable: part1api.o part2api.o part3api.o
这将自动在任何VPATH指定目录中找到匹配的partXapi.cpp文件并进行编译。但是,当您的src目录分解为子目录时,这会更有用。正如你所描述的那样,正如其他人所说,你可能最好使用每个部件的makefile,特别是如果每个部件都可以独立使用。
答案 3 :(得分:23)
您可以向根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 $@" @echo "=============" @$(CC) $(CFLAGS) -o $@ $^ $(LIBS) @echo -- Link finished -- ## Generic compilation rule %.o : %.cpp @mkdir -p $(dir $@) @echo "=============" @echo "Compiling $<" @$(CC) $(CFLAGS) -c $< -o $@ ## 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 $@) @echo "=============" @echo "Compiling $<" @$(CC) $(CFLAGS) -c $< -o $@ # Rule for "other directory" You will need one per "other" dir $(OTHERDIR)/../obj/%.o : %.cpp @mkdir -p $(dir $@) @echo "=============" @echo "Compiling $<" @$(CC) $(CFLAGS) -c $< -o $@ ## Make dependancy rules ../.dep/%.d: %.cpp @mkdir -p $(dir $@) @echo "=============" @echo Building dependencies file for $*.o @$(SHELL) -ec '$(CC) -M $(CFLAGS) $< | sed "s^$*.o^../obj/$*.o^" > $@' ## Dependency rule for "other" directory $(OTHERDIR)/../.dep/%.d: %.cpp @mkdir -p $(dir $@) @echo "=============" @echo Building dependencies file for $*.o @$(SHELL) -ec '$(CC) -M $(CFLAGS) $< | sed "s^$*.o^$(OTHERDIR)/../obj/$*.o^" > $@' ## Include the dependency files -include $(DEPENDS)
答案 4 :(得分:18)
如果源代码分布在许多文件夹中,并且按照之前的建议建立单独的Makefile是有意义的,递归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 $@ ...
$(CXX) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
构建输出更加容易:
# 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)))
答案 5 :(得分:9)
我认为最好指出使用Make(递归或非递归)通常是您可能想要避免的,因为与今天的工具相比,它很难学习,维护和扩展。
这是一个很棒的工具,但直接使用应该在2010年以后被认为是过时的。
当然,除非您在特殊环境中工作,例如遗留项目等。
使用IDE,CMake,或者,如果您是硬核,则使用Autotools。
(由于downvotes编辑,ty Honza指出)
答案 6 :(得分:2)
RC的帖子非常有用。我从未想过使用$(dir $ @)函数,但它确实完成了我需要它做的事情。
在parentDir中,有一堆包含源文件的目录:dirA,dirB,dirC。各种文件依赖于其他目录中的目标文件,因此我希望能够在一个目录中创建一个文件,并通过调用与该依赖项关联的makefile使其成为依赖项。
基本上,我在parentDir中创建了一个Makefile,它在许多其他方面都有类似于RC的通用规则:
%.o : %.cpp @mkdir -p $(dir $@) @echo "=============" @echo "Compiling $<" @$(CC) $(CFLAGS) -c $< -o $@
每个子目录都包含此上级makefile,以便继承此通用规则。在每个子目录的Makefile中,我为每个文件编写了一个自定义规则,以便我可以跟踪每个文件所依赖的所有内容。
每当我需要创建文件时,我(基本上)使用此规则递归地生成任何/所有依赖项。完善!
注意:有一个名为“makepp”的实用程序似乎更直观地完成了这项任务,但为了便于携带而不依赖于其他工具,我选择这样做。
希望这有帮助!
答案 7 :(得分:2)
all:
+$(MAKE) -C part1
+$(MAKE) -C part2
+$(MAKE) -C part3
这允许make
分割成作业并使用多个核心
答案 8 :(得分:1)
我一直在寻找这样的东西,经过几次尝试后,我创建了自己的makefile,我知道这不是“惯用的方式”,但这是一种开始理解make的方法,这对我有用,也许您可以尝试使用项目。
PROJ_NAME=mono
CPP_FILES=$(shell find . -name "*.cpp")
S_OBJ=$(patsubst %.cpp, %.o, $(CPP_FILES))
CXXFLAGS=-c \
-g \
-Wall
all: $(PROJ_NAME)
@echo Running application
@echo
@./$(PROJ_NAME)
$(PROJ_NAME): $(S_OBJ)
@echo Linking objects...
@g++ -o $@ $^
%.o: %.cpp %.h
@echo Compiling and generating object $@ ...
@g++ $< $(CXXFLAGS) -o $@
main.o: main.cpp
@echo Compiling and generating object $@ ...
@g++ $< $(CXXFLAGS)
clean:
@echo Removing secondary things
@rm -r -f objects $(S_OBJ) $(PROJ_NAME)
@echo Done!
我知道这很简单,对于某些人来说,我的标志是错误的,但是正如我所说的,这是我的第一个Makefile,它将我的项目编译成多个目录,然后将所有这些链接在一起以创建我的bin。
我接受建议:D
答案 9 :(得分:0)
我建议使用autotools
:
//##
将生成的目标文件(.o)放入与其源文件相同的目录中,以避免在使用非递归make时发生冲突。
AUTOMAKE_OPTIONS = subdir-objects
将它包含在Makefile.am
中与其他非常简单的东西。
这是tutorial。