使用makefile创建目录

使用makefile创建目录,makefile,object,directory,Makefile,Object,Directory,我是makefiles的新手,我想使用makefile创建目录。我的项目目录如下 +--Project +--output +--source +Testfile.cpp +Makefile 我想把所有的对象和输出放到相应的输出文件夹中。我想创建文件夹结构,编译后会像这样 +--Project +--output +--debug (or release) +--objs +Testfile.o

我是makefiles的新手,我想使用makefile创建目录。我的项目目录如下

+--Project  
   +--output  
   +--source  
     +Testfile.cpp  
   +Makefile  
我想把所有的对象和输出放到相应的输出文件夹中。我想创建文件夹结构,编译后会像这样

+--Project
   +--output
     +--debug (or release)
       +--objs
         +Testfile.o
       +Testfile (my executable file)
   +--source
     +Testfile.cpp
   +Makefile
我尝试了几种选择,但没有成功。请帮助我使用make file创建目录。我将发布我的Makefile供您考虑

#---------------------------------------------------------------------
# Input dirs, names, files
#---------------------------------------------------------------------
OUTPUT_ROOT := output/

TITLE_NAME := TestProj 

ifdef DEBUG 
    TITLE_NAME += _DEBUG
else
ifdef RELEASE
    TITLE_NAME += _RELEASE
endif
endif


# Include all the source files here with the directory tree
SOURCES := \
        source/TestFile.cpp \

#---------------------------------------------------------------------
# configs
#---------------------------------------------------------------------
ifdef DEBUG
OUT_DIR     := $(OUTPUT_ROOT)debug
CC_FLAGS    := -c -Wall
else
ifdef RELEASE
OUT_DIR     := $(OUTPUT_ROOT)release
CC_FLAGS    := -c -Wall
else
$(error no build type defined)
endif
endif

# Put objects in the output directory.
OUT_O_DIR   := $(OUT_DIR)/objs

#---------------------------------------------------------------------
# settings
#---------------------------------------------------------------------
OBJS = $(SOURCES:.cpp=.o)
DIRS = $(subst /,/,$(sort $(dir $(OBJS))))
DIR_TARGET = $(OUT_DIR)

OUTPUT_TARGET = $(OUT_DIR)/$(TITLE_NAME)

CC_FLAGS +=   

LCF_FLAGS := 

LD_FLAGS := 

#---------------------------------------------------------------------
# executables
#---------------------------------------------------------------------
MD := mkdir
RM := rm
CC := g++

#---------------------------------------------------------------------
# rules
#---------------------------------------------------------------------
.PHONY: all clean title 

all: title 

clean:
    $(RM) -rf $(OUT_DIR)

$(DIR_TARGET):
    $(MD) -p $(DIRS)

.cpp.o: 
    @$(CC) -c $< -o $@

$(OBJS): $(OUT_O_DIR)/%.o: %.cpp
    @$(CC) -c $< -o $@

