patsubst and dir usage - makefile

I am trying to figure out what the following two lines in a .mk file mean
include $(ROOTDIRECT)/target/$(MYSUBDIR)/defs.mk
include $(ROOTDIRECT)/target/$(dir $(patsubst %/,%,$(MYSUBDIR)))/defs.mk
For clarity let ROOTDIRECT be "/home/me" and MYSUBDIR be "platform"
The first line I guess is straight forward and includes "/home/me/target/platform/defs.mk"
The second line I dont understand and my guess from my environment is that it includes "/home/me/target/defs.mk"
Am I right/wrong and could could someone help me to understand the second line

$(patsubst %/,%,$(MYSUBDIR)) will substitute anything matching the pattern %/ by %, where % can be anything.
In other words, it will remove the trailing / of $(MYSUBDIR).
See GNU Make Manual 8.2 Functions for String Substitution and Analysis

Related

Extracting part of a match in a makefile rule

I have a makefile which generates a bunch of versions of an image in different places:
website/img/logo_256.png
website/img/logo_152.png
/tmp/logo_64.png
and so on (the /tmp/ generation is so I can later use those files to later generate a multiresolution .ico, the details of that aren't important).
I'd like a rule of the form
logo_%.png: ${SRC}
convert $^ -thumbnail $*x$* $#
but, $* brings in the matched directory too, so I get a command of the form:
convert logo_1024.png -thumbnail /tmp/64x/tmp/64 /tmp/logo_64.png
which is incorrect (I need 48x48, not /tmp/48x/tmp/48).
Or I can write
/tmp/logo_%.png: ${SRC}
convert $^ -thumbnail $*x$* $#
website/img/logo_%.png: ${SRC}
convert $^ -thumbnail $*x$* $#
which seems ugly.
I'm sure there are ways to break down and pattern match $# to get what I want, but I'm not a makefile guru, so this would take some research.
What's the easiest way to do this?
See the second half of the Automatic Variables in the GNU Make Manual:
Of the variables listed above, four have values that are single file names, and three have values that are lists of file names. These seven have variants that get just the file's directory name or just the file name within the directory. The variant variables' names are formed by appending ‘D’ or ‘F’, respectively. These variants are semi-obsolete in GNU make since the functions dir and notdir can be used to get a similar effect (see Functions for File Names). Note, however, that the ‘D’ variants all omit the trailing slash which always appears in the output of the dir function. Here is a table of the variants:
‘$(#D)’
The directory part of the file name of the target, with the trailing slash removed. If the value of ‘$#’ is dir/foo.o then ‘$(#D)’ is dir. This value is . if ‘$#’ does not contain a slash.
‘$(#F)’
The file-within-directory part of the file name of the target. If the value of ‘$#’ is dir/foo.o then ‘$(#F)’ is foo.o. ‘$(#F)’ is equivalent to ‘$(notdir $#)’.
‘$(*D)’
‘$(*F)’
The directory part and the file-within-directory part of the stem; dir and foo in this example.
‘$(%D)’
‘$(%F)’
The directory part and the file-within-directory part of the target archive member name. This makes sense only for archive member targets of the form archive(member) and is useful only when member may contain a directory name. (See Archive Members as Targets.)
‘$(<D)’
‘$(<F)’
The directory part and the file-within-directory part of the first prerequisite.
‘$(^D)’
‘$(^F)’
Lists of the directory parts and the file-within-directory parts of all prerequisites.
‘$(+D)’
‘$(+F)’
Lists of the directory parts and the file-within-directory parts of all prerequisites, including multiple instances of duplicated prerequisites.
‘$(?D)’
‘$(?F)’
Lists of the directory parts and the file-within-directory parts of all prerequisites that are newer than the target.
Edit:
As prompted by #Ian's comment I looked again and realized that this was not a complete solution. A complete solution follows.
The above F modifiers (and the $(notdir) function) will strip the path from the target filename. That's part of what is necessary.
Additional manipulation is required to extract only the numerical component from target like /some/path/logo_64.png.
The $(basename) function will strip off suffixes (as will $(patsubst %.png,%,$#) or $(#:%.png=) in a more specific fashion).
Combining those we get from /some/path/logo_64.png to logo_64. Handling things at this point depends heavily on what the data is going to look like and what assertions about it can be made. If logo_ is a static prefix then a simple $(patsubst logo_%,%,...) will work (as will the matching substitution reference like before).
If that is not guaranteed but the guarantee can be made that the dimension will be the last underscore separated component then $(lastword $(subst _, ,...)) can be used.
The rule needed is:
logo_%.png: ${SRC}
convert $^ -thumbnail $(*F)x$(*F) $#
The $(*F), is documented very briefly in the Make manual, as quoted in Etan's answer.
‘$(*F)’ The file-within-directory part of the stem; foo in this example.
The 'stem' ($*) is anything not explicit in the pattern. That includes the wildcard, and any implicit directories. So hence in the question it had the value /tmp/48, /tmp/ from the implicit directory, and 48 from the wildcard in the pattern. So of this combined stem, I need to select just the filename part, $(*F).
Alternatively, noting that the manual states:
These variants are semi-obsolete in GNU make since the functions dir and notdir can be used to get a similar effect
we can instead do:
logo_%.png: ${SRC}
convert $^ -thumbnail $(notdir $*)x$(notdir $*) $#
In a comment, Etan also linked to the How Patterns Match section of the manual, to help understand how the stem is constructed. I found this useful and wanted to bubble it up into an answer.

can't use variable in Makefile

My main Makefile call config.mk
include $(TOPDIR)/config.mk
then config.mk include some sentences like this:
ifdef CPU
sinclude $(TOPDIR)/cpu/$(CPU)/config.mk
endif
ifdef SOC
sinclude $(TOPDIR)/cpu/$(CPU)/$(SOC)/config.mk
endif
I have prepared these two tree and necessary config.mks. But for "SOC", whose value is "versatile", there is a problem. If I put "versatile" directly here, it could find the file and everything is fine; but when I use $(SOC), il will meet an error, and say
/../../../cpu/arm926ejs/versatile: is a folder, stop
Anyone know what the problem is ??
Are you sure you gave the exact error message? What version of make are you using? That error doesn't look like anything GNU make would print.
Anyway, I'll bet the problem is that your assignment of the SOC variable has trailing whitespace. According to the POSIX definition of make, leading whitespace before a variable value is removed, but trailing whitespace is preserved. That means, for example, if you write your makefile like this:
SOC = versatile # this is the versatile SOC
then make will remove the comment, but keep the space, so the value will be 'versatile' (space at the end). This means when the value is expanded in the sinclude line you get:
sinclude $(TOPDIR)/cpu/$(CPU)/versatile /config.mk
which make interprets as trying to include two different values, the first of which is a directory.
Even if you don't have a comment there, any trailing whitespace will be preserved. When editing makefiles you should try to put your editor into a mode where it flags trailing whitespace, or even better removes it automatically. GNU Emacs, for example, can do this.

What does wildcard mean in makefile?

I found the following lines in a makefile tutorial, but I have some problem with the bold lines.
In 1 line, if I write
program_C_SRCS:=$(*.c)
it does not work. So please tell me what is
wildcard word in doing here. Is this word is specific to the makefile only?
In tutorial it is written that second line will perform the test substitution. Can anyone tell me something about this text substitution?
Please excuse me if my questions are very basic because I am new to make filestuff.
link of tutorial
CC:=g++
program_NAME:=myprogram
**program_C_SRCS:=$(wildcard *.c)** # 1 line
program_CXX_SRCS:=$(wildcard *.cc)
**program_C_OBJ:=$(program_C_SRCS:.c=.o)** # 2 line
program_CXX_OBJ:=$(program_CXX_SRCS:.c=.o)
program_OBJ:= $(program_C_OBJ) $(program_CXX_OBJ)
Suppose you have two source files. foo.c and bar.c.
program_C_SRCS:=$(wildcard *.c) # 1 line
The wildcard function is Make syntax. The variable program_C_SRCS will now have the value foo.c bar.c (maybe not in that order).
program_C_OBJ:=$(program_C_SRCS:.c=.o) # 2 line
This is a substitution reference. It transforms text, replacing one substring with another. The variable program_C_OBJ now has the value foo.o bar.o.
The use of wildcard card function in make file is to list all the source files with a particular extension. For example:
program_C_SRCS:=$(*.c) // In this the variable program_C_SRCS will have all the files with ".c" extension.
Suppose if you want to convert .c files to .o files then the following syntax may be useful:
program_C_OBJS:=$(patsubst %.c,%.o,$(wildcard *.c))

What does a percent symbol do in a makefile?

I have a makefile that looks like this :
include $(patsubst %,$(src)/%/Make.tests, $(TEST_SUBDIRS))
%-test:
Something here
I understand what it is intended for in the target rule line. What is the % sign doing in the first line ? Does it have anything to do percent sign in the target rule line ?
When I write make sometarget, are the lines in the makefile that are not written as part of any rule (like the first line in this makefile) executed at all ? If yes, then what is the order of execution ?
As you can read in the GNU make manual, the percent acts as a wildcard. The first argument of the patsubst function forms the pattern. Each item/word in the last argument is compared against this pattern, and if it matches, it is replaced with the second argument. If there is a wildcard symbol (%) in the pattern, this will match any number of characters, and these characters are copied into the replacement string at the place of the % in the second argument.
In your example the pattern is just the wildcard symbol, so it will match any word in the last argument to the function, and this word will be copied into the replacement string (the second argument) at the place of the %.
An example may make things more clear. Let's assume TEST_SUBDIRS contains two names.
TEST_SUBDIRS := test1 test2
include $(patsubst %,$(src)/%/Make.tests, $(TEST_SUBDIRS))
This is then equivalent to the following.
include $(src)/test1/Make.tests $(src)/test2/Make.tests
A makefile is processed sequentially, line by line. Variable assignments are "internalized", and include statements cause the contents of other files to be inserted literally at that location after which that content is processed as part of the makefile.
A dependency graph is formed from the rules as they are being read in, and after the entire file is processed, the necessary recipes are executed to update the requested target.

GNU make: variable for command line arguments

How to pass the entire command line (including goals, link lines, make options etc) from top level make to recursive make:
targets : prerequisites
$(MAKE) $(this should expand to top level command line) additional_args
Thanks.
I think the closest you can get is using a combination of $(MAKE), which contains the exact filename make was invoked with, $(MAKECMDGOALS), which contains the goals you specified on the command line, and $(MAKEFLAGS), which contains any variable definitions and (a subset of) the switches specified on the command line.
The $(MAKE) macro is special and expands to include some relevant options. See the section How the MAKE variable works in the Make documentation for more details. However, this doesn't include the complete line including goals etc, and I'm not sure that is possible.
Usually I try to avoid using Make recursively, there's a good article about that here: Recursive Make Considered Harmful.

Resources