Same rule for different directory in makefile - makefile

I am having rule like this.
$(OBJDIR)/%.s: %.c
$(CC) $(PPE-CFLAGS) $(DEFS) -S -o $# $<
i have a list like
dirs := $(OBJDIR) $(COMOBJDIR)
So, instead of writing duplicate code for each dir, can I make them into one? Something like iteration on demand?

You have hit one of the weak spots in Make: its inability to handle multiple wildcards at once. There is a way, but it's ugly.
First take your rule:
$(OBJDIR)/%.s: %.c
$(CC) $(PPE-CFLAGS) $(DEFS) -S -o $# $<
and put it into a variable, escaping the '$' symbols and replacing $(OBJDIR) with $(1):
define myrule
$(1)/%.s: %.c
$$(CC) $$(PPE-CFLAGS) $$(DEFS) -S -o $$# $$<
endef
Then you can call it using call and invoke it using eval:
$(eval $(call myrule, $(OBJDIR))
That's good enough for OBJDIR, but to do the same for a list of directories, use foreach:
$(foreach dir, $(OBJDIR) $(COMOBJDIR), $(eval $(call myrule, $(dir))))
Or just use your variable:
dirs := $(OBJDIR) $(COMOBJDIR)
$(foreach dir, $(dirs), $(eval $(call myrule, $(dir))))
Ugly, but effective.

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 - prereq-patterns % in $(wildcard)

I want to add rules of .cc files to a static mode rule. And I try to use $(wildcard ) to enable the prereq-pattern which exists in folder in order to avoid a No rule to make target ... error. But % in $(wildcard ) isn't transformed to the file basename. $(wildcard %.cpp) and $(wildcard %.cc) turn to be nothing.
I want to know how to solve this and make .cc, .cpp in one static mode rule.
# before
# CXX_SOURCE_FILE = $(wildcard *.cpp)
CXX_SOURCE_FILE = $(wildcard *.cpp) $(wildcard *.cc)
C++ = g++
CXX_FLAGS = -g -Wall
c++ : $(basename $(CXX_SOURCE_FILE))
# before
# $(basename $(CXX_SOURCE_FILE)) : % : %.cpp
# $(C++) $< -o $# $(CXX_FLAGS)
$(basename $(CXX_SOURCE_FILE)) : % : $(wildcard %.cpp) $(wildcard %.cc)
$(C++) $< -o $# $(CXX_FLAGS)
You cannot use wildcard like this because it will be evaluated during the parsing, before static pattern rules are considered. Unless you have source files that are literally %.cpp or %.cc your prerequisite list will be empty when the time comes to consider the rules.
A simple solution consists in separating your two sets of source files (CPP_SOURCE_FILE and CC_SOURCE_FILE) and use two different static pattern rules:
CPP_SOURCE_FILE = $(wildcard *.cpp)
CC_SOURCE_FILE = $(wildcard *.cc)
$(basename $(CPP_SOURCE_FILE)): %: %.cpp
$(C++) $< -o $# $(CXX_FLAGS)
$(basename $(CC_SOURCE_FILE)): %: %.cc
$(C++) $< -o $# $(CXX_FLAGS)
There are other solutions but they are more complicated. If you use GNU make you can either use the foreach-eval-call construct or the secondary expansion.
Example with foreach-eval-call:
# $1: executable
define MY_rule
$1: $$(wildcard $1.cpp) $$(wildcard $1.cc)
$$(C++) $$< -o $$# $$(CXX_FLAGS)
endef
$(foreach e,$(basename $(CXX_SOURCE_FILE)),$(eval $(call MY_rule,$e)))
For executable foo this will call MY_rule with parameter foo, pass the result to eval that will expand it and instantiate it as a new rule. $(call MY_rule,foo) expands as:
foo: $$(wildcard foo.cpp) $$(wildcard foo.cc)
$$(C++) $$< -o $$# $$(CXX_FLAGS)
eval expands it as:
foo: $(wildcard foo.cpp) $(wildcard foo.cc)
$(C++) $< -o $# $(CXX_FLAGS)
This is exactly what you wanted for this executable. Note the need of $$ to escape the first expansion by eval.
Example with secondary expansion:
.SECONDEXPANSION:
$(basename $(CXX_SOURCE_FILE)): $$(wildcard $$#.cpp) $$(wildcard $$#.cc)
$(C++) $< -o $# $(CXX_FLAGS)
After the first expansion, during the parsing of the Makefile, this becomes:
foo bar baz: $(wildcard $#.cpp) $(wildcard $#.cc)
$(C++) $< -o $# $(CXX_FLAGS)
Note that if you were trying to use this rule in your Makefile, instead of your static pattern rule, this would not work for the very same reason: when the Makefile is parsed and the prerequisites are expanded the automatic variables are not yet set. So, unless you have files named .cpp or .cc your liste of prerequisites would also be empty.
But every rule after .SECONDEXPANSION: has its prerequisites expanded a second time. And the second time, different from the first, the automatic variables are set, including $#. The final result is equivalent to the 3 following rules:
foo: $(wildcard foo.cpp) $(wildcard foo.cc)
$(C++) $< -o $# $(CXX_FLAGS)
bar: $(wildcard bar.cpp) $(wildcard bar.cc)
$(C++) $< -o $# $(CXX_FLAGS)
baz: $(wildcard baz.cpp) $(wildcard baz.cc)
$(C++) $< -o $# $(CXX_FLAGS)
From the GNU make manual:
the true power of this feature only becomes apparent when you discover that secondary expansions always take place within the scope of the automatic variables for that target. This means that you can use variables such as $#, $*, etc. during the second expansion and they will have their expected values, just as in the recipe. All you have to do is defer the expansion by escaping the $.
Note: here again the $$ are essential to escape the first expansion.

Add rule to generate specific headers if missing

I have a Makefile that mixes Java and C++ with JNI and I would like to generate the JNI header automatically when needed.
Currently, I have the following:
$(OBJDIR)/org_some_package_%.cpp: $(INCDIR)/jni/org_some_package_%.h
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
#mkdir -p $(OBJDIR)
$(CC) -c -o $# $(CFLAGS) \
-I$(INCDIR) -I../build/include -I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/linux" \
-MD -MF $(patsubst %.o, %.d, $#) $<
.SECONDEXPANSION:
$(INCDIR)/jni/%.h: $(JAVA_TEST_BIN)/$$(subst _,/,%).class
#mkdir -p $(INCDIR)/jni
$(JAVAH) -d inc/jni -classpath TestJNI/bin/tests:$(JUNIT_JAR):$(HAMCREST_JAR) $(basename $(subst _,.,$(subst $(INCDIR)/jni/,,$#)))
The problem is that when a .o file is needed, the first rule is never applied:
$(OBJDIR)/org_some_package_%.cpp: $(INCDIR)/jni/org_some_package_%.h
If I replace this rule with a specific one (by replacing % by the name of a class), it works.
How can I make this generic rule work?
I don't want to do this:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(INCDIR)/jni/%.h
...because I may have .cpp files that do not correspond to JNI header.
You cannot create simple prerequisites using patterns. A pattern rule without any recipe doesn't define a prerequisite, it cancels a previously-existing pattern rule. The GNU make manual says:
You can cancel a built-in implicit rule by defining a pattern rule with the same target and prerequisites, but no recipe.
The only way to create a prerequisite is to make it explicit.
So, your $(INCDIR)/jni/a_b_c.h depend on $(JAVA_TEST_BIN)/a/b/c.class? You will have to use advanced make features. I assume that all *.class file under $(JAVA_TEST_BIN) correspond to a built header file. This (not tested) should do what you show in your question:
CLASSES := $(patsubst $(JAVA_TEST_BIN)/%.class,%,$(shell find $(JAVA_TEST_BIN) -type f -name '*.class'))
BUILT_HEADERS :=
# $(1): class
define BUILD_HEADER_rule
header := $$(INCDIR)/jni/$$(subst /,_,$(1)).h
$$(header): $$(JAVA_TEST_BIN)/$(1).class
BUILT_HEADERS += $$(header)
endef
$(foreach c,$(CLASSES),$(eval $(call BUILD_HEADER_rule,$(c))))
$(BUILT_HEADERS):
#mkdir -p $(dir $#)
$(JAVAH) -d inc/jni -classpath TestJNI/bin/tests:$(JUNIT_JAR):$(HAMCREST_JAR) $(basename $(subst _,.,$(subst $(INCDIR)/jni/,,$#)))

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

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?

In creating a makefile with subdirectories in windows, % wildcard stops working

This is in reference to the second response here:
How to generate a Makefile with source in sub-directories using just one makefile
The solution works great for me except for when the make rules are called. They never seem to make any once make-goal is called since the files don't exist in the build directory yet. I tested this by creating empty files in the build directory (just anyting.o) and the make rule is then found
my conclusion is that the % wildcard character is only looking for what is in the directory, and can't find the file so it doesnt make a build rule for it, and thus fails to continue. There are two possible solutions:
1) Find a way to make dummy object files that are overwritten when the compiler actually starts
2) Make make "realize" that the wild card is for anything put into the make-goal function, not what is already in the directory
any pointers?
As far as I know, I am the first one to have this issue
\
MODULES := calibration calibration/settings camera/nikon camera ommon
SRC_DIR := $(addprefix src/, $(MODULES)) src
SDK_INCLUDES := include $(addprefix include/, $(MODULES))
BUILD_DIR := build $(addprefix build/, $(MODULES))
SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.cpp))
OBJ := $(patsubst src/%.cpp,build/%.o, $(SRC))
# OpenCV directories, change according to your own installation
CV_INCLUDE_DIR = C:\Users\a0225122\Downloads\opencv\build\include
CV_LIB_DIR = C:\Users\a0225122\Downloads\opencv\bin\lib
CV_LIBS = -llibopencv_core249 \
-llibopencv_highgui249 \
-llibopencv_imgproc249 \
-llibopencv_features2d249 \
-llibopencv_calib3d249
CV_FLAGS = -I$(CV_INCLUDE_DIR) -L$(CV_LIB_DIR) $(CV_LIBS)
HID_API_INCLUDE_DIR := 3rd_party/hidapi-master/hidapi/hid.h
# Compiler instructions
CXXFLAGS = -std=c++11 -Wall -I $(SDK_INCLUDE_DIR) -I $(CV_INCLUDE_DIR) -I $(HID_API_INCLUDE_DIR) -L $(CV_LIB_DIR) $(CV_LIBS) -L $(FLYCAP_LIB_DIR) $(FLYCAP_LIBS)
# Clean up instructions
ifdef SystemRoot #This is windows
CXX = mingw32-g++
RM = del /Q
FixPath = $(subst /,\,$1)
BUILD_DIR := $(call FixPath, $(BUILD_DIR))
SRC_DIR := $(call FixPath, $(SRC_DIR))
SDK_INCLUDES := $(call FixPath, $(SDK_INCLUDES))
SRC := $(call FixPath, $(SRC))
OBJ := $(call FixPath, $(OBJ))
CXXFLAGS := $(call FixPath, $(CV_FLAGS))
define make-goal
$1\%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $$< -o $$#
endef
else #more ifeqs can be added for more OS's but this should be fine
CXX = g++
RM = rm -f
define make-goal
$(1)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $$< -o $$#
endef
endif
vpath %.cpp $(SRC_DIR)
SDK_LIBS = lib_core.a
default: SDK.exe
.PHONY: clean
clean:
$(RM) build *.a
#executable generation
SDK.exe: $(SDK_LIBS)
$(CXX) $(CXXFLAGS) $^ -o $#
lib_core.a: checkdirs $(OBJ)
ar rcs lib_core.a $(OBJ)
checkdirs: $(BUILD_DIR)
$(BUILD_DIR):
mkdir $#
#$(OBJ): $(SRC)
# $(CXX) $(CXXFLAGS) -c $^ -o $#
$(foreach bdir,$(BUILD_DIR),$(eval $(call make-goal,$(bdir))))
Your first problem is that you cannot use backslashes in GNU make rules, except in recipes (make just sends the recipe to the shell, it doesn't interpret the recipe except for $). All GNU make targets, prerequisites, etc. must use forward slashes, all the time, even on Windows.
Almost all Windows applications will accept forward-slashes as directory separators properly. For the few that don't, you can use your function FixPath, but you must use it inside the recipe, not in the target or prerequisite lists.
Once you've resolved that issue if you still have problems, post what you have and we'll look.

Resources