how to prevent "directory already exists error" in a makefile when using mkdir - makefile

I need to generate a directory in my makefile and I would like to not get the "directory already exists error" over and over even though I can easily ignore it.
I mainly use mingw/msys but would like something that works across other shells/systems too.
I tried this but it didn't work, any ideas?
ifeq (,$(findstring $(OBJDIR),$(wildcard $(OBJDIR) )))
-mkdir $(OBJDIR)
endif

Looking at the official make documentation, here is a good way to do it:
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
$(OBJDIR)/%.o : %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
all: $(OBJS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir -p $(OBJDIR)
You should see here the usage of the | pipe operator, defining an order only prerequisite.
Meaning that the $(OBJDIR) target should be existent (instead of more recent) in order to build the current target.
Note that I used mkdir -p. The -p flag was added compared to the example of the docs.
See other answers for another alternative.

On UNIX Just use this:
mkdir -p $(OBJDIR)
The -p option to mkdir prevents the error message if the directory exists.

You can use the test command:
test -d $(OBJDIR) || mkdir $(OBJDIR)

Here is a trick I use with GNU make for creating compiler-output directories. First define this rule:
%/.d:
mkdir -p $(#D)
touch $#
Then make all files that go into the directory dependent on the .d file in that directory:
obj/%.o: %.c obj/.d
$(CC) $(CFLAGS) -c -o $# $<
Note use of $< instead of $^.
Finally prevent the .d files from being removed automatically:
.PRECIOUS: %/.d
Skipping the .d file, and depending directly on the directory, will not work, as the directory modification time is updated every time a file is written in that directory, which would force rebuild at every invocation of make.

If having the directory already exist is not a problem for you, you could just redirect stderr for that command, getting rid of the error message:
-mkdir $(OBJDIR) 2>/dev/null

Inside your makefile:
target:
if test -d dir; then echo "hello world!"; else mkdir dir; fi

On Windows
if not exist "$(OBJDIR)" mkdir $(OBJDIR)
On Unix | Linux
if [ ! -d "$(OBJDIR)" ]; then mkdir $(OBJDIR); fi

ifeq "$(wildcard $(MY_DIRNAME) )" ""
-mkdir $(MY_DIRNAME)
endif

$(OBJDIR):
mkdir $#
Which also works for multiple directories, e.g..
OBJDIRS := $(sort $(dir $(OBJECTS)))
$(OBJDIRS):
mkdir $#
Adding $(OBJDIR) as the first target works well.

It works under mingw32/msys/cygwin/linux
ifeq "$(wildcard .dep)" ""
-include $(shell mkdir .dep) $(wildcard .dep/*)
endif

If you explicitly ignore the return code and dump the error stream then your make will ignore the error if it occurs:
mkdir 2>/dev/null || true
This should not cause a race hazard in a parallel make - but I haven't tested it to be sure.

A little simpler than Lars' answer:
something_needs_directory_xxx : xxx/..
and generic rule:
%/.. : ;#mkdir -p $(#D)
No touch-files to clean up or make .PRECIOUS :-)
If you want to see another little generic gmake trick, or if you're interested in non-recursive make with minimal scaffolding, you might care to check out Two more cheap gmake tricks and the other make-related posts in that blog.

Related

Need to run make twice after make clean

All I want to do is gather source files from different source directories into one folder and then do the build of those make files. After a make clean I have to run make command twice to do the build.
So first I run make clean, then i run make, which throws an error saying no -o files found. But when iIrun the make again, the build goes through and generates the build files.
My makefile looks like below
.PHONY: dirs all clean
all: dirs $(OBJ_DIR) $(OBJ_FILES)
"$(CC) -rvn fLib.a $(OBJ_FILES)
# clean build target. Remove all files without reporting errors in case they don't exist.
clean:
#rm -rf fLib.a $(OBJ_DIR)
# Build target for creating flat header file folder for SharedTrackerAPI (FLAT_INC_DIR)
# due to too long paths in Windows 7 build
dirs:
#echo 'Making flat source and header folders.'
#mkdir -p $(OBJ_DIR)
#for f in $(SRC_FILES); do cp $$f $(OBJ_DIR); done
#mkdir -p $(FLAT_INC_DIR)
#OLD_CWD=$(CURDIR)
#cd $(FLAT_INC_DIR)
#find $(STA_RADAR_TRACKER_IFACE) -name '*.h' | xargs -i cp -l {} $(FLAT_INC_DIR)
#cd $(OLD_CWD)
$(OBJ_DIR)/%.o: $(OBJ_DIR)/%.cpp
"$(TASKING_CTC_BIN)"/cctc.exe $(CXXFLAGS) -c -o $# $< $(CC_INCLUDE_PATH)
What am I doing wrong that I have to run make twice after a make clean.
The problem is that although dirs will place the source files in the flat source directory, Make doesn't know that. Before it executes the dirs rule, it has already determined that it knows no way to build the object files.
The quick and dirty solution is to tell Make "trust me, it'll be fine"; one way to do that is to modify the object rule like this:
$(OBJ_DIR)/%.o:
"$(TASKING_CTC_BIN)"/cctc.exe $(CXXFLAGS) -c -o $# $(OBJ_DIR)/$*.cpp $(CC_INCLUDE_PATH)
If you stop there, you will have a working solution.
If you want a more clean, efficient and flexible makefile, you must rethink the approach to finding source files. I see no good reason to use the flat source file approach, but if you really want to use it, here is a good way:
vpath %.cpp $(dir $(SRC_FILES))
$(OBJ_DIR)/%.cpp: %.cpp
#cp $< $#
Now you can get rid of dir and use your unmodified object rule:
$(OBJ_DIR)/%.o: $(OBJ_DIR)/%.cpp
"$(TASKING_CTC_BIN)"/cctc.exe $(CXXFLAGS) -c -o $# $< $(CC_INCLUDE_PATH)
How to handle the header files (FLAT_INC_DIR) is up to you, but I recommend vpath again.

Make target with / at the end?

I wanted to write a general makefile that fulfils most of my needs for various projects at once. But then I tumbled over the following:
%/:
mkdir -p $#
.SECONDEXPANSION:
$(objects): $$(dir $$#)
I expected this to run just fine and create a directory whenever a dir for a target in $(objects) does need one. But somehow it didn't work. I checked and found the following: Targets can't end with '/'.
Is there a way I can avoid this?
You just need to select an suffix that will can't be the name of a file in the folder. For example .. So the rules become the following:
%/.:
mkdir -p $#
.SECONDEXPANSION:
$(objects): $$(dir $$#).
As . refers to the directory itself this should not create problems what-so-ever :)

Expanding dependency's dirname for Makefile wildcard

Following on from Build script to Makefile, which lives in this upstream location. I want to include the Javascript examples that are included into this generated HTML document as dependencies.
INFILES = $(shell find . -name "index.src.html")
OUTFILES = $(INFILES:.src.html=.html)
TEMP:= $(shell mktemp -u /tmp/specs.XXXXXX)
all: $(OUTFILES)
# Problem line:
%.html: %.src.html $(wildcard contacts/*js)
#echo Dependencies: $^
cd $(#D) && m4 -PEIinc index.src.html > $(TEMP)
anolis --max-depth=3 $(TEMP) $#
rm -f $(TEMP)
clean:
rm -f $(OUTFILES)
PHONY: all clean
I want $(wildcard contacts/*js) to be $(wildcard $(#D)/*js) or $(wildcard $(dirname %)/*js), but nothing I've tried works. There must be some sort of keyword to get the parent directory of the target or dependency so I can reference the javascript dependencies.
AFAIK, using $(#D) and other automatic variables inside list of prerequisites can only be achieved using secondary expansion feature of GNU Make.
Thus, your problem probably can be solved as follows:
.SECONDEXPANSION:
%.html: %.src.html $$(wildcard $$(#D)/*js)
However, I'm not sure whether it will work with pattern rules.

depending on directories in make [duplicate]

This question already has answers here:
how to prevent "directory already exists error" in a makefile when using mkdir
(12 answers)
Closed 9 years ago.
This is a followup to my earlier question: SO 4403861 because the suggested solutions broke the dependencies, making the makefile useless. I can't figure out why.
I am using gnu make 3.82
I have a rule that works if the obj directory has been created:
objdir:=../obj
$(objdir)/%.o: %.C
$(COMPILE) -MM -MT$(objdir)/$(notdir $#) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
$(COMPILE) -o $(objdir)/$(notdir $# ) -c $<
However, if the obj directory isn't there, make fails. I wanted make to automatically create ../obj on demand, so I added what I thought was very simple:
$(objdir)/%.o: %.C $(objdir)
$(COMPILE) -MM -MT$(objdir)/$(notdir $#) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
$(COMPILE) -o $(objdir)/$(notdir $# ) -c $<
$(objdir):
if [ ! -d $(objdir) ] ; then mkdir $(objdir) ; fi
When I do so, make always forces the compile, every time. Why? The mkdir should not happen unless there is no directory? Why are dependencies destroyed by this simple change?
You also can try with Order-only prerequisites.
There is a similar example, of your question, available.
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
$(OBJDIR)/%.o : %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
all: $(OBJS)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir $(OBJDIR)
As others have said, the problem is that a directory is considered "changed" whenever directory members are added or removed, so make sees your output directory changing all the time, and reruns all the compilations which you have told it depend on the output directory.
As an alternative to the workarounds described by others, recent GNU make versions have support for "order-only prerequisites". The description of order-only prerequisites in the manual includes an example of how to use them for directory creation.
Some sort of sentinel file will solve this quite nicely. Allows you to write a single pattern rule to create all folders, does not have any rogue recompilation issues, and is -j safe.
OBJDIR := objdir/
OBJS := $(addprefix ${OBJDIR},foo.o bar.o baz.o)
all: ${OBJS}
${OBJDIR}%.o : %.c ${OBJDIR}.sentinel
${COMPILE.c} ${OUTPUT_OPTION} $<
# A single pattern rule will create all appropriate folders as required
.PRECIOUS: %/.sentinel # otherwise make (annoyingly) deletes it
%/.sentinel:
mkdir -p ${#D}
touch $#
As answered already, you cannot put a directory with output files as a dependency, because it is updated every time.
One solution (stated above) is to put a mkdir -p before each build, like this:
objdir:=../obj
$(objdir)/%.o: %.C
#mkdir -p $(objdir) $(DEPDIR) ...
$(COMPILE) -MM -MT$(objdir)/$(notdir $#) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
$(COMPILE) -o $(objdir)/$(notdir $# ) -c $<
But I don't love this solution, because it forces running an extra process lots and lots of times. However, knowing the reason for the error, there is another way:
exe: dirs $(OBJ)
In the primary target, the one building the executable, just insert a target dirs before the objects. Since it's hit in order:
dirs:
#mkdir -p $(objdir) $(DESTDIR) ...
and this is only done once for the entire build, rather than once per file.

Create directories using make file

I want to create directories using makefile. My project directory is like this
+--Project
+--output
+--source
+Testfile.cpp
+Makefile
I want to put all the objects and output into the respective output folder. I want to create folder structure which would be like this after compiling.
+--Project
+--output
+--debug (or release)
+--objs
+Testfile.o
+Testfile (my executable file)
+--source
+Testfile.cpp
+Makefile
I tried with several options, but could not succeed. Please help me to make directories using make file. I'm posting my Makefile for your consideration.
#---------------------------------------------------------------------
# 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)
In my opinion, directories should not be considered targets of your makefile, either in technical or in design sense. You should create files and if a file creation needs a new directory then quietly create the directory within the rule for the relevant file.
If you're targeting a usual or "patterned" file, just use make's internal variable $(#D), that means "the directory the current target resides in" (cmp. with $# for the target). For example,
$(OUT_O_DIR)/%.o: %.cpp
#mkdir -p $(#D)
#$(CC) -c $< -o $#
title: $(OBJS)
Then, you're effectively doing the same: create directories for all $(OBJS), but you'll do it in a less complicated way.
The same policy (files are targets, directories never are) is used in various applications. For example, git revision control system doesn't store directories.
Note: If you're going to use it, it might be useful to introduce a convenience variable and utilize make's expansion rules.
dir_guard=#mkdir -p $(#D)
$(OUT_O_DIR)/%.o: %.cpp
$(dir_guard)
#$(CC) -c $< -o $#
$(OUT_O_DIR_DEBUG)/%.o: %.cpp
$(dir_guard)
#$(CC) -g -c $< -o $#
title: $(OBJS)
This would do it - assuming a Unix-like environment.
MKDIR_P = mkdir -p
.PHONY: directories
all: directories program
directories: ${OUT_DIR}
${OUT_DIR}:
${MKDIR_P} ${OUT_DIR}
This would have to be run in the top-level directory - or the definition of ${OUT_DIR} would have to be correct relative to where it is run. Of course, if you follow the edicts of Peter Miller's "Recursive Make Considered Harmful" paper, then you'll be running make in the top-level directory anyway.
I'm playing with this (RMCH) at the moment. It needed a bit of adaptation to the suite of software that I am using as a test ground. The suite has a dozen separate programs built with source spread across 15 directories, some of it shared. But with a bit of care, it can be done. OTOH, it might not be appropriate for a newbie.
As noted in the comments, listing the 'mkdir' command as the action for 'directories' is wrong. As also noted in the comments, there are other ways to fix the 'do not know how to make output/debug' error that results. One is to remove the dependency on the the 'directories' line. This works because 'mkdir -p' does not generate errors if all the directories it is asked to create already exist. The other is the mechanism shown, which will only attempt to create the directory if it does not exist. The 'as amended' version is what I had in mind last night - but both techniques work (and both have problems if output/debug exists but is a file rather than a directory).
Or, KISS.
DIRS=build build/bins
...
$(shell mkdir -p $(DIRS))
This will create all the directories after the Makefile is parsed.
make in, and off itself, handles directory targets just the same as file targets. So, it's easy to write rules like this:
outDir/someTarget: Makefile outDir
touch outDir/someTarget
outDir:
mkdir -p outDir
The only problem with that is, that the directories timestamp depends on what is done to the files inside. For the rules above, this leads to the following result:
$ make
mkdir -p outDir
touch outDir/someTarget
$ make
touch outDir/someTarget
$ make
touch outDir/someTarget
$ make
touch outDir/someTarget
This is most definitely not what you want. Whenever you touch the file, you also touch the directory. And since the file depends on the directory, the file consequently appears to be out of date, forcing it to be rebuilt.
However, you can easily break this loop by telling make to ignore the timestamp of the directory. This is done by declaring the directory as an order-only prerequsite:
# The pipe symbol tells make that the following prerequisites are order-only
# |
# v
outDir/someTarget: Makefile | outDir
touch outDir/someTarget
outDir:
mkdir -p outDir
This correctly yields:
$ make
mkdir -p outDir
touch outDir/someTarget
$ make
make: 'outDir/someTarget' is up to date.
TL;DR:
Write a rule to create the directory:
$(OUT_DIR):
mkdir -p $(OUT_DIR)
And have the targets for the stuff inside depend on the directory order-only:
$(OUT_DIR)/someTarget: ... | $(OUT_DIR)
All solutions including the accepted one have some issues as stated in their respective comments. The accepted answer by #jonathan-leffler is already quite good but does not take into effect that prerequisites are not necessarily to be built in order (during make -j for example). However simply moving the directories prerequisite from all to program provokes rebuilds on every run AFAICT.
The following solution does not have that problem and AFAICS works as intended.
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)
I've just come up with a fairly reasonable solution that lets you define the files to build and have directories be automatically created. First, define a variable ALL_TARGET_FILES that holds the file name of every file that your makefile will be build. Then use the following code:
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))))
Here's how it works. I define a function depend_on_dir which takes a file name and generates a rule that makes the file depend on the directory that contains it and then defines a rule to create that directory if necessary. Then I use foreach to call this function on each file name and eval the result.
Note that you'll need a version of GNU make that supports eval, which I think is versions 3.81 and higher.
given that you're a newbie, I'd say don't try to do this yet. it's definitely possible, but will needlessly complicate your Makefile. stick to the simple ways until you're more comfortable with make.
that said, one way to build in a directory different from the source directory is VPATH; i prefer pattern rules
OS independence is critical for me, so mkdir -p is not an option. I created this series of functions that use eval to create directory targets with the prerequisite on the parent directory. This has the benefit that make -j 2 will work without issue since the dependencies are correctly determined.
# convenience function for getting parent directory, will eventually return ./
# $(call get_parent_dir,somewhere/on/earth/) -> somewhere/on/
get_parent_dir=$(dir $(patsubst %/,%,$1))
# function to create directory targets.
# All directories have order-only-prerequisites on their parent directories
# https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html#Prerequisite-Types
TARGET_DIRS:=
define make_dirs_recursively
TARGET_DIRS+=$1
$1: | $(if $(subst ./,,$(call get_parent_dir,$1)),$(call get_parent_dir,$1))
mkdir $1
endef
# function to recursively get all directories
# $(call get_all_dirs,things/and/places/) -> things/ things/and/ things/and/places/
# $(call get_all_dirs,things/and/places) -> things/ things/and/
get_all_dirs=$(if $(subst ./,,$(dir $1)),$(call get_all_dirs,$(call get_parent_dir,$1)) $1)
# function to turn all targets into directories
# $(call get_all_target_dirs,obj/a.o obj/three/b.o) -> obj/ obj/three/
get_all_target_dirs=$(sort $(foreach target,$1,$(call get_all_dirs,$(dir $(target)))))
# create target dirs
create_dirs=$(foreach dirname,$(call get_all_target_dirs,$1),$(eval $(call make_dirs_recursively,$(dirname))))
TARGETS := w/h/a/t/e/v/e/r/things.dat w/h/a/t/things.dat
all: $(TARGETS)
# this must be placed after your .DEFAULT_GOAL, or you can manually state what it is
# https://www.gnu.org/software/make/manual/html_node/Special-Variables.html
$(call create_dirs,$(TARGETS))
# $(TARGET_DIRS) needs to be an order-only-prerequisite
w/h/a/t/e/v/e/r/things.dat: w/h/a/t/things.dat | $(TARGET_DIRS)
echo whatever happens > $#
w/h/a/t/things.dat: | $(TARGET_DIRS)
echo whatever happens > $#
For example, running the above will create:
$ make
mkdir w/
mkdir w/h/
mkdir w/h/a/
mkdir w/h/a/t/
mkdir w/h/a/t/e/
mkdir w/h/a/t/e/v/
mkdir w/h/a/t/e/v/e/
mkdir w/h/a/t/e/v/e/r/
echo whatever happens > w/h/a/t/things.dat
echo whatever happens > w/h/a/t/e/v/e/r/things.dat
See https://www.oreilly.com/library/view/managing-projects-with/0596006101/ch12.html
REQUIRED_DIRS = ...
_MKDIRS := $(shell for d in $(REQUIRED_DIRS); \
do \
[[ -d $$d ]] || mkdir -p $$d; \
done)
$(objects) : $(sources)
As I use Ubuntu, I also needed add this at the top of my Makefile:
SHELL := /bin/bash # Use bash syntax
I use the makefiles in windows environment and my simple solution is as follows,
Create a target makedir and add it as a prerequisites to where ever it is required.
# Default goal
all: gccversion makedir build finalize list sizeafter completed
The makedir target is (applicable only in windows environment)
makedir:
#IF NOT EXIST $(subst /,\,$(BUILD_DIR)) mkdir $(subst /,\,$(BUILD_DIR)) 2> NULL
#IF NOT EXIST $(subst /,\,$(OUTPUT_DIR)) mkdir $(subst /,\,$(OUTPUT_DIR)) 2> NULL
#IF NOT EXIST $(subst /,\,$(DEP_DIR)) mkdir $(subst /,\,$(DEP_DIR)) 2> NUL
#IF NOT EXIST $(subst /,\,$(OBJ_DIR)) mkdir $(subst /,\,$(OBJ_DIR)) 2> NUL
$(subst /,\,$(BUILD_DIR)) converts the directory separator / to \ and
mkdir $(subst /,\,$(BUILD_DIR)) 2> NUL redirects the error if any.
src_dir := src
obj_dir := obj
build_dir := build
dirs := $(src_dir) $(obj_dir) $(build_dir) # new variable
all: $(dirs) $(other_dependencies) # added dependency (*before* any others)
$(dirs): # rule which makes missing directories
mkdir $#
Won't clutter your terminal with "cannot create directory" error messages. If the directories exist, they don't need to be built.
Works like any other dependency, only requires one rule and one variable.

Resources