make, write a rule for single file - makefile

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.

Related

make pattern to automatically generate dependencies

I want to allow pattern rules to generate the correct header dependencies for me. I've attempted do this by, but it's failing
For example, if I have files foo.cpp, foo.h, bar.cpp, bar.h and foo.h includes bar.h. with Makefile:
foo_H=foo.h $(bar_H)
bar_H=bar.h
%.o: %.cpp $(%_H)
$(CPP) $(CPPFLAGS) $< -o $#
but make will not update when foo.h or bar.h is changed.
why does this fail and how can it be fixed?
If you really want to do that you can use secondary expansion for it:
foo_H = foo.h $(bar_H)
bar_H = bar.h
.SECONDEXPANSION:
%.o: %.cpp $$($$*_H)
$(CPP) $(CPPFLAGS) $< -o $#
That's not the way gnu make works.
the variable bar_H is undefined when assigning foo_H. So foo_H will just have the value foo.h.
the pattern expansion will not work inside $(...). It just will look up the variable %_H which does not exists, i.e. is empty.
%< and %# is wrong. You probably intended to write $< and $#.
You makefile needs at least one non target. A patterned rule is not sufficient.
A patterned rule will not be used unless all dependencies exist. This might not be intended here.
Your patterned rule will not apply because it searches for a foo.c rather than foo.cpp.
The intended behavior is achieved by
foo.o : foo.h bar.h
bar.o : bar.h
%.o: %.cpp
$(CPP) $(CPPFLAGS) $< -o $#
Note that the dependencies are specified separately from the executable commands.
Another note: if you want to get rid of the include dependency hell you might want to have a look at cmake.
$(%_H) could not expand because as stated in
https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html
Note that expansion using ‘%’ in pattern rules occurs after any variable or function expansions, which take place when the makefile is read
so it seems like using patterns to achieve this kind of logic is a dead end
As an alternative, I used foreach and include as follows:
makedep.mk
$(CUR_OBJ): $(CUR_OBJ:.o=.cpp) $($(CUR_OBJ:.o=_H))
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $< -o $#
Makefile
foo_H=foo.h $(bar_H)
bar_H=bar.h
SRCS=foo.cpp bar.cpp
OBJS=$(SRCS:.cpp=.o)
$(foreach obj,$(OBJS),$(eval CUR_OBJ:=$(obj)) $(eval include makedep.mk))
since there are only make variables and no pattern matching % everything can expand properly

How can I make a Makefile file target depend on a different path?

I apologize for the ambiguous title, I couldn't think of a simple way to phrase it due to my lack of knowledge in GNU make.
I'm writing a simple Makefile for a small project, and I'm trying to enable it to generate individual objects by using their base name (without path) as the target:
$(BASE_OBJS) : %.o : $(SRC_DIR)/%.c $(OBJDIR) $(INCLUDES)
#echo $(CC): [$(notdir $<)] '->' [$(notdir $#)]
#$(CC) -c $< $(CFLAGS) -o $(OBJDIR)/$#
The problem is that the 'make' app obviously expects the target object to be present in the current folder, but it's actually found in the $(OBJDIR) subfolder. The causes those targets to unnecessarily rebuild.
Alternatively, this rule does check for the object's existence in the right place:
$(OBJS) : $(OBJDIR)/%.o: $(SRC_DIR)/%.c $(INCLUDES)
#echo $(CC): [$(notdir $<)] '->' [$(notdir $#)]
#$(CC) -c $< $(CFLAGS) -o $#
But it can't be used for running things like 'make main.o', as $(OBJS) includes the full path of the objects, so it only allows things like 'make output/main.o'.
If it's a duplicate then I'm sorry, I was looking for a while and couldn't find a similar question.
For reference, these are the variable definitions:
BASE_SRC=$(notdir $(SOURCES))
BASE_OBJS = $(BASE_SRC:%.c=%.o)
OBJS = $(BASE_OBJS:%.o=$(OBJDIR)/%.o)
Your main set of targets and prerequisites must use the full path, because that's how make works. So you must have something like:
$(OBJS) : $(OBJDIR)/%.o: $(SRC_DIR)/%.c $(INCLUDES)
#echo $(CC): [$(notdir $<)] '->' [$(notdir $#)]
#$(CC) -c $< $(CFLAGS) -o $#
Now if in addition you want to be able to run a simple make foo.o, then to do that you should define extra "alias" targets for the real targets. These rules only exist for the short-hand, they don't actually do anything. Something like:
$(BASE_OBJS) : %.o : $(OBJDIR)/%.o

Single make rule for multiple output files in different directories