title: $(DIR_TARGET) $(OBJS)
#---------------------------------------------------------------------
#输入目录、名称、文件
#---------------------------------------------------------------------
输出根:=输出/
TITLE\u NAME:=TestProj
ifdef调试
标题\u名称+=\u调试
其他的
ifdef释放
标题\u名称+=\u发布
恩迪夫
恩迪夫
#在目录树中包含所有源文件
资料来源:=\
source/TestFile.cpp\
#---------------------------------------------------------------------
#配置
#---------------------------------------------------------------------
ifdef调试
OUT\u DIR:=$(输出\u根)调试
CC_标志:=-c-墙
其他的
ifdef释放
OUT\u DIR:=$(输出\u根目录)发布
CC_标志:=-c-墙
其他的
$(错误:未定义生成类型)
恩迪夫
恩迪夫
#将对象放入输出目录。
OUT\u O\u DIR:=$(OUT\u DIR)/objs
#---------------------------------------------------------------------
#背景
#---------------------------------------------------------------------
OBJS=$(来源:.cpp=.o)
DIRS=$(subst/,/,$(sort$(dir$(OBJS)))
DIR\u TARGET=$(OUT\u DIR)
输出\目标=$(输出\目录)/$(标题\名称)
CC_标志+=
LCF_标志:=
劳工处旗帜:
#---------------------------------------------------------------------
#可执行文件
#---------------------------------------------------------------------
MD:=mkdir
RM:=RM
CC:=g++
#---------------------------------------------------------------------
#规则
#---------------------------------------------------------------------
.冒牌货:全是干净的头衔
全部:标题
清洁:
$(RM)-rf$(输出方向)
$(DIR_目标):
$(MD)-p$(目录)
.cpp.o:
@$(CC)-c$<-o$@
$(OBJS):$(OUT\u O\u DIR)/%.O:%.cpp
@$(CC)-c$<-o$@
标题:$(目录目标)$(OBJS)

提前谢谢。如果我也犯了错误,请指导我

既然你是个新手,我想说现在还不要尝试这么做。这当然是可能的,但会不必要地使Makefile复杂化。坚持简单的方法,直到你对make更满意为止


也就是说,在不同于源目录的目录中构建的一种方法是;我更喜欢这样做——假设是一个类似Unix的环境

MKDIR_P = mkdir -p

.PHONY: directories

all: directories program

directories: ${OUT_DIR}

${OUT_DIR}:
        ${MKDIR_P} ${OUT_DIR}
这必须在顶级目录中运行,或者${OUT_DIR}的定义必须相对于它的运行位置是正确的。当然,如果您遵循Peter Miller的“”论文中的法令,那么您将在顶级目录中运行make

我现在正在玩这个(RMCH)。它需要对我用作测试场的软件套件进行一些调整。该套件有十几个独立的程序,其源代码分布在15个目录中,其中一些是共享的。但只要小心一点,这是可以做到的。OTOH,这可能不适合新手



如注释中所述,将“mkdir”命令列为“directories”的操作是错误的。如注释中所述,还有其他方法可以修复导致的“不知道如何进行输出/调试”错误。一种是删除“目录”行上的依赖项。这是因为如果要求“mkdir-p”创建的所有目录都已存在,则“mkdir-p”不会生成错误。另一个是所示的机制,仅当目录不存在时才会尝试创建该目录。“修订后的”版本是我昨晚想到的-但这两种技术都可以工作(如果存在输出/调试,但都是文件而不是目录,那么这两种技术都会有问题)。

在我看来,目录不应该被视为makefile的目标,无论是在技术上还是在设计上。您应该创建文件,如果文件创建需要一个新目录,则在相关文件的规则内安静地创建目录

如果您针对的是一个普通的或“模式化”文件,只需使用
make
的内部变量
$(@D)
,这意味着“当前目标所在的目录”(对于目标,使用
$@
的cmp。比如说,

$(OUT_O_DIR)/%.o: %.cpp
        @mkdir -p $(@D)
        @$(CC) -c $< -o $@

title: $(OBJS)

我刚刚提出了一个相当合理的解决方案,允许您定义要构建的文件并自动创建目录。首先,定义一个变量
ALL_TARGET_FILES
,该变量保存生成文件的每个文件的文件名。然后使用以下代码:

define depend_on_dir
$(1): | $(dir $(1))

ifndef $(dir $(1))_DIRECTORY_RULE_IS_DEFINED
$(dir $(1)):
    mkdir -p $$@

$(dir $(1))_DIRECTORY_RULE_IS_DEFINED := 1
endif
endef

$(foreach file,$(ALL_TARGET_FILES),$(eval $(call depend_on_dir,$(file))))
下面是它的工作原理。我定义了一个函数
depend_on_dir
,它接受一个文件名并生成一个规则,使文件依赖于包含它的目录,然后定义一个规则来创建该目录(如果需要)。然后我使用
foreach
对每个文件名调用
此函数,并
eval
结果


请注意,您需要一个支持
eval
的GNU make版本,我认为它是3.81版和更高版本。

所有解决方案,包括公认的解决方案,都有一些问题,请参见各自的评论。已经很好了,但是没有考虑到先决条件不一定要按顺序构建(例如在
make-j
期间)。但是,只要将
目录
先决条件从
all
移动到
program
就会在每次运行时引发重建。 以下解决方案不存在该问题,AFAICS按预期工作

MKDIR_P := mkdir -p
OUT_DIR := build

.PHONY: directories all clean

all: $(OUT_DIR)/program

directories: $(OUT_DIR)

$(OUT_DIR):
    ${MKDIR_P} $(OUT_DIR)

$(OUT_DIR)/program: | directories
    touch $(OUT_DIR)/program

clean:
    rm -rf $(OUT_DIR)

操作系统独立性对我来说至关重要,因此
mkdir-p
不是一个选项。我创建了这一系列函数,它们使用
eval
在父目录上创建具有先决条件的目录目标。这有
make的好处
MKDIR_P := mkdir -p
OUT_DIR := build

.PHONY: directories all clean

all: $(OUT_DIR)/program

directories: $(OUT_DIR)

$(OUT_DIR):
    ${MKDIR_P} $(OUT_DIR)

$(OUT_DIR)/program: | directories
    touch $(OUT_DIR)/program

clean:
    rm -rf $(OUT_DIR)
DIRS=build build/bins

... 

$(shell mkdir -p $(DIRS))
outDir/someTarget: Makefile outDir
    touch outDir/someTarget

outDir:
    mkdir -p outDir
$ make
mkdir -p outDir
touch outDir/someTarget
$ make
touch outDir/someTarget
$ make
touch outDir/someTarget
$ make
touch outDir/someTarget
# The pipe symbol tells make that the following prerequisites are order-only
#                           |
#                           v
outDir/someTarget: Makefile | outDir
    touch outDir/someTarget

outDir:
    mkdir -p outDir
$ make
mkdir -p outDir
touch outDir/someTarget
$ make
make: 'outDir/someTarget' is up to date.
$(OUT_DIR):
    mkdir -p $(OUT_DIR)
$(OUT_DIR)/someTarget: ... | $(OUT_DIR)
REQUIRED_DIRS = ...
_MKDIRS := $(shell for d in $(REQUIRED_DIRS); \
             do                               \
               [[ -d $$d ]] || mkdir -p $$d;  \
             done)

$(objects) : $(sources)
SHELL := /bin/bash # Use bash syntax