Writing recipes inside ifeq block in Makefiles - linux

I am relatively new to Makefiles.
I have the following (simplified) code as part of my Makefile.
I wish to know if, target and the recipe can be declared inside
else statement. Is this valid to write recipe inside ifeq block.
If not can you suggest how to improve it.
CUR_PI_VERSION:= abc
CUR_GIT_VERSION:= cde
LAST_PI_VERSION:= bbc
LAST_GIT_VERSION:= cde
$(info $$CUR_GIT_VERSION is [${CUR_GIT_VERSION}])
$(info $$CUR_PI_VERSION is [${CUR_PI_VERSION}])
$(info $$LAST_GIT_VERSION is [${LAST_GIT_VERSION}])
$(info $$LAST_PI_VERSION is [${LAST_PI_VERSION}])
ABC_AG := ./abc_ag.py
ABC_KG := ./abc_kg.vhd
ABC_OC := ./abc_ef.txt
ifeq ($(CUR_PI_VERSION)#$(CUR_GIT_VERSION),$(LAST_PI_VERSION)#$(LAST_GIT_VERSION))
| #echo "Everything matched, so don't need the make top"
else
# is this valid !!!
.PHONY: $(ABC_KG)
$(ABC_AG) $(ABC_KG) $(ABC_OC):
printf "\t TEST \n"
endif
clean: clean_fpi
clean_fpi:
#rm -f $(ABC_KG); \
| rm -f $(ABC_OC); \
| rm -f $(ABC_AG);
Thanks. Any feedback is appreciated.

Related

Why I cannot create directory in makefile?

ODIR =./obj
SRCS = myfunc.cpp
DEPS = header.h
OBJ = $(patsubst %.cpp, %.o, $(SRCS))
_OBJ = $(ODIR)/$(OBJ)
$(DLL): $(_OBJ)
if test ! -d $(ODIR); then mkdir $(ODIR); fi
$(AR) $(CFLAGS) -o $# $^
$(_OBJ): $(SRCS) $(DEPS)
$(CC) -c -o $# $< $(INCL) $(LDFLAGS)
I want to put all my object file in a directory ./obj. I want to create it if such a directory is not existing. What is wrong with if test ! -d $(ODIR); then mkdir $(ODIR); fi? The error said
Assembler messages: Fatal error: can't create obj/: Is a directory
The first problem is that DLL isn't defined anywhere.
The second problem is here:
OBJ = $(patsubst %.cpp, %.o, $(SRCS))
See the space after the first comma? It looks innocuous, but it means that the variable OBJ winds up containing myfunc.o, which also looks harmless, until you construct _OBJ which turns out to be ./obj/ myfunc.o, which trips up the compiler.
The third problem is that Make will execute the $(_OBJ) rule before the $(DLL) rule, so the compiler must use the obj/ directory before it exists.
The last problem (I hope) is that you seem to be passing $(CFLAGS) as arguments to the archive-maintaining program, when you should use $(ARFLAGS) (and make sure it actually contains what you intend).
A final problem that isn't a problem yet but will be:
SRCS = myfunc.cpp
OBJ = $(patsubst %.cpp,%.o,$(SRCS))
_OBJ = $(ODIR)/$(OBJ)
As long as SRCS only contains one file, this will be fine. But as soon as you add a second file, the above is wrong.
Suppose SRCS contains myfunc.cpp myother.cpp. Then OBJ contains myfunc.o myother.o. Then _OBJ, which is $(ODIR)/$(OBJ), will be ./obj/myfunc.o myother.o which is not what you want.
Better is to just write it as a single change:
SRCS = myfunc.cpp
_OBJ = $(patsubst %.cpp,$(ODIR)/%.o,$(SRCS))

Make/BASH/SH: Dead simple prefix pop and suffix swap for a string?

Suppose I have made some non-conventional use of make. Suppose further that I've come up with a name scheme within this usage that is elegant and useful with tools other than make, and which is almost fitting perfectly into the make paradigm.
I can almost leverage make built-ins to accomplish this task, and am looking for a bit of magic to make it 'just work' within the semantics and grammar of the system.
Right now, I have a buildable process that depends as follows:
# "<-" = "depends on"
foo.bar.biz.baz.new <- foo.bar.biz.baz.extension bar.biz.baz.new
bar.biz.baz.new <- bar.biz.baz.extension biz.baz.new
biz.baz.new <- biz.baz.extension baz.new
baz.new <- baz.extension
# and the following rules should suffice, where $(magic ...) is a stand-in for what I'd like to do:]
SHELL:=/usr/bin/env bash
.SECONDEXPANSION
%.new: $$*.extension $(magic $$*)
...
build: foo.bar.biz.baz.new
What I am looking for is some magic swapper that:
a...b -> ...c if ... != ""
# so, it chops off the prefix (dot-delimited), a
# and swaps the suffix only if something is present other than the suffix
I think this could be:
$(filter-out .c, $(patsubst %,%.c $(not-prefix $$*)))
If not-prefix existed, and I am wondering whether there is some built-in that more or less accomplishes this task out of the box?
Alternatively, is there some really compact bashism that can accomplish this?
For example:
$(shell echo "$$*" | sed -E 's/[^.]*(.*)\.[^.]*$$/\1.new/' | grep -v -E '^\.new$$')
Is super windy and verbose, but maybe there is some compact way to do this?
The most readable I've come up with so far:
%.new: $$*.extension $(filter-out .new, $(shell echo "$$#" | cut -d '.' -f 1 --complement))
Update Minimal verifiable example of the tree-build recursion problem:
%.ext:
#touch $#
.SECONDEXPANSION:
%.new: $$*.ext $(filter-out new, $(shell echo "$$#" | cut -d '.' -f 1 --complement))
#echo "#: $#"
#echo "<: $<"
#echo "^: $^"
#echo $(filter-out new, $(shell echo "$#" | cut -d '.' -f 1 --complement))
$ make descendant.ancestor.new
#: descendant.ancestor.new
<: descendant.ancestor.ext
^: descendant.ancestor.ext
ancestor.new
rm descendant.ancestor.ext
Next, I add in the second "$" sign to the rule, so that it executes during the second expansion instead:
%.ext:
#touch $#
.SECONDEXPANSION:
%.new: $$*.ext $$(filter-out new, $$(shell echo "$$#" | cut -d '.' -f 1 --complement))
#echo "#: $#"
#echo "<: $<"
#echo "^: $^"
#echo $(filter-out new, $(shell echo "$#" | cut -d '.' -f 1 --complement))
Which yields:
$ make descendant.ancestor.new
make: *** No rule to make target 'descendant.ancestor.new'. Stop.
Ultimately, I think this should be something like:
.SECONDEXPANSION:
%.new: $$*.ext | $$(filter-out new, $$(shell echo "$$#" | cut -d '.' -f 1 --complement))
But instead what I have done to make it "just work" is:
%.ext:
#touch $#
.SECONDEXPANSION:
%.new: $$*.ext .FORCE
#echo "#: $#"
#echo "<: $<"
#echo "^: $^"
#$(eval prior=$(filter-out new, $(shell echo "$#" | cut -d '.' -f 1 --complement)))
#$(if $(prior),$(MAKE) $(prior))
#echo "ta-da: idempotent, depth first tree recursion #:$#"
.FORCE:
Which yields a more brittle behavior than the rule line:
$ make -s branch.root.new
#: branch.tree.new
<: branch.tree.ext
^: branch.tree.ext .FORCE
#: tree.new
<: tree.ext
^: tree.ext .FORCE
ta-da: idempotent, depth first tree recursion #:tree.new
ta-da: idempotent, depth first tree recursion #:branch.tree.new
OK thanks for clarifying what you're looking for. So, I don't have anything I would consider "dead simple" but you can do it wholly with GNU make using this:
e =
sp = $e $e
magic1 = $(if $(filter-out 1,$(words $(subst ., ,$1))),$1,)
magic = $(call magic1,$(subst $(sp),.,$(wordlist 2,1000,$(subst ., ,$1))))
Now wherever you want "magic" to happen, call the magic function:
.SECONDEXPANSION:
%.new: $$*.ext $$(call magic,$$#)
The magic1 macro expands to its argument if its argument has >1 ., else expands to the empty string. The magic macro strips off the first "prefix" and calls magic1 with that value.
There may be simpler ways to do this, I didn't come up with one off the top of my head.
Also, I didn't review your edited question so I'm not sure if something you added there makes a difference here.
The problem here is that most build systems depend on stable prefixes and suffixes, with only varying stems (middle parts).
Here, you have an arbitrarily varying prefix, as well as middle part. So for instance bar.biz.baz is the common stem among all the names in the first dependency situation. It is arbitrary. However, each one of the names involved also has an independently arbitrary prefix, like foo.
To avoid fighting the tool, I would try to encode foo and biz.bar.baz, and every other such pair, together in some variables that act as the primary source of this information.
Sample Makefile. In this solution we use nothing but call, firstword, secondword a one-character subst, foreach and eval:
UNITS := foo#biz.bar.baz bar#biz.baz biz#baz
# $(call FIRST, foo#bar) -> foo
FIRST = $(firstword $(subst #, ,$(1)))
# $(call REST, foo#bar) -> bar
REST = $(lastword $(subst #, ,$(1)))
TARGETS := $(foreach U,$(UNITS),$(call FIRST,$(U)).$(call REST,$(U)).new)
DEPS := $(foreach U,$(UNITS),$(call FIRST,$(U)).$(call REST,$(U)).extension) \
$(foreach U,$(UNITS),$(call REST,$(U)))
.PHONY: all $(TARGETS) $(DEPS)
all: $(TARGETS)
define RULE
$(1).$(2).new: $(1).$(2).extension $(2)
#echo BUILD $$# '<-' $$^
endef
$(foreach U,$(UNITS),\
$(eval $(call RULE,$(call FIRST,$(U)),$(call REST,$(U)))))
Output:
$ make
BUILD foo.biz.bar.baz.new <- foo.biz.bar.baz.extension biz.bar.baz
BUILD bar.biz.baz.new <- bar.biz.baz.extension biz.baz
BUILD biz.baz.new <- biz.baz.extension baz
Alternative, using computed variable names. Here, in addition to computed variables, which simulate data structuring, we are only using foreach, call and eval. No string processing at all, other than the nested variable expansion:
UNITS := mercury mars venus
mercury.head := foo
mercury.tail := biz.bar.baz
mars.head := bar
mars.tail = biz.baz
venus.head := biz
venus.tail := baz
TARGETS := $(foreach U,$(UNITS),$($(U).head).$($(U).tail).new)
DEPS := $(foreach U,$(UNITS),$($(U).head).$($(U).tail).extension) \
$(foreach U,$(UNITS),$($(U).tail))
.PHONY: all $(TARGETS) $(DEPS)
all: $(TARGETS)
define RULE
$(1).$(2).new: $(1).$(2).extension $(2)
#echo BUILD $$# '<-' $$^
endef
$(foreach U,$(UNITS),\
$(eval $(call RULE,$($(U).head),$($(U).tail))))
What I am looking for is some magic swapper that:
a...b -> ...c if ... != ""
# so, it chops off the prefix (dot-delimited), a
# and swaps the suffix only if something is present other than the suffix
I don't completely understand the operation you want to execute, but the GNUmake table toolkit has, despite its name, also some practical string operations to offer:
include gmtt.mk
TEST := $(call glob-match,aprefix.thensomething.somemore.thenapostfix,aprefix.*.*apostfix)
$(info $(TEST))
$(if $(TEST),$(info Yes, string looks like),$(info No, string doesn't look like))
$(info aprefix..apostfix)
$(if $(TEST),$(info The variable contents of the string is "$(word 2,$(TEST))" and "$(word 4,$(TEST))"))
Output:
aprefix. thensomething . somemore.then apostfix
Yes, string looks like
aprefix..apostfix
The variable contents of the string is "thensomething" and "somemore.then"
PS: I want to note that the .* sequence in the pattern does not constitute the regex [sequence of 0..n arbitrary characters] but a glob pattern, where the * alone stands for repetition of 0..n arbitrary characters. The . is literal here.
EDIT:
Here is a solution with dynamic rules (to really generate them, replace info with eval:
include gmtt/gmtt.mk
gen-rules = \
$(if $(call glob-match,$1,*.*.new),\
$(info $1 : $(firstword $(call glob-match,$1,*.new)).extension $(word 3,$(call glob-match,$1,*.*)))\
$(call gen-rules,$(word 3,$(call glob-match,$1,*.*))),\
$(info $1 : $(patsubst %.new,%.extension,$1)))
$(foreach cmdline-target,$(filter %.new,$(MAKECMDGOALS)),$(call gen-rules,$(cmdline-target)))

variable to switch the pre-requisites for a target in a Makefile

I wish to use 'MY_TYPE' to switch the prerequisites for the target 'top'.
based on MY_TYPE Can I select the pre-requisites required
For example, for
MY_TYPE=FOO , I wish to have $(BUILD) $(TARGETS) $(X_LOCALS) as pre-requisites for top
MY_TYPE=BAR , I wish to have $(BUILD) $(TARGETS) $(Y_LOCALS) as pre-requisites for top
How can I achieve it?
Below is a simple code snippet.
BUILD = build
TARGETS = targets
XLOCALS = xlocals
YLOCALS = ylocals
# can be FOO or BAR
MY_TYPE ?= FOO
$(BUILD):
printf "\t Doing Build\n"
$(TARGETS):
printf "\t Doing target\n"
$(XLOCALS):
printf "\t my local build for X \n"
$(YLOCALS):
printf "\t my local build for Y \n"
# based on MY_TYPE Can I select the pre-requisites required
# For example, for
# MY_TYPE=FOO , I wish to have $(BUILD) $(TARGETS) $(X_LOCALS) as pre-requisites for 'top' target
# MY_TYPE=BAR , I wish to have $(BUILD) $(TARGETS) $(Y_LOCALS) as pre-requisites for 'top' target
# How can I achieve it .
top: $(BUILD) $(TARGETS) $(XLOCALS)
printf "\t doing top\n"
Happy to take your thoughts.
Nothing easier, just use conditionals:
ifeq ($(MY_TYPE),FOO)
top: $(X_LOCALS)
endif
ifeq ($(MY_TYPE),BAR)
top: $(Y_LOCALS)
endif
top: $(BUILD) $(TARGETS)
#echo prereqs are $^

How to handle special cases in make?

I have following makefile where a bunch of pla files are processed to a files
$(SRC_DIR) has dec.pla,inc.pla, and many more *.pla files
$(FILES) = all corresponding *.a files and instead of dec.a I have dec0.a and dec1.a since I want to generate two different files dec0.a and dec1.a corresponding to dec.pla based on the variable that is being passed. How do I accomplish this?
$(FILES):$(TMP_DIR)/%.a : $(SRC_DIR)/%.pla
$(BASE_CMD) < $< > $#
$(FILES):$(TMP_DIR)/dec0.a : $(SRC_DIR)/dec.pla
$(BASE_CMD) -D c=0 < $< > $(TMP_DIR)/dec0.a
$(FILES):$(TMP_DIR)/dec1.a : $(SRC_DIR)/dec.pla
$(BASE_CMD) -D c=1 < $< > $(TMP_DIR)/dec1.a
I tried the above and got the error
proc.make:8: *** target pattern contains no '%'. Stop
What am I missing here?
$(FILES): $(TMP_DIR)/dec0.a: $(SRC_DIR)/dec.pla is a static pattern rule... without pattern. This is not valid make syntax.
You could try:
FILES1 := $(patsubst $(SRC_DIR)/%.pla,$(TMP_DIR)/%.a,$(wildcard $(SRC_DIR)/*.pla))
FILES2 := $(TMP_DIR)/dec0.a $(TMP_DIR)/dec1.a
$(FILES1): $(TMP_DIR)/%.a: $(SRC_DIR)/%.pla
$(BASE_CMD) < $< > $#
$(FILES2): $(TMP_DIR)/dec%.a: $(SRC_DIR)/dec.pla
$(BASE_CMD) -D c=$* < $< > $#

Bash snippet doesn't work in makefile

I have one version file verfile which contains below version string
V1.1.2
And in Makefile I intend to read this version string,
So I wrote Makefile as follows,
filepath := $(PWD)
versionfile := $(filepath)/verfile
all:
cat $(versionfile)
version=$(shell cat $(versionfile))
echo "version=$(version)"
Now when I run the make file I get following ouput
cat /home/ubuntu/ankur/verfile
v1.1.2
version=v1.1.2
echo "version="
version=
So I am not able to store version string in the variable and use it later,
I am not sure what am I doing wrong?
Any suggestion/pointer ?
After reading answer from "Didier Trosset" I changed my makefile as follows,
filepath := $(PWD)
versionfile := $(filepath)/verfile
myversion := ""
all:
ifeq ($(wildcard $(versionfile)),)
all:
echo "File not present"
else
all: myversion = $(shell cat $(versionfile))
endif
all:
echo "myversion = $(myversion)"
and below is output for the
echo "myversion = v1.1.2"
myversion = v1.1.2
You have two problems. First to have bash (and not make) expand the variable you need to use $$version (or $${version}). By this Make first translates $$ into just $ and then bash will see $version (or ${version}).
Secondly each line in the rule will be executed as a separate command, so in order to let them interact via environmental variables you have to put them into a common subshell, enclosing with paranthesis.
filepath := $(PWD)
versionfile := $(filepath)/verfile
all:
cat $(versionfile)
(version=$(shell cat $(versionfile)); echo "version=$$version")
I usually prefer to have this version string in a make variable.
Therefore, I'd rather use the following that keeps variables into variables, and rules/target/commands in rules/target/commands.
filepath := $(PWD)
versionfile := $(filepath)/verfile
version := $(shell cat $(versionfile))
info:
echo "version=$(version)"
Note that here, version is a real make variable. (As opposed to a bash variable existing only in a lingle rule line of the target.)
If you need some commands to create the versionfile then it'd be better to create this file on its own target
filepath := $(PWD)
versionfile := $(filepath)/verfile
all: versionfile
echo "version=$(version)"
all: version = $(shell cat $(versionfile))
versionfile:
# Create your version file here
Note that you cannot use the := anymore for the target variable: it would read the file at Makefile reading instead of when used, i.e. after versionfile target has been created.

Resources