makefile跳过构建目录

时间:2016-09-01 02:18:14

标签: makefile

我希望我的所有构建文件都存储在项目根文件夹中的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)的方法?

2 个答案:

答案 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_FLAGSLD_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)