I'd like to generate two output words for each input word, that they be consecutive, and apply patsubst to them.
A non-working prototype of what I want:
$(patsubst %.o,%.a.o %.so.o,$(OBJ))
The second apearance of % is not substituted, and instead a plain % appears.
A working version that does not give the desired order:
$(patsubst %.o,%.a.o,$(OBJ)) $(patsubst %.o,%.so.o,$(OBJ))
Example:
Input:
foo.o bar.o
Desired output:
foo.a.o foo.so.o bar.a.o bar.so.o
How can I get the desired output?
The join make function takes two word lists and concatenate them word by word. Not exactly what you want because there would be no space between foo.a.o and foo.so.o, but not far from it.
Assuming you know for sure that some string will never be part of your file names (e.g. !!!) you can combine substitution references (or the equivalent patsubst), join and subst:
$(subst !!!, ,$(join $(OBJ:o=a.o!!!),$(OBJ:o=so.o)))
Or, even simpler, if you know for sure that .a.o cannot be part of your files' basename:
$(subst .a.o,.a.o ,$(join $(OBJ:o=a.o),$(OBJ:o=so.o)))
Two nested foreach loop could be solve your problem. One for the files and the other one for extensions. The below code should solve your problem.
OBJS = foo.o bar.o
EXTS = a.o so.o
OUT = $(foreach file, ${OBJS}, \
$(foreach ext, ${EXTS}, \
$(patsubst %.o, %.${ext}, ${file})))
Related
I'm trying to write a rule that would replace a set of .c files with .o files for a variable.
To make sure it works, I'm echoing their values.
the .c files are obtained from the current working directory via a shell wildcard
sources := *.c
However, nothing gets printed out for the .o files, as 'sources' doesn't seem to get expanded for this, whether I do with using patsubst or the handier $(src:%.c=%.o).
On the other hand, if I set the value of 'manually', everything works as expected, e.g.
sources := source1.c source2.c source3.c
The makefile:
sources := *.c
srcs = one.c two.c
objects := $(sources:.c=.o)
objs := $(patsubst %.c, %.o, $(srcs))
prints:
#echo sources
#echo $(sources)
#echo objects
#echo $(objects)
#echo $(objs)
Output:
sources
source1.c source2.c source3.c source4.c
objects
*.o
one.o two.o
As you can see, 'objects' (based on the wildcard-using 'sources') is a no-go, but 'objs' (based on the manally-set 'srcs' works as expected).
What am I missing. I know it must have to do with when or how the expansion takes place.
Make is not the shell. This line:
sources := *.c
sets the make variable sources to the literal string *.c. Then this line:
objects := $(sources:.c=.o)
sets objects to the literal string *.o.
Then this line:
#echo $(sources)
Sends echo *.c to the shell, and the SHELL expands the *.c to the list of files that match that glob.
Then this line:
#echo $(objects)
sends echo *.o to the shell, and since there are no files that match the *.o glob, it just prints the glob itself *.o.
If you want to get a list of files in make you have to use the wildcard function:
sources := $(wildcard *.c)
Also, you have fallen prey to two different common errors people make when they are trying to debug makefiles:
First, you should never, EVER use # in your recipe lines to hide the commands. This is like trying to debug your makefile with a blindfold on. Seeing what make is sending to the shell gives you absolutely vital information as to what is happening here. I personally don't use # even after my makefile is working, except for some trivial operations, and I definitely never use it while trying to debug.
Second, if you want to see the contents of make variables in recipes you should always use single quotes around them. If you leave them unquoted or use double quotes, then the shell will come along and mess with those values (depending on what the values are) and you won't be able to see what they really are. Either use '' around them or else use a make function like $(info ...) to see their value rather than a shell program like echo.
If you had written your test makefile like this:
prints:
echo sources
echo '$(sources)'
echo objects
echo '$(objects)'
echo '$(objs)'
it would have been more immediately obvious what the problem was.
I want to construct my linker flags LDFLAGS from a list of libraries with their full paths. Here's where/why I'm stuck. (The library names are Linux style, but that shouldn't really matter for how to solve this, I think.)
FULL_LIBS = \
./path1/libone.a \
../../path2/libtwo.a
# etc.
LIB_DIRS = $(dir $(FULL_LIBS))
LIB_NAMES = $(basename $(notdir $(FULL_LIBS)))
LIB_NAMES_TRIMMED = # zzz trim leading "lib" somehow??? This is what I don't know how to do, or at least the best way
LDFLAGS += \
$(addprefix -L, $(LIB_DIRS)) \
$(addprefix -l, $(LIB_NAMES_TRIMMED))
The desired result, if it's not obvious, should be like
LDFLAGS += -L./path1 -L../../path2 -lone -ltwo
Not sure if I NEED regular expressions (or sed/awk/grep), so I'll withhold that tag (regex) for now.
You can use the text processing capabilities of make (https://www.gnu.org/software/make/manual/html_node/Text-Functions.html#Text-Functions) :
LIB_NAMES_TRIMMED = $(subst lib,,$(LIB_NAMES))
Although this could fail if the string "lib" appears elsewhere in the library names. To avoid that we can use 2 steps:
LIB_NAMES_TRIMMED = $(basename $(notdir $(subst /lib,/,$(FULL_LIBS))))
As explained by Matt, it's even simpler with patsubst:
LIB_NAMES_TRIMMED = $(patsubst lib%,%,$(LIB_NAMES))
I would like a way to take the argument to a call invocation in a Makefile rule and pass that to a builtin function, in this case wildcard.
This doesn't seem to work:
MODULE_OBJS = $(patsubst %.cc, %.o, $(wildcard $(1)/*.cc))
lib%.a: $(call MODULE_OBJS, %)
#echo $# : $^
In this case I would expect make libfoo.a to print a list of .o files corresponding to the .cc files found under foo/, but nothing is printed. The parameter is getting there because if I append $(1) to the end of MODULE_OBJS the value of % gets printed, but it seems to be lost when getting passed into wildcard.
You need to understand that make will execute $(call MODULE_OBJS, %) before it has even begun building the dependency tree, you cannot accomplish this with a pattern rule. You could use eval hackery but there's a case to made against trying to be too clever with make.
Something like the following is easy enough to maintain
MODULE_OBJS = $(patsubst %.cc, %.o, $(wildcard $(1)/*.cc))
libfoo.a: $(call MODULE_OBJS, foo)
lib%.a:
#echo $#: $^
but after wrestling with clever ways of generating library and binary dependencies I prefer simply listing them explicitly.
I got what I wanted with some hacking of the eval rule:
EXCLUDE_MODULES = obj
MODULES = $(filter-out $(EXCLUDE_MODULES), $(patsubst %/, %, $(wildcard */)))
define MODULE_RULE
lib$(MODULE).a: $(patsubst %.cc, obj/%.o, $(wildcard $(MODULE)/*.cc))
#echo $# : $^
endef
$(foreach MODULE, $(MODULES), $(eval $(MODULE_RULE)))
This allows you to call make libfoo.a and get out a list of all the .o's corresponding with the .cc's in that subdirectory.
For those curious, I uploaded a complete example here.
The Metaprogramming Make articles were a useful resource here.
I'm trying to write a rule for make that effectively does "In order to make any <dir>/out, append all <dir>/<num>/source, making them if necessary". In other words, I need to expand a list of all directories <dir>/<num>/, and add source to each, placing that as the prerequisite.
My attempt is
%/out : $(addsuffix source, $(wildcard %/*/))
cat $^ > $#
But the $(wildcard %/*/) doesn't expand. % does not appear to be defined the way I would like at that point (it's a literal %) -- how can I fix this?
I have no a priori knowledge of what directories this will be run on, or how many <num> subdirectories it will find.
If you have a list of directories that can contain out files, you can generate a separate rule for each of them.
You could hard-code such a list, or generate it.
dirs = $(patsubst %/1, %, $(shell find -type d -name 1))
$(foreach %, $(dirs), $(eval $%/out: $(wildcard $%/*/source) ; cat $$^ > $$#))
I don't recommend using secondary expansion because it also would change the semantics of all other rules.
I'm having trouble getting path substitution working correctly. I have a bunch of source files in SOURCES:
#echo $(SOURCES)
foo.c bar.cpp bah.cxx
And I want a list of object files:
# Imaginary only because nothing works
#echo $(OBJECTS)
foo.o bar.o bah.o
I'm trying to build the list of OBJECTS with patsubst. First, this produces a list of source files and object files. Besides being wrong, it causes a duplicate of _main which fails a link.
OBJECTS = $(patsubst %.c, %.o, ${SOURCES}) $(patsubst %.cc, %.o, ${SOURCES}) \
$(patsubst %.cpp, %.o, ${SOURCES}) $(patsubst %.cxx, %.o, ${SOURCES})
Second, this performs no substitutions. Not only is it wrong, I get back the original list in SOURCES.
OBJECTS = $(patsubst %.c %.cc %.cpp %.cxx, %.o, ${SOURCES})
Third, this produces the original list of source files:
OBJECTS = $(patsubst %.*, %.o, ${SOURCES})
I also tried using the following, which seems to multiply the files like rabbits:
OBJECTS = $(SOURCES:.c=.o) $(SOURCES:.cc=.o) \
$(SOURCES:.cpp=.o) $(SOURCES:.cxx=.o)
How does one perform a simple substitution of extensions when using a portable make?
Tom's answer is correct. Etan's will work too. A shorter solution would be:
$(addsuffix .o,$(basename $(SOURCES))
If you have a filter-like function you can use that. Otherwise you can do it in stages:
SOURCES := foo.c bar.cpp bah.cxx
O := $(SOURCES)
$(info $(O))
O := $(patsubst %.c,%.o,$(O))
$(info $(O))
O := $(patsubst %.cpp,%.o,$(O))
$(info $(O))
O := $(patsubst %.cxx,%.o,$(O))
$(info $(O))
The problem with your first (and third since that is effectively identical) attempt is that patsubst leaves untouched any words in the input that do not match the pattern. So when you built OBJECTS up from multiple calls to patsubst you were duplicating (in each piece) all the SOURCSE entries that didn't match that pattern.
The problem with the second is that patsubst doesn't take multiple patterns so nothing matches that erroneous pattern and so you get SOURCES back entirely unmodified.
First, I don't think patsubst is portable. It is a GNU make feature.
I think one answer to your question is nested subsitutions, like:
$(patsubst %c,%.o,$(patsubst %.cc,%.o,$(patsubst .....)))