Lets say I have one directory with c files (.) and I want the object files to end up in two different directories: debug and release. Now I want to make the rule for this. This will end up being something like this:
$(DEBUGDIR)%.o : %.c
$(CC) $(CFLAGS) -c $< -o $#
$(RELEASEDIR)%.o : %.c
$(CC) $(CFLAGS) -c $< -o $#
These are two rules which are exactly the same. Since all possible differences between those rules are contained in CFLAGS there is no reason to even have two rules: I want to maintain only one. I tried this:
$(DEBUGDIR)%.o $(RELEASEDIR)%.o : %.c
$(CC) $(CFLAGS) -c $< -o $#
But now it will not compile the o-files for RELEASE when it already compiled for DEBUG. How can I merge these two rules into one?
You can't do it. Pattern rules with multiple targets define a recipe that creates multiple output files when run one time.
For this I'd just write the rule twice. Alternatively you can put the recipe into a variable and use it twice:
COMPILE = $(CC) $(CFLAGS) -c $< -o $#
$(DEBUGDIR)%.o : %.c
$(COMPILE)
$(RELEASEDIR)%.o : %.c
$(COMPILE)

Understanding deeply using a specific case how makefiles are interpreted

I'm trying to understand deeply how makefiles work.
For example, I've the following one:
CC = gcc
CFLAGS = -I.
DEPS = int_array.h
OBJS = int_array.o test_int_array.o
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
clean:
rm -rf *.o test_int_array *.dSYM
The part that I really don't understand fully is :
...
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
...
I know that the option -c basically indicates just to run the preprocessor, compiling and assembling steps (i.e. without producing executables, I guess).
-o means to write the output to the specified file. Which file in this case?
I understood that $# (and $^ for right) is apparently referring to a "left" side, but which one? Is it referring, in the first case, to the left side of :, that is %.o?
What does $< mean?
Could you please explain step by step how the make tool would interpret those two statements?
I think I understood this part more or less:
...
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
...
which should mean produce an executable called "test_int_array" (which basically is indicated by these options -o $# from the $(OBJS) files on the right (stated using the option $^).
Is $(CFLAGS) needed in both cases? Does the order matter?
In the example:
test_int_array: $(OBJS)
$(CC) -o $# $^ $(CFLAGS)
$# is the filename of the target for this rule: test_int_array.
$^ is the names of all prerequisites.
This would be whatever is contained in OBJS, so: int_array.o test_int_array.o
In the example:
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
$< is the name of the first prerequisite: %.c
$# is the filename of the target for this rule: %.o
$(CFLAGS) is not needed for linking, since it only includes the flag -I. Also the CFLAGS indicates that the flags are used for compiling only, hence C FLAGS.
In a Makefile, each rule follows this format:
resulting_file : source_files
steps to get resulting_file from source_files
What is called respectively lefthand and righthand in a rule is the resulting_file and the source_files.
%.ext : %.ext2
is a pattern rule. It allows your Makefile to automatically create any .ext file it needs if it can find a file at the same path with .ext2.
%.c : %.o
is a pattern rule to obtain your .o files (int_array.o test_int_array.o) from their equivalent .c files (int_array.c test_int_array.c)
This is invoked when you specify that $(OBJS) is needed to build the test_int_array file.
Pattern rules automatically use certain variables, such as $(CFLAGS) so you do not need to manually add it in that rule. You can find a full list of implicitly used variables in pattern rules here: https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC96
You can find out about $#, $< and $^ and similar here: https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC101
$#: the entire lefthand
$<: the first file in the righthand
$^: the entire righthand list of files, space separated.

Difference of two pattern rules and integration on makefile

I'm learning makefile and I'm little bit confused about the use of pattern rule and how to use it:
I have two questions:
difference form of pattern rules
In some examples I saw this form:
.c.o:
$(CC) $(CFLAGS) $< -o $#
Other times I saw this:
%.o: %.c
$(CC) $(CFLAGS) $< -o $#
Is this the same form or there are many differences?
How to integrate the pattern rule in my makefile
I have a makefile like this:
.PHONY: all brsserver brsclient clean
CC = gcc
CFLAGS = -Wall -pedantic -g -lpthread
# source files for server
SOURCES_SERV = brsserver.c func_client_serv.c comsock.c bris.c users.c aux_func.c Stack.c
# source files for client
SOURCES_CLI = brsclient.c func_client_serv.c comsock.c bris.c users.c aux_func.c Stack.c
# object file for server
OBJECTS_SERV = $(SOURCES_SERV:.c = .o)
# object file for client
OBJECTS_CLI = $(SOURCES_SERV:.c = .o)
# executable file server
SERV_EXE = brsserver
# executable file client
CLI_EXE = brsclient
I did this:
$(SERV_EXE): $(OBJECTS_SERV)
$(CC) $(CFLAGS) -o $# $^ newDeck.o
$(CLI_EXE): $(OBJECTS_CLI)
$(CC) $(CFLAGS) -o $# $^
But I want to use the pattern rule to do make brsserver and make brsclient from command.
it's enough do this?
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
As you can see, I have to complie only the brsserver including a module called newDeck.o.
The .c.o form is a suffix rule. This form is defined in the POSIX standard for the make program.
The %.o : %.c is a pattern rule. This is a GNU make feature, not part of the POSIX standard (I think there may be a few other make implementations that have something similar).
In this case, they are equivalent. However pattern rules in general are much more flexible than suffix rules; for example you can't represent a pattern rule like this:
foo%.o : bar%.c
as a suffix rule.

Resources