How to exclude a few files in an implicit makefile rule? - makefile

I am building several "main" files and currently have the following implicit rule:
$(PROJECT_ROOT)build/%.bin: $(PROJECT_ROOT)obj/%.o $(DEPS)
#mkdir -p $(dir $#)
#g++ -o $# $^
Now I need to have special linking instructions for some of the "main" files. I defined the exceptions as follows:
SPECIAL_TARGET_1 = $(PROJECT_ROOT)build/...
SPECIAL_TARGET_2 = $(PROJECT_ROOT)build/...
SPECIAL_TARGETS = $(SPECIAL_TARGET_1) $(SPECIAL_TARGET_2)
and tried to filter them out as follows:
$(filter-out $(SPECIAL_TARGETS), $(PROJECT_ROOT)build/%.bin): $(PROJECT_ROOT)obj/%.o $(DEPS)
#mkdir -p $(dir $#)
#g++ -o $# $^
but the filter-out is not filtering anything.
What is the correct way of exluding a few files from an implicit rule?

The filter-out function is used to remove things from a list. But you do not have a list: you only have the single text string $(PROJECT_ROOT)build/%.bin.
If you were to add the new rule:
$(SPECIAL_TARGETS):
#echo TODO I need to write some special linking instructions for $#
then this specific rule will override the generic pattern-matching rule.

Related

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/,,$#)))

No rule to make object files based on pattern

Hello I am trying to build my C++ project. I currently have a makefile that lists out all the names of the .o files I want to make. Then I prefix the directory onto them where I want them to be compiled to. Finally, I have two basic rules that handle building each object file then the executable from those object files. For whatever reason, make is not recognizing the pattern. Here is the makefile
CXX=g++
SRC_DIR=/home/epi/jfrye_xilinx/Cosimulation/SystemC/Xilinx/lib
INC_DIR=-I/home/epi/jfrye_xilinx/Cosimulation/SystemC/Xilinx/include
INC_DIR += -I/home/epi/jfrye_xilinx/SystemC/systemc-2.3.2/include
LIB_DIR=-L/home/epi/jfrye_xilinx/SystemC/system-2.3.2/lib-linux64
LIB_TAGS=-lsystemc
OBJ_DIR=/home/epi/jfrye_xilinx/Cosimulation/Adder_PL/obj
ZYNQ_DEMO=/home/epi/jfrye_xilinx/Cosimulation/Adder_PL/bin/zynq_demo
ZYNQMP_DEMO=/home/epi/jfrye_xilinx/Cosimulation/Adder_PL/bin/zynqmp_demo
OBJS+ = memory.o trace.o debugdev.o demo-dma.o xilinx-zynq.o xilinx-zynqmp.o
OBJS += safeio.o remote-port-proto.o remote-port-sk.o remote-port-tlm.o
OBJS += remote-port-tlm-memory-master.o remote-port-tlm-memory-slave.o
OBJS += remote-port-tlm-wires.o
_ZYNQ_OBJS=zynq_demo.o
_ZYNQMP_OBJS=zynqmp_demo.o
_ZYNQ_OBJS += $(OBJS)
_ZYNQMP_OBJS += $(OBJS)
ZYNQ_OBJS=$(addprefix $(OBJ_DIR)/, $(_ZYNQ_OBJS))
ZYNPMP_OBJS=$(addprefix $(OBJDIR)/, $(_ZYNQMP_OBJS))
$(info $(ZYNQ_OBJS))
all: $(ZYNQ_DEMO) $(ZYNQMP_DEMO)
$(ZYNQ_DEMO): $(ZYNQ_OBJS)
$(ZYNQMP_DEMO): $(ZYNQMP_OBJS)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cc
$(CXX) $(INC_DIR) $(LIB_DIR) $(LIB_TAGS) -c -o $# $<
I am getting the error:
make: *** No rule to make target
/home/epi/jfrye_xilinx/Cosimulation/Adder_PL/obj/zynq_demo.o', needed
by/home/epi/jfrye_xilinx/Cosimulation/Adder_PL/bin/zynq_demo'.
Stop.
The fourth rule should take care of zynq_demo.o correct. Why is it not recognizing a rule it can use to build that object file?
I'm not a fan of pattern rules.
When and where they apply is a little haphazard for my tastes.
A better alternative IMHO is static pattern rules.
To use these simply prefix your pattern rules with the targets that those patterns apply to.
So
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cc
$(CXX) $(INC_DIR) $(LIB_DIR) $(LIB_TAGS) -c -o $# $<
simply becomes
${ZYNC_OBJS}: $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cc
$(CXX) $(INC_DIR) $(LIB_DIR) $(LIB_TAGS) -c -o $# $<
I can't tell because I don't have your source tree,
but I suspect make will now give you a different error.
Something about /home/epi/jfrye_xilinx/Cosimulation/SystemC/Xilinx/lib/zynq_demo.cc being missing maybe (???).

Makefile - generic target rule with src- and obj-files in nested directories

