Is it possible to create all missing directory at once with make? - makefile

The common pattern is:
obj/%.o : src/%.c
mkdir -p $(dir $#)
$(CC) -c $< -o $#
I am wondering if I can space the call to mkdir for each file. I came across this solution:
CSRC=some/path/here/foo.c another/directory/random/here/bar.c
OBJDIR=obj/
objdirs = $(sort $(foreach path,$(CSRC),$(addprefix $(OBJDIR),$(dir $(path)))))
$(objdirs): %:
mkdir -p $#
obj/%.o : src/%.c | $(objdirs)
$(CC) -c $< -o $#
Is there a better solution?

A simple solution, but not 100% satisfactory, resembles yours:
OBJDIR := obj
CSRC := some/path/here/foo.c another/directory/random/here/bar.c
CSRCDIRS := $(sort $(dir $(CSRC)))
objdirs := $(addprefix $(OBJDIR)/,$(CSRCDIRS))
OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(CSRC))
$(OBJS): $(OBJDIR)/%.o: %.c | $(objdirs)
$(CC) -c $< -o $#
$(objdirs):
mkdir -p $#
It should work but its drawback is that each object file has all object directories as order-only prerequisite, which is overkill. All object directories will be created, even if only one object file is built. They will be created only once because they are order-only, but still, it is not 100% satisfactory.
In order to have only one order-only object directory prerequisite per object file, the only solution I see (but there may be better ones) is something like:
OBJDIR := obj
CSRC := some/path/here/foo.c another/directory/random/here/bar.c
CSRCDIRS := $(sort $(dir $(CSRC)))
objdirs := $(addprefix $(OBJDIR)/,$(CSRCDIRS))
# $(1): source directory
define MY_rule
$(OBJDIR)/$(1)%.o: $(1)%.c | $(OBJDIR)/$(1)
$(CC) -c $$< -o $$#
endef
$(foreach c,$(CSRCDIRS),$(eval $(call MY_rule,$(c))))
$(objdirs):
mkdir -p $#
The iterator explicitly declares each object directory as the only order-only prerequisite of all object files it contains. But it is more difficult to understand (especially the $$). Is it worth the extra complexity?

Related

How do I write a prerequisite to loop through two lists of files together?

This is an example illustrating the output I would like:
LIST1 := hello.o world.o
LIST2 := hello.c world.c
# Make the first object
# hello.o: hello.c
$(word 1, $(LIST1)): $(word 1, $(LIST2))
cc -c $^ -o $#
# Make the second object
# world.o: world.c
$(word 2, $(LIST1)): $(word 2, $(LIST2))
cc -c $^ -o $#
Is there a way to summarise the target: prerequisite text so that it loops through two entire lists?
I have tried using foreach functions with word functions but I don't get the output. I get non-numeric arguments to word and other invalid expressions.
You actually can do it, but it's really ugly (and would be hard to maintain), I'm showing the answer, but I am definitely not suggesting using it... If you can use pattern rules as #MadScientist suggests, that would be best. If not (say the names differ, you can do something like):
LIST1 := hello.o bob.o
hello.o : hello.c
bob.o : sally.c
$(LIST1):
cc -c $< -o $#
Which allows you to specify custom prereqs for each target. If you really need two lists, the technical answer to your question would be as follows:
LIST1 := hello.o bob.o
LIST2 := hello.c sally.c
all:
define recursive_def
$(firstword $(1)) : $(firstword $(2))
cc -c $$^ -o $$#
$(if $(wordlist 2,3,$1),$(call recursive_def,$(wordlist 2,$(words $(1)),$1),$(wordlist 2,$(words $(2)),$(2))))
endef
$(info -v---v-)
$(info $(call recursive_def,$(LIST1),$(LIST2)))
$(info -^---^-)
$(eval $(call recursive_def,$(LIST1),$(LIST2)))
The short answer is "no". Why don't you just write a pattern rule?
all: $(LIST1)
%.o : %.c
cc -c $^ -o $#
? In fact you don't even need to write a pattern rule at all: make already has a default rule that can build object files from C source files.
ETA
If you have source files in different directories, you have two choices. The best choice is to have one pattern rule and create all your objects in a subdirectory structure that mimics your source directories. So, like this:
SRCS := foo.c bar/bar.c bar/biz/baz.c
OBJS := $(patsubst %.c,obj/%.o,$(SRCS))
all: $(OBJS)
obj/%.o : %.c
#mkdir -p $(#D)
$(COMPILE.c) -o $# $<
If you really don't want to do that and you want to put all the object files into the same directory (a bad idea because if you have two source files with the same name in different source directories, your build will fail) you can use VPATH:
SRCS := foo.c bar/bar.c bar/biz/baz.c
OBJS := $(patsubst %.c,obj/%.o,$(notdir $(SRCS)))
VPATH := $(sort $(dir $(SRCS)))
all: $(OBJS)
obj/%.o : %.c
#mkdir -p $(#D)
$(COMPILE.c) -o $# $<

Makefile with multiple directories and dependencies

``I am pretty new to Makefile and I am trying to build a project.
This is the structure of my project:
-Project
|-generic
| |-include
| |-src
|-specific
| |-include
| |-src
|-Makefile
|-bin
Here generic contains mainly interface classes (virtual), and files in specific may depends on those.
I want to compile all sources and put their corresponding .o files in bin and also create a static library in bin.
EDIT:
CC=k1-g++
CPPFLAGS=-c -I$(GENERIC_INCLUDE_DIR) -I$(SPECIFIC_INCLUDE_DIR) -Os -std=gnu++11 -mos=nodeos
CXXFLAGS=-c -I$(GENERIC_INCLUDE_DIR) -I$(SPECIFIC_INCLUDE_DIR) -Os -std=gnu++11 -mos=nodeos
LFLAGS=-pthread -lnodeos
GENERIC_INCLUDE_DIR=generic/include
SPECIFIC_INCLUDE_DIR=specific/include
GENERIC_SRC_DIR=generic/src
SPECIFIC_SRC_DIR=specific/src
LIB = libengine.a
BIN_DIR=bin
vpath %.cpp $(GENERIC_SRC_DIR) $(SPECIFIC_SRC_DIR)
SOURCES := $(wildcard $(GENERIC_SRC_DIR)/*.cpp $(SPECIFIC_SRC_DIR)/*.cpp)
#SOURCES := $(wildcard $(GENERIC_SRC_DIR)/*.cpp $(SPECIFIC_SRC_DIR)/*.cpp)
SOURCES := $(notdir $(SOURCES))
OBJECTS := $(patsubst %.cpp,$(BIN_DIR)/%.cpp.o,$(SOURCES))
all: $(OBJECTS) $(LIB)
$(LIB): $(OBJECTS)
ar -cvq $(BIN_DIR)/$# $^
#$(BIN_DIR)/%.cpp.o: $(GENERIC_SRC_DIR)/%.cpp
# $(CC) $(CPPFLAGS) $< $(LFLAGS) -o $#
$(BIN_DIR)/%.cpp.o: %.cpp
$(CC) $(CPPFLAGS) $< $(LFLAGS) -o $#
.PHONY: clean
clean:
rm -f $(BIN_DIR)/*
Any help would be appreciated
Suppose you have generic/src/foo.cpp and specific.src/bar.cpp.
This:
$(BIN_DIR)/%.o: %.cpp
$(CC) $(CPPFLAGS) $*.cpp -o $#
is pretty close to what you need (I've replaced $(BIN_DIR)/$*.o with the automatic variable $#, which expands to the name of the target); the only problem is that it doesn't work. This rule tells Make it can build obj/foo.o from foo.cpp, but there is no foo.cpp. There's a generic/src/foo.cpp, but Make doesn't know that that's what you meant. We could write a rule like this:
$(BIN_DIR)/%.o: $(GENERIC_SRC_DIR)/%.cpp
$(CC) $(CPPFLAGS) $*.cpp -o $#
But a tidier way is to use the vpath directive:
vpath %.cpp $(GENERIC_SRC_DIR) $(SPECIFIC_SRC_DIR)
$(BIN_DIR)/%.o: %.cpp
$(CC) $(CPPFLAGS) $*.cpp -o $#
This will do nicely for building any one object file, but you say you want to compile "all sources". That isn't always a good idea, but if that's what you want it isn't hard, we use wildcard to obtain a list of all the sources, then convert that into a list of corresponding object files, then build them all:
SOURCES := $(wildcard $(GENERIC_SRC_DIR)/*.cpp $(SPECIFIC_SRC_DIR)/*.cpp)
SOURCES := $(notdir $(SOURCES))
OBJECTS := $(patsubst %.cpp,%.o, $(SOURCES))
# We could have done that all in one line, but this way is easier to read.
all: $(OBJECTS)
Now for the library:
vpath %.o $(BIN_DIR)
$(BIN_DIR)/$(LIB): $(OBJECTS)
ar -cvq $# $^
Further refinements are possible, but that should keep busy for a while.

Makefile does not work properly

I've this folder structure
project
|_src
| |_test
| |_main.cpp
|_Makefile
This is my makefile (trying to adapt from this link):
CC = g++
RM = rm
WFLAGS = -c -Wall -W
LDFLAGS =
SRCTESTD = src/test
EXECUTABLE = test
OBJD = .obj
DEPD = .dep
SRCSTEST = $(SRCTESTD)/main.cpp
OBJECTSTEST = $(patsubst %.cpp, $(OBJD)/test/%.o, $(notdir $(SRCSTEST)))
DEPDSTEST = $(patsubst %.cpp, $(DEPD)/test/%.d, $(notdir $(SRCSTEST)))
all: $(SRCSTEST) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTSTEST)
$(CC) $(LDFLAGS) $(OBJECTSTEST) -o $#
.cpp.o:
$(CC) $(WFLAGS) $< -o $#
It does not work, and I've this error
make: *** No rule to make target `.obj/test/main.o', needed by `test'. Stop.
What I'm doing wrong? Sorry for trivial question, but I'm a make newbie.
The link shows outdated methods, such as suffix rules. Making dependencies can also be done during compilation by gcc/g++.
As for the rest, here is it :
EXE := test
SRCDIR := src
OBJDIR := .obj
SRC := $(shell find $(SRCDIR) -name "*.cpp")
OBJ := $(SRC:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEP := $(OBJ:.o=.d)
LDLIBS := # -l flags
LDFLAGS := # -L flags
CPPFLAGS := -MMD -MP # -I flags also
CXXFLAGS := -W -Wall # no -c flag here
.PHONY: all clean fclean re
all: $(EXE)
clean:
$(RM) -r $(OBJDIR)
fclean: clean
$(RM) $(EXE)
re: fclean all
-include $(DEP)
$(EXE): $(OBJ)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
No redefinition of internally defined variables, no suffix rules, correct linking step and dependencies generation.
Update: To avoid calling mkdir for every source file, one should use order-only prerequisites and the special target .SECONDEXPANSION.
Change this block:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
To this:
.SECONDEXPANSION:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp | $$(#D)/
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
%/:
mkdir $*
The error means make can't find a correct rule to build your object files. Your tree structure lacks some informations: only one file ? Where are the others ? Anyway, here are some hints:
In the last two lines, you are using an obsolete feature of make: suffix rules. I suggest you switch to a pattern rule, which is functionaly equivalent.
Say something like:
%.o: %.cpp
$(CXX) $(CXXFLAGS) $< -o $#
Another thing (that shouldn't be a problem here): you are using the variable CC which is internally defined as the default C compiler. It's okay because you redefine it, but as your sources seem to be C++ files, why not use the variable CXX, that is internally defined as the C++ compiler ?
Lastly, to make sure your set of files are correctly defined, you can print them with a dummy show target, see here.
show:
#echo "OBJECTSTEST=$(OBJECTSTEST)"
...

Create Directory using MakeFile

I wrote a MakeFile, but I need it to create folder OBJ, so, for this, I tried a lot of things... based on this link:
https://stackoverflow.com/questions/ask
So, that is my makefile
IDIR =.
CC=gcc
CFLAGS=-I$(IDIR) -Wall -g
SRCDIR=src
ODIR=obj
LIBS=-ltest
_OBJ = main.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
OUTPUTDIR = ../bin
$(ODIR)/%.o: $(SRCDIR)/%.c
$(CC) -c -o $# $< $(CFLAGS)
$(OUTPUTDIR)/test: $(OBJ)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
I need to create the obj folder, I tried that idea:
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)
and this:
MKDIR_P = mkdir -p
.PHONY: directories
all: directories program
directories: ${OUT_DIR}
${OUT_DIR}:
${MKDIR_P} ${OUT_DIR}
But apparently every time I called the makefile, it ignored the command to create the directory OBJ and began compiling directly...
How I can make to makefile create the directory?
Another approach is to have a dummy variable that evaluates early in the parse of the Makefile and produces the required folder.
ODIR = obj_64
dummy_build_folder := $(shell mkdir -p $(ODIR))
Then the rest of the Makefile can safely assume that $(ODIR) exists.
I've used this on various Linux flavors, and Solaris, with GNU Make 3.81.
Try this:
OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
$(OBJDIR)/%.o : %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
all: $(OBJS)
$(OBJS): | $(OBJDIR)
$(OBJDIR): FORCE
mkdir -p $(OBJDIR)
FORCE:

Makefile mirror build directory

I need to create Makefile that compiles .c files with a lot of subdirs (sources directory goes in around 5 level depth) and I need to place the object files in the mirrored build directory. So far, I have created this Makefile:
CC := gcc.exe
AS := as.exe
CFLAGS = -DCORE_SW_VERSION='"$(CORE_SW_VERSION)"' -Wall -mA6 -c -fmessage-length=0 -Hsdata0
CFLAGS += -fgnu89-inline -mno-volatile-cache $(INCLUDE) -Hon=each_function_in_own_section -Xcrc -std=c99 -O1
CORE_SW_VERSION:=CORE.07.01.04.01.03.01.R
HAL_SW_VERSION:=16.01.06.01.06.00
MODE_CORE := dev
MODE_HAL := dev
OBJDIR := $(shell pwd)/$(TARGET12) #TARGET12 is a make parameter
INCLUDE := $(shell cat ./$(TARGET12)_include.txt)
SOURCEDIR := ../sources
CSRC := $(shell find $(SOURCEDIR) -name '*.c')
EXCLUDES := $(shell cat ./$(TARGET12)_exclude.txt)
OBJ := $(CSRC:.c=.o)
OBJS := $(patsubst ../%.c,$(OBJDIR)/%.o,$(CSRC))
.PHONY: $(TARGET12)
$(TARGET12): $(OBJS)
$(AR) -r $(CORE_SW_VERSION).a $(OBJS)
$(OBJS): $(CSRC)
mkdir -p $(dir $#)
$(CC) $(CFLAGS) $< -o $(patsubst ../%,$(OBJDIR)/%,$#)
If I define rule for $(OBJS) this way, $< is always the first .c file in $(CSRC).
If I define $(OBJS) this way:
$(OBJS): %.o: %.c
mkdir -p $(dir $#)
$(CP) $< $#
I get error that there is no rule to make target for .c file. But I see that make is looking for .c file in build mirrored directory, and it should look at the source dir. Do you maybe know how this could be arranged?
Thanks you in advance!
The rule $(OBJS): %.o: %.c means something like this: when trying to create a .o file, use this rule if the corresponding .c file exists. For example: when make is looking for a way to create $(OBJDIR)/foo.o, it will look for $(OBJDIR)/foo.c.
In your case this file does not exists, so the rule is ignored.
What you want is rather something like this:
$(OBJS): $(OBJDIR)/%.o: $(SOURCEDIR)/%.c
mkdir -p $(dir $#)
$(CP) $< $#
The first rule for $(OBJS) you tried, states that every object file individually depends on all source files. Surely that's not correct.
Your second attempt is better, although the recipe is weird. Fix that and use VPATH to make make find the sources.

Resources