我希望我的所有构建文件都存储在项目根文件夹中的build
目录中。但是,如果我添加调试标志,我不想重建所有文件。因此,我有两个目录.build_release
和.build_debug
。然后我创建一个从build
到正确目录的符号链接。
我希望所有这些都由make
处理。这是我的makefile:
## setup
ifdef DEBUG
BUILDDIR=.build_debug
else
BUILDDIR=.build_release
endif
BLACKLIST:=bayesP obsDataStats test3 test bayesPsamplesBR test2 tuneSp \
toyFeatures2Multi getCov getDist isConnected mergeClusters sample \
toyFeatures0 toyFeatures1 toyFeatures2 toyFeatures3 toyFeatures4 \
toyFeatures6 toyFeatures7 wnsFeatures0 wnsFeatures1 wnsFeatures2
## make code
PROGS:=$(shell find ./src/ -maxdepth 1 -name "*.cpp" -exec grep -l "int main" {} \;)
PROGS:=$(notdir $(basename $(PROGS)))
PROGS:=$(filter-out $(BLACKLIST),$(PROGS))
CPP_SRC:=$(wildcard src/*.cpp)
CPP_SRC:=$(notdir $(basename $(CPP_SRC)))
CPP_SRC:=$(filter-out $(PROGS) $(BLACKLIST),$(CPP_SRC))
PROGS:=$(PROGS:=.bin)
PROGS:=$(PROGS:%=$(BUILDDIR)/%)
CPP_SRC:=$(CPP_SRC:%=src/%.cpp)
CPP_OBJ:=$(CPP_SRC:src/%.cpp=$(BUILDDIR)/%.o)
LIB=$(BUILDDIR)/libspatialDecisionMaking.so
## test code
CPP_SRC_TEST:=$(wildcard src/test/*.cpp)
CPP_SRC_TEST:=$(notdir $(basename $(CPP_SRC_TEST)))
CPP_SRC_TEST:=$(filter-out $(BLACKLIST),$(CPP_SRC_TEST))
PROGS_TEST:=$(CPP_SRC_TEST:%=$(BUILDDIR)/test/%.bin)
CPP_OBJ_TEST:=$(CPP_SRC_TEST:%=$(BUILDDIR)/test/%.o)
CPP_SRC_TEST:=$(CPP_SRC_TEST:%=src/test/%)
## options
CC=g++-4.9
ifdef DEBUG
CPP_FLAGS=-std=c++11 -ggdb
else
CPP_FLAGS=-std=c++11 -O3
endif
LD_FLAGS=-Isrc -L$(BUILDDIR) -lgsl -larmadillo -fPIC -fopenmp
## rules
all: | $(BUILDDIR) $(LIB) $(PROGS) build
test: | $(BUILDDIR)/test $(LIB) $(PROGS_TEST) build
build: $(BUILDDIR)
ln -rfs $(BUILDDIR) build
$(BUILDDIR)/test: $(BUILDDIR)
mkdir $(BUILDDIR)/test
$(BUILDDIR):
mkdir $(BUILDDIR)
$(BUILDDIR)/%.bin: src/%.cpp $(LIB)
$(CC) $(CPP_FLAGS) -o $@ $< $(LD_FLAGS) -l$(LIB:$(BUILDDIR)/lib%.so=%)
ln -rfs $@ $(@:%.bin=%)
$(LIB): $(CPP_OBJ)
$(CC) $(CPP_FLAGS) -o $@ $^ $(LD_FLAGS) -shared
$(BUILDDIR)/%.o: src/%.cpp $(BUILDDIR)/%.d
$(CC) $(CPP_FLAGS) -c $< -o $@ $(LD_FLAGS)
$(BUILDDIR)/%.d: src/%.cpp
$(CC) $(CPP_FLAGS) -MM $< -MT $(@:%.d=%.o) > $@ $(LD_FLAGS)
%.cpp:
%.hpp:
# include dependencies
-include $(CPP_OBJ:%.o=%.d)
clean:
rm -rf $(BUILDDIR)
虽然,它似乎跳过了$(BUILDDIR)
。我在每次运行make之前删除了目录,它直接根据目标$(BUILDDIR)/%.d
的规则构建依赖关系makefile。但是,在尝试构建依赖项时,它自然会抱怨,因为$(BUILDDIR)
不存在。
任何想法为什么会跳过制作$(BUILDDIR)
的方法?
答案 0 :(得分:2)
因为我还有一个关于SO的问题而不是答案,所以我必须找到一个问题来回答:),你似乎不喜欢已经存在的答案,所以好吧,即使你的问题不是“最小的” “,我花了一个小时来研究它。
你的Makefile一般情况不错,但它没有遵循一些“好的做法”。一旦我整理了一切,所有的问题就消失了。我希望它可以帮助您从这个示例中学习 - 我如何更改您的原始makefile以遵循良好实践。
唯一留下的小问题是build
每次都会重新链接。这是因为通常Make不依赖于变量值(例如DEBUG
),仅仅依赖于文件。通过创建“可靠变量”,可以解决这个问题(在这个小的情况下并不重要,但可能以后你需要这个解决方案)。
How do I force a target to be rebuilt if a variable is set?
下面是完整的工作makefile,我对代码之外的更改进行了注释。
## setup
可以
时使用:=
ifdef DEBUG
BUILDDIR:=.build_debug
else
BUILDDIR:=.build_release
endif
不要使用find
列出文件,更好地明确声明文件
PROGS:=\
prog0 \
prog1 \
CPP_SRC:=\
spam \
eggs \
CPP_SRC_TEST:=\
spam_test \
eggs_test \
拆分链接目标,因此只在规则中创建目标:
PROG_LINKS:=$(addprefix $(BUILDDIR)/, $(PROGS))
PROGS:=$(PROGS:=.bin)
PROGS:=$(PROGS:%=$(BUILDDIR)/%)
CPP_SRC:=$(CPP_SRC:%=src/%.cpp)
CPP_OBJ:=$(CPP_SRC:src/%.cpp=$(BUILDDIR)/%.o)
LIB:=$(BUILDDIR)/libspatialDecisionMaking.so
PROGS_TEST:=$(CPP_SRC_TEST:%=$(BUILDDIR)/test/%.bin)
PROGS_TEST_LINKS:=$(addprefix $(BUILDDIR)/test, $(CPP_SRC_TEST))
## options
CC=g++-4.9
你混淆了CPP_FLAGS
和LD_FLAGS
,我在每个中加上了正确的标记
另外,你找到共享库的方法太复杂了,我简单了。
CPP_FLAGS:= -std=c++11 -Isrc -fPIC -fopenmp
ifdef DEBUG
CPP_FLAGS+= -ggdb
else
CPP_FLAGS+= -O3
endif
LD_FLAGS:= -L$(BUILDDIR) -lgsl -larmadillo
## rules
你有太多的依赖 - 只列出那些手头目标所需的那些,并递归
all: | $(PROGS) $(PROG_LINKS) build
test: | $(PROGS_TEST) $(PROGS_TEST_LINKS) build
链接文件不以任何方式依赖链接目标
在你的情况下,它实际上取决于DEBUG
的值,但就像我上面说的那样,实现它并不是非常容易的,所以我在这里跳过它并且有一个虚假的,它重新链接所有时间
.PHONY: build
build:
ln -srf $(BUILDDIR) $@
这是处理目录创建的最佳方式
%/.:
mkdir -p $(@D)
不幸的是,这是必要的,因为mkdir -p
不是可重入且受竞争条件影响
$(BUILDDIR)/test/.: | $(BUILDDIR)/.
.SECONDEXPANSION:
$(PROGS_TEST_LINKS) $(PROG_LINKS): %: | %.bin
ln -sr $| $@
所有非平凡的食谱都应该依赖于这个makefile,将Makefile
更改为正确的(有更复杂的方法,自动处理)
$(BUILDDIR)/%.bin: src/%.cpp $(LIB) Makefile | $$(@D)/.
$(CC) $(CPP_FLAGS) -o $@ $< $(LD_FLAGS) $(LIB)
$(LIB): $(CPP_OBJ) Makefile | $$(@D)/.
$(CC) $(CPP_FLAGS) -o $@ $(CPP_OBJ) $(LD_FLAGS) -shared
这是处理“自动”依赖关系生成的最有效方法 - 它只调用预处理器一次,而不是原始makefile的两倍
我把它放在引号中,因为自动依赖的整个方法存在微妙的缺陷,并且在所有情况下都无法工作 - 但在你的简单情况下,你很可能遇到那个微妙的缺陷
是的我违反了上面提到的良好做法 - 只有在规则中创建的目标。如果一个人理解一个好的做法是什么,并且仍然认为更好地违反它,那么好。
$(BUILDDIR)/%.o: src/%.cpp Makefile | $$(@D)/.
$(CC) $(CPP_FLAGS) -MMD -MP -c $< -o $@ $(LD_FLAGS)
# include dependencies
-include $(CPP_OBJ:%.o=%.d)
clean:
rm -rf $(BUILDDIR)
答案 1 :(得分:0)
.d,.o和.bin文件在逻辑上依赖$(BUILDDIR)
,所以告诉make是这样的
$(BUILDDIR)/%.d: src/%.cpp | $(BUILDDIR)