How to reference 2 output files in rule - makefile

So I have the following Makefile snippet:
OUTPUT = f1 f2
$(OUTPUT) : $SOURCES
$(PROCESSOR) -i $SOURCES -o $#
My intention is to name 2 output files: $(PROCESSOR) -i $SOURCES -o f1 f2
, but make interprets it to be 2 separate commands:
$(PROCESSOR) -i $SOURCES -o f1
$(PROCESSOR) -i $SOURCES -o f2
So how can I give 2 outputs here?
Thanks.

IMHO, this calls for a pattern rule with multiple targets, e.g.,
OUTPUT = f1 f2
%1 %2: $(SOURCES)
$(PROCESSOR) -i $(SOURCES) -o $*1 $*2
which, unlike normal rules, will not be translated into two separate rules. Note that the two output file names need to have a common stem for this to work.

Related

Generate a directory if a target name has a directory part

I have this makefile code:
$(DIRS):
#echo " MKDIR build/tmp/base/socket/$#"
$(Q)mkdir -p $#/
%.a.s:
#echo " CC build/tmp/base/socket/$#"
$(Q)$(CC) $(CFLAGS_A) -S $< -o $#
%.so.s:
#echo " CC build/tmp/base/socket/$#"
$(Q)$(CC) $(CFLAGS_SO) -S $< -o $#
%.o: %.s
#echo " AS build/tmp/base/socket/$#"
$(Q)$(AS) $< -o $#
tcp/client.a.s: $(TCP_CLIENT_SRC) $(TCP_CLIENT_INC)
tcp/client.so.s: $(TCP_CLIENT_SRC) $(TCP_CLIENT_INC)
tcp/server.a.s: $(TCP_SERVER_SRC) $(TCP_SERVER_INC)
tcp/server.so.s: $(TCP_SERVER_SRC) $(TCP_SERVER_INC)
I'd like to add a | tcp in the prerequisites of all targets that have a leading tcp/ in their name, but I'd like to be able to do it in one line. I wouldn't want to append that manually to every line that needs it.
I thought of adding this new rule:
tcp/%.s: | tcp
but it isn't doing anything.
I also thought of the more generic, which would be nicer, but same results:
%.s: | $(#D)
How should I write that?
A workaround would be to call mkdir every time (include it in both %.a.s and %.so.s rules), but that would add unnecessary calls to mkdir, wouldn't it?
I am not a fan of pattern rules. They are too arbitrary for my tastes.
(What actually happens depends on what files you may have lying around on your hard disk.)
You cannot just add a prerequisite to a given set of targets using a pattern rule
Well you can if you use static pattern rules. This is a much nicer idiom. Here we prefix a pattern rule with the actual list of sources you want the pattern rule to apply to. This is good where you can describe dependencies using make's noddy pattern matching.
A sketch:
%.a: ; date >$# # Pattern rule
tcp: ; mkdir -p $# # Explicit rule
tcp/a.a: tcp/%.a: | tcp ; # Static pattern rule!
.PHONY: all
all: tcp/a.a
all: c.a
all: dir/b.a
all: ; : $# Success
And we have:
$ make all
mkdir -p tcp
date >tcp/a.a
date >c.a
date >dir/b.a
/bin/sh: dir/b.a: No such file or directory
make: *** [Makefile:3: dir/b.a] Error 1
Here we have told make that before it builds (i.e., "runs the recipe for") tcp/a.a, it must first build tcp. That works. We didn't tell make about the directory for dir/b.a, so that failed. Note that the .a file's recipe is still in an ordinary pattern rule. This is just by way of exposition. I would definitely change this.
Yeah, in this case the pattern rule for tcp/ is over-the-top. Consider though that before you create tcp/a.a, you might first need to create a auto/a.src (say).
tcp/a.a: tcp/%.a: auto/%.src | tcp ; # Static pattern rule!
Easily extensible.
targets := tcp/a.a tcp/b.a tcp/c.a
${targets}: tcp/%.a: auto/%.src | tcp ; # Static pattern rule!
[By the way, in your original makefile, your archive and shared object should depend on the .o files, not the source (???)]
You cannot just add a prerequisite to a given set of targets using a pattern rule. That's not how pattern rules work: they are rules: they must have a recipe associated with them. A pattern rule without a recipe actually deletes that pattern rule (see Canceling Implicit Rules).
You can either create two sets of pattern rules, one for all targets and a second one for just targets that start with tcp/ that have an extra prerequisite, but you have to write the entire pattern rule twice, including a recipe, not just the pattern line.
Or just put the mkdir into the recipe. A mkdir on a directory that already exists won't even be noticeable.
This answer is only to show a working Makefile implementing #bobbogo 's answer.
This Makefile is a leaf of a Makefile tree, so all variables not defined here are exported by upper Makefiles.
Makefile:
#! /usr/bin/make -f
################################################################################
# *AUTHOR*
# FULL NAME "Alejandro Colomar Andrés"
################################################################################
################################################################################
DIRS = \
$(CURDIR)/tcp
OBJ = \
$(CURDIR)/tcp/client.o \
$(CURDIR)/tcp/server.o \
$(CURDIR)/foo.o
SRC = \
$(SRC_DIR)/base/socket/tcp/client.c \
$(SRC_DIR)/base/socket/tcp/server.c \
$(SRC_DIR)/base/socket/foo.c
DEP = $(OBJ:.o=.d)
BOTH_OBJ = $(subst .a.o,.a.o ,$(join $(OBJ:.o=.a.o),$(OBJ:.o=.so.o)))
BOTH_ASM = $(subst .a.s,.a.s ,$(join $(OBJ:.o=.a.s),$(OBJ:.o=.so.s)))
NEEDDIR = $(DEP) $(BOTH_ASM)
################################################################################
PHONY := all
all: $(BOTH_OBJ)
#:
$(DIRS): $(CURDIR)/%:
#echo " MKDIR build/tmp/base/socket/$*"
$(Q)mkdir -p $#
$(NEEDDIR): | $(DIRS)
$(CURDIR)/%.d: $(SRC_DIR)/base/socket/%.c
#echo " CC -M build/tmp/base/socket/$*.d"
$(Q)$(CC) $(CFLAGS_A) -MG -MT"$#" \
-MT"$(CURDIR)/$*.a.s" -MT"$(CURDIR)/$*.so.s" \
-M $< -MF $#
$(CURDIR)/%.a.s: $(SRC_DIR)/base/socket/%.c $(CURDIR)/%.d
#echo " CC build/tmp/base/socket/$*.a.s"
$(Q)$(CC) $(CFLAGS_A) -S $< -o $#
$(CURDIR)/%.so.s: $(SRC_DIR)/base/socket/%.c $(CURDIR)/%.d
#echo " CC build/tmp/base/socket/$*.so.s"
$(Q)$(CC) $(CFLAGS_SO) -S $< -o $#
$(CURDIR)/%.o: $(CURDIR)/%.s
#echo " AS build/tmp/base/socket/$*.o"
$(Q)$(AS) $< -o $#
include $(DEP)
PHONY += clean
clean:
$(Q)rm -rf *.o *.s *.d
################################################################################
# Declare the contents of the PHONY variable as phony.
.PHONY: $(PHONY)
################################################################################
######## End of file ###########################################################
################################################################################
output:
MKDIR build/tmp/base/socket/tcp
CC -M build/tmp/base/socket/foo.d
CC -M build/tmp/base/socket/tcp/server.d
CC -M build/tmp/base/socket/tcp/client.d
CC build/tmp/base/socket/tcp/client.a.s
AS build/tmp/base/socket/tcp/client.a.o
CC build/tmp/base/socket/tcp/client.so.s
AS build/tmp/base/socket/tcp/client.so.o
CC build/tmp/base/socket/tcp/server.a.s
AS build/tmp/base/socket/tcp/server.a.o
CC build/tmp/base/socket/tcp/server.so.s
AS build/tmp/base/socket/tcp/server.so.o
CC build/tmp/base/socket/foo.a.s
AS build/tmp/base/socket/foo.a.o
CC build/tmp/base/socket/foo.so.s
AS build/tmp/base/socket/foo.so.o

What does sed 's expression do in a Makefile

I have Makefile from an older project which I have to modify for a new system. It has the following global definitions for its source and object files:
SRCFILES = $(wildcard *.c) $(wildcard tasks/*.c)
SRCDIR = .
OBJDIR = objdir
OBJFILES = $(SRCFILES:%.c=${OBJDIR}/%.o)
The Makefile was a mess and I had to modify it heavily. I manged to compile the code and generate the .o files from the .c source code. The expected .elf file is also compiled correctly.
the problem is that I can do not understand what the code is doing in the following lines I searched so many websites but no luck. any ideas?
sed 's,^\(.*\)\.o[ :]*,$(#D)/\1.o $(#D)/\1.d : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
The makefile is as follows
lwip.elf: build_echo $(OBJFILES)
#set -e; echo Linking the object files...; \
sparc-elf-gcc $(OBJFILES) -o $#;
#echo Successfully linked the files
#echo lwip.elf file ready to load...
build_echo: httpserver_raw/fsdata.c
#echo Building the source files first...
#echo The Modified or New source code to be build are :
clean:
- rm -f lwip.elf
$(OBJDIR)/%.o: $(SRCDIR)/%.c
#set -e; echo ' $<'; \
sparc-elf-gcc-4.4.2 -Wall -O2 -g -msoft-float -mcpu=v8 -c -o $# $(CFLAGS) -I. -I lwip/include -I lwip/include/ipv4 -I lwip/leon3 $<
$(OBJDIR)/%.d: $(SRCDIR)/%.c
#set -e; rm -f $#; mkdir -p $(#D); \
sparc-elf-gcc -MM -I. -I lwip/include -I lwip/include/ipv4 -I lwip/leon3 $< > $#.$$$$; \
sed 's,^\(.*\)\.o[ :]*,$(#D)/\1.o $(#D)/\1.d : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
-include $(patsubst %.c,$(OBJDIR)/%.d,$(SRCFILES))
Note: The sparc-elf-gcc is a special cross-compiler used for the sparcV8 architecture.
There's a lot going on in there:
sed 's,^\(.*\)\.o[ :]*,$(#D)/\1.o $(#D)/\1.d : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
Let's break it down.
There's the sed command itself: sed 's,^\(.*\)\.o[ :]*,$(#D)/\1.o $(#D)/\1.d : ,g',
whose input is redirected (<) from a file designated by #.$$$$, and
whose output is redirected (>) to a file designated by $#, then
there's a second command, rm -f $#.$$$$.
Furthermore, that's in the context of a larger list of commands, which set it up with
#set -e; rm -f $#; mkdir -p $(#D); \
sparc-elf-gcc -MM -I. -I lwip/include -I lwip/include/ipv4 -I lwip/leon3 $< > $#.$$$$;
In interpreting that, you have to first recognize several make implicit variables:
$#, which represents the name of the target of the rule
$(#D), which represents the directory of the target name (i.e. the target's dirname)
$<, which represents the first prerequisite
Next, you need to recognize that the dollar sign has special meaning to make, so if you want a literal $ you need to double it. The $$$$ simply repeat this, so that what gets passed to the shell is just two dollar signs ($$). The shell, in turn, replaces that with its own process ID -- a relatively common (but nevertheless insecure) idiom for generating unique file names.
So, the part of the command that you omitted from your callout ensures that the target's destination directory exists, then runs a (cross-?) gcc with flags that cause it to emit information about header dependencies. These are captured in a file, something like objdir/src.d.12345, then in the part you called out, that file is redirected into sed, with the output going to the final target, something like objdir/src.d, after which the intermediate file is removed.
The sed command itself is performing a substitution (s) on all lines, replacing every occurrence (g) of the pattern ^\(.*\)\.o[ :]* with a replacement that I'll come back to in a moment. First the pattern. The ^ anchors the pattern to the beginning of a line. The \(\) are metacharacters delimiting a capturing group, and the .* inside matches any number of any characters. Following that must be a literal decimal point, \., an o, and zero or more occurrences or the space and colon characters ([ :]*). For example, that would match this, up to but not including the header name:
objdir/tasks/t1.o : my_header.h
The replacement uses the aforementioned $(#D) -- which is expanded by make, not the shell or sed -- and \1, which sed expands to the text matched by the first capturing group. Thus, that would transform the above example line to this:
objdir/tasks/t1.o objdir/tasks/t1.d : my_header.h
In short, then, all that to say that it munges the computed dependency list to make the dependency file that is the target of the rule list itself as depending on all the same files that the corresponding object file does.

GNU Make Force Removal of Intermediate Files

I have a compiler that produces .c files from .ec files as an intermediate step. The compiler does not remove the .c file. The compiler cannot be asked to skip invocation of $CC to produce the .o file. I am trying to have GNU make (3.81) treat the .c files produced as intermediate files and clean them up. The following is an isolated example that reproduces the bad behavior with a file extension that has no implied rules.
.INTERMEDIATE: %.delme
%.o: %.ec
cp $< $(<:.ec=.delme)
cp $(<:.ec=.delme) $#
all: test.o
To execute the test case:
rm -f test.*
touch test.ec
make
if [[ -e test.delme ]]; then echo "Failure"; else echo "Success"; fi
Try using a pattern rule to tell make their your compiler produces both .o and .c files from the .ec source. And then declare all the c files as INTERMEDIATE. Pattern rules with multiple outputs work differently than non-pattern rules. Make will run pattern rules only once to produce all output files from the rule, while static rules will be run for each output file. Make also understand that a pattern rule will produce all output files, even if it only wanted one of them as a target.
The result is something like this:
SRC := foo.ec bar.ec
OBJS := $(SRC:.ec=.o)
all: program
program: $(OBJS)
cat $^ > $#
%.o %.c: %.ec
cp $< $(<:.ec=.c) ; cp $< $(<:.ec=.o)
.INTERMEDIATE: $(SRC:.ec=.c)
The command to make the .c and .o from the .ec will be run once to produce both those files. Since make knows it made the .c (even though it only wanted the .o), it will know enough to delete it. The .INTERMEDIATE target will only work if the files are listed explicitly, not using a pattern, so we haven't used %.c. Which seems like a bad idea anyway, what if you had C source that wasn't produce from an .ec file and make deleted it for you? Example output:
$ make
cp foo.ec foo.c ; cp foo.ec foo.o
cp bar.ec bar.c ; cp bar.ec bar.o
cat foo.o bar.o > program
rm bar.c foo.c
$ touch foo.ec ; make
cp foo.ec foo.c ; cp foo.ec foo.o
cat foo.o bar.o > program
rm foo.c
Notice how in the second invocation it only deleted foo.c since bar.o/c wasn't rebuilt.
Make can only consider make targets to be intermediate. You can't just declare a random file on the filesystem as intermediate and have make delete it for you.
Here the .delme file is created as a side effect of the recipe that builds the .o file; make doesn't know anything about it, so make will not delete it because there are no targets in the makefile that are intermediate.
In your example you could split the two cp commands into separate rules and that would allow the intermediate setting to work:
%.delme : %.ec
cp $< $#
%.o : %.delme
cp $< $#
I'm assuming that in your real environment you can't do that because it's all one command that generates the intermediate file and the real file. In that case you'll have to deal with the delete yourself inside the recipe:
%.o : %.ec
cp $< $(<:.ec=.delme)
cp $(<:.ec=.delme) $# && rm -f $(<:.ec=.delme)
Note this leaves the .delme file existing if the cp command fails; if you want to remove it no matter what you can do that too.
EDIT
To delete the intermediate file even if the command fails you have to preserve the exit code so you can tell make what it was. Something like:
%.o : %.ec
cp $< $(<:.ec=.delme)
cp $(<:.ec=.delme) $#; e=$$?; rm -f $(<:.ec=.delme); exit $$e

GNU make: friendly way to choose mutually exclusive files

I'm writing a GNU makefile to create a license file like so: if the customer's file exists then copy it to the package directory, else use the generic license. I have about a dozen files that have the same copy pattern. The goal is to copy one of the two mutually exclusive source files onto the target filename.
Is there a better way to express this with GNU make syntax? Here's what I currently have. I considered copying all GENERIC files to the directory, then overwriting with the existing CUST files.
$(PDIR)/license.txt: | $(PDIR)
if [ -f Package/license.txt.$(CUST) ] ; \
then \
cat Package/license.txt.$(CUST) >$(PDIR)/license.txt ; \
else \
cat Package/license.txt.GENERIC >$(PDIR)/license.txt ; \
fi
Edit: Thanks to MadScientist for the help. Here's my final working version:
TARGETS = license.txt ...
final: $(addprefix ${PDIR}/,${TARGETS})
#echo some output
$(foreach T,${TARGETS},$(eval ${PDIR}/$T: $(firstword $(wildcard Package/$T.${CUST} Package/$T.GENERIC Package/$T)) | ${PDIR}))
$(addprefix ${PDIR}/,${TARGETS}):
#echo Creating substituted version of $< as $#
#sed --expression="\
... \
< '$<' \
> '$#'
${PDIR}:
mkdir $#
You can use wildcard, then (as always) you should use automatic variables. Like this:
$(PDIR)/license.txt: $(firstword $(wildcard Package/license.txt.$(CUST) Package/license.txt)) | $(PDIR)
cat '$<' > '$#'
If you have a lot of these you can also use a loop to define the targets:
TARGETS = license.txt
$(foreach T,$(TARGETS),$(eval $(PDIR)/$T: $(firstword $(wildcard Package/$T.$(CUST) Package.$T) | $(PDIR))))
$(addprefix $(PDIR)/,$(TARGETS)):
cat '$<' > '$#'

Using sed in a makefile; how to escape variables?

I am writing a generic makefile to build static libraries. It seems to work well so far, except for the line calling sed:
# Generic makefile to build a static library
ARCH = linux
CFLAGS = -O3 -Wall
SOURCES = src
BUILD_DIR = build/$(ARCH)
TARGET = $(BUILD_DIR)/libz.a
CFILES = $(foreach dir,$(SOURCES),$(wildcard $(dir)/*.c))
OBJECTS = $(addprefix $(BUILD_DIR)/,$(CFILES:.c=.o))
# Pull in the dependencies if they exist
# http://scottmcpeak.com/autodepend/autodepend.html
-include $(OBJECTS:.o=.dep)
default: create-dirs $(TARGET)
$(TARGET): $(OBJECTS)
$(AR) -rc $(TARGET) $^
$(BUILD_DIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
$(CC) -M $(CFLAGS) $*.c > $(BUILD_DIR)/$*.tmp
sed s/.*:/$(BUILD_DIR)\\/$*.o:/ $(BUILD_DIR)/$*.tmp > $(BUILD_DIR)/$*.dep
#rm $(BUILD_DIR)/$*.tmp
.PHONY: create-dirs
create-dirs:
#for p in $(SOURCES); do mkdir -p $(BUILD_DIR)/$$p; done
.PHONY: clean
clean:
rm -fr $(BUILD_DIR)
sed is used to replace the path/name of the object file with the full path of where the object actually is. e.g. 'src/foo.o:' is replaced with 'build/linux/src/foo.o:' in this example.
$(BUILD_DIR) and $* in the replacement string both contain forward slashes when expanded - how do I pass them to sed?
Note: This might have been answered here before, but I am so far unable to apply those answers to my specific problem!
You can use anything else than forward slashes as separator in sed. E.g. sed s~foo~bar~g
You can use double quotes " (at least in the shell), and variables will still be expanded: echo "Hello $PLANET"
If you want the path to expand into a file you use
sed -i "s/TO_REPLACE/$(subst, /,\/,${PATH_VARIABLE})/g" filename.txt
If your variable PATH_VARIABLE looked like /opt/path/user/home/etc
it will now inflate to:
\ /opt\ /path\ /user\ /home\ /etc
This should allow sed to insert the ' / ' correctly.
-Matt

Resources