I have code sorted in nested directories like
src/cmn/abc.cpp
src/voc/xyz.cpp
And desired object output should be
obj/cmn/abc.o
obj/voc/xyz.o
The Makefile entries are
SRC_FILES := src/cmn/abc.cpp src/voc/xyz.cpp
OBJ_FILES := $(patsubst %.cpp,*.o,$(patsubst src/%,obj%,$SRC_FILES))
The generic target rule is simple (too simple) and not working as desired. It creates the obj-files right next to the src-files as it misses pattern substitution. Further it misses directory creation (like obj/voc).
.cpp.o:
#$(CC) $(CC_FLAGS) $< -o $#
How should a target be defined to achieve the desired goals from above?
Since you're using GNU make already (patsubst) you might as well use pattern rules which are much more powerful than suffix rules:
obj/%.o : src/%.c
#mkdir -p $(#D)
$(CC) $(CC_FLAGS) -c $< -o $#

make, write a rule for single file

I need a file to have a dedicated rule for use special flags.
Now I use
$(OBJDIR)/%.$(OE): special_file.c
$(ECHO) "Compiling file $< => $#"
$(CC) $(CFLAGS) $(CFLAGS_SPECIAL) $(DEFINES) $(INCLUDE) $< -o $#
$(OBJDIR)/%.$(OE): %.c $(OBJDIR)
$(ECHO) "Compiling file $< => $#"
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDE) $< -o $#
But isn't working for special_file.c. It seems the path is not known, but when I comment my special rule and let make all files, file is compiling fine.
How to divert make to a rule just for one file?
Thanks very much in advance,
You should use Target-specific Variable Values:
$(OBJDIR)/special_file.$(OE): CFLAGS += --specific_flags
$(OBJDIR)/special_file.$(OE): special_file.c
$(OBJDIR)/%.$(OE): %.c $(OBJDIR)
$(ECHO) "Compiling file $< => $#"
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDE) $< -o $#
If you want to do it this way, you'll have to write it as a static rule:
$(OBJDIR)/special_file.$(OE): special_file.c
$(ECHO) "Compiling file $< => $#"
$(CC) $(CFLAGS) $(CFLAGS_SPECIAL) $(DEFINES) $(INCLUDE) $< -o $#
However, much simpler and more flexible is to use recursive variable naming. Do something like this:
special_file_FLAGS = $(CFLAGS_SPECIAL)
$(OBJDIR)/%.$(OE): %.c
$(ECHO) "Compiling file $< => $#"
$(CC) $(CFLAGS) $($*_FLAGS) $(DEFINES) $(INCLUDE) $< -o $#
The automatic variable $* expands to the stem (the part that matches %). Now when you build anything other than special_file.c, say other_file.c, make will expand $(other_file_FLAGS) which is empty. When you build special_file.c, make will expand $(special_file_FLAGS).
BTW, you should (almost) never list a directory as a prerequisite of a target. Search for other answers to find out why not and the right way to ensure the target directory is created.
ETA:
Target-specific variables are definitely a cool feature. I tend to not use them, though. Why? Because I prefer to separate my data from my rules.
If you use target-specific variables, you are mixing together the rule syntax (the target) with the data syntax (the variable assignment). Using the recursive variable name method, I keep the rule syntax and the data assignment separate. What if I decide I need to change my pattern rule so that the target name changes? With target-specific variables I have to go through all my files and change the target names. With recursive variable naming, I just change the pattern rule and it Just Works.
In my build environments I typically have makefiles containing only data (variable assignments), plus an include of a common makefile that declares all my rules. Avoiding the need to leak target formatting syntax all over my general data-driven makefiles, escaping from my uber-magical common rule definitions, keeps me from doing much with target-specific variables.

Passing target name to a dependency in makefile

If I have the following rule in a makefile:
$(OBJ)/%.o: $(SRC)/%.c
$(CC) -c -o $# $< $(CFLAGS)
Every file matching the prefix ./obj/ and sufix .o will have its stem passed to %, so I can provide some dependencies based on its name.
But, suppose I have this kind of rule, which I specify one by one the targets I want:
OBJECTS=abc.o bca.o cba.o
$(OBJECTS): $(SRC)/%.c
$(CC) -c -o $# $< $(CFLAGS)
How do I make the % stem actually work for the current target name make is executing? Just using % doesn't work, neither $#.
Note that I'm trying to write the actual target name to its own dependency. For example, when make is executing the rule for abc.o, it would include $(SRC)/abc.c and just it (something like $(patsubst %.o, $(SRC)/%.c, MAGIC_TARGET_NAME_VARIABLE)).
You can just replace this rule:
$(OBJECTS): $(SRC)/%.c
with:
$(OBJECTS) : %.o : $(SRC)/%.c
You will need to add the $(OBJ) to the -o part of the recipe if you still want them built there:
$(OBJECTS) : %.o : $(SRC)/%.c
$(CC) -c -o $(OBJ)/$# $< $(CFLAGS)
I’m not completely clear on what you’re asking, but I think this accomplishes what you’re trying to do:
OBJECTS=abc.o bca.o cba.o
.PHONY: all
all: $(OBJECTS:%=obj/%)
$(OBJ)/%.o: $(SRC)/%.c
echo $(CC) -c -o $# $< $(CFLAGS)
All .o files are built; each .o file is built using only the .c file corresponding to it; and if you want to refer to the list of all object files or source files in the command for compiling a .o file, then you can reference ${OBJECTS} directly.
If this isn’t what you’re trying to do, you’ll be able to get a better answer by listing the input files you have, the output files you want to make, the input dependencies of each output file, and what compilation command you want to execute for each output file.

Resources