Manage exit code in Makefile define - makefile

I am creating a target that can be used as a hook to add some extra procedure when is needed.
This is the code in the main Makefile
export MSG:="Linux hook"
linux-build:
# echo "Dependency target"
linux-build-post: linux-build
# make -s -f linux.hook -q linux_build_post 2> /dev/null ; \
if [ $$? -le 1 ] ; then \
echo "Target exist" ; \
make -s -f linux.hook linux_build_post ; \
else \
echo "Target doesn't exist" ; \
fi
# touch $#
This is the code in the file linux.hook
linux_build_post:
# echo ${MSG}
This code works correctly, but now I am trying to create a template in the main Makefile. For example:
export MSG:="Linux hook"
linux-build:
# echo "Dependency target"
# Common hook target
# Parameters:
# 1: Target name
# 2: Dependecies
# 3: Hook name
define COMMON_HOOK_TARGET
$(1): $(2)
make -s -f $(3).hook -q $(1) 2> /dev/null ; \
if [ $$? -le 1 ] ; then \
echo "Target exist" ; \
make -s -f $(3).hook $(1) ; \
else \
echo "Target doesn't exist" ; \
fi
touch $(1)
endef
$(eval $(call COMMON_HOOK_TARGET,linux-build-post,linux-build))
But in this case the make command fails because $$? is replaced with the dependency linux-build then the if condition is evaluated like this if [ linux-build -le 1 ].
Error reported:
/bin/sh: 1: [: Illegal number: linux-build
How I can change the code in order to use $$? as the exit code of the previous command make -s -f $(3).hook -q $(1) 2> /dev/null ?

I think the answer is actually this:
if [ $$$$? -le 1 ] ; ...
The call to call turns "$$$$" into "$$", then when Make executes the rule it converts "$$?" to "$?" and passes it to the shell.

Related

Passing Makefile variable to docker-compose is resulting in a "unknown shorthand flag" error

I have a Makefile which I use to help our programmers get easily setup. At present I am writing one to pass an IMAGE tag to the docker-compose command, but I keep getting a unknown shorthand flag and I cant figure out why.
My Makefile is as follows;
.PHONY: all
ARCH = $(shell uname -m)
start:
if [ "$(ARCH)" = "x86_64" ]; then \
IMAGE_ARCH="amd64"; \
elif [ "$(ARCH)" = "aarch64" ]; then \
IMAGE_ARCH="arm64"; \
else \
echo "Unknown architecture: $(ARCH)"; \
fi
docker-compose up -d -e IMAGE=$IMAGE_ARCH
The error is;
unknown shorthand flag: 'e' in -e
docker-compose has no -e option.
You can run this way :
.PHONY: all
ARCH := $(shell uname -m)
start:
if [ "$(ARCH)" = "x86_64" ]; then \
IMAGE_ARCH="amd64"; \
elif [ "$(ARCH)" = "aarch64" ]; then \
IMAGE_ARCH="arm64"; \
else \
echo "Unknown architecture: $(ARCH)"; \
fi; \
IMAGE=$$IMAGE_ARCH docker-compose up -d
docker-compose command needs to be put in the same block as [if] in order to use $IMAGE_ARCH.

How to use bash conditionals correctly

I want to only do some code if $# equals 1 and $1 is a readable existing file.
I have following code:
if [[ $# -eq 1 ] -a [ test -r $1 ]]
I have tried many different solutions for an and statement.
Like
[ $# -eq 1 ] $$ [ test -r $1 ]
[ $# -eq 1 -a test -r $1 ]
and many more...
Nothing seems to work. I think its because of the test command.
Sometimes I get an error like test not found or too many arguments or smth else
My whole code:
#!/bin/bash
if [[ $# -eq 1 ] -a [ test -r $1 ]]
then
groupadd -f "TAI12A"
IFS=:
while read nachname vorname klasse
do
nutzername=$nachname$vorname
groupadd -f $klasse
useradd -g "TAI12A" -G $klasse -s /bin/bash -m -p "taipasswd $nutzername
done < $1
else
echo "Uebergabewerte fehlerhaft"
fi
if you want to use test, then no brackets:
if [ $# -eq 1 ] && test -r "$1" ; then
do this ...
fi
Note: [ is a command, it's an alias for test with one exception: when using [ instead of test, ] must be the last argument.
To illustrate this: even if bash nowadays includes [ as a builtin command, the command /usr/bin/[ should still exist on your server.
PS: I would just use:
if [ $# -eq 1 ] && [ -r "$1" ] ; then
do this ...
fi
which is the same as
if test $# -eq 1 && test -r "${1}" ; then
do this ...
fi
Further confusion might be added by the fact that bash also has an extended conditional expressions in the form [[ ... ]]. I recommend to read https://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html#Bash-Conditional-Expressions

Unable to call function from a Makefile

I need to call a function from a make target, this function would be called multiple time ,
define generate_file
if [ "${RQM_SETUP}" = "ci" ]; then
echo "$1" > $(2).txt
else
echo "It is Not Setup";
fi
endef
all:
$(call generate_file,John Doe,101)
$(call generate_file,Peter Pan,102)
right now i am stuck at this Error:
bash-5.0# make
if [ "" = "ci" ]; then
/bin/sh: syntax error: unexpected end of file (expecting "fi")
make: *** [Makefile:10: all] Error 2
Your function is multiple line, which will try to execute as separate shell invocations. This will fail as any single line is not syntactically correct on its own. You can make it work by setting it up in a single line, i.e.:
$ cat Makefile
define generate_file
if [ "${RQM_SETUP}" = "ci" ]; then \
echo "$1" > $(2).txt; \
else \
echo "It is Not Setup"; \
fi
endef
all:
$(call generate_file,John Doe,101)
$(call generate_file,Peter Pan,102)
Output:
$ make
if [ "" = "ci" ]; then echo "John Doe" > 101.txt; else echo "It is Not Setup"; fi
It is Not Setup
if [ "" = "ci" ]; then echo "Peter Pan" > 102.txt; else echo "It is Not Setup"; fi
It is Not Setup

how to break GNU Make shell function call to multiple line

Here is the correct code, but it is very long
$(shell if [ ! -f .oldmodel ] || [ "$(MODEL)" != `cat .oldmodel` ] ; then echo $(MODEL) > .oldmodel ; fi )
I tried
$(shell if [ ! -f .oldmodel ] || [ "$(MODEL)" != `cat .oldmodel` ] ; \
then echo $(MODEL) > .oldmodel ; fi )
But There is a error
common.mak:21: *** missing separator. Stop.
the strange thing is that the .oldmodel is generated, and it's content is right, the next time call make, no error anymore.
Can anyone explain this.
Looks like you are trying to achieve something in a wrong way. Consider the following solution:
ifeq ($(MODEL),)
MODEL := $(shell cat .oldmodel 2>/dev/null)
endif
stuff_to_do: \.oldmodel
mkdir -p $(MODEL)
\.oldmodel: $(if $(shell echo '$(MODEL)' | cmp $# 2>/dev/null), phony,)
#if [ -z "$(MODEL)" ]; then echo "error: MODEL is not set" && exit 1; fi
echo '$(MODEL)' > $#
clean::
rm -rf $(MODEL)
rm -f .oldmodel
The stuff_to_do is your rule where you use the $(MODEL) variable.
Note, the prerequisites for .oldmodel rule is either a phony or empty depending on equality of .oldmodel file contents and $(MODEL). This phony is taken as some non-existent file/rule, so when phony is there it causes the .oldmodel to be rebuilt.

Use the result of a shell command in a conditional in a makefile

I am trying to execute a command in a conditional in a makefile.
I got it working in a shell:
if [ -z "$(ls -A mydir)" ]; then \
echo "empty dir"; \
else \
echo "non-empty dir"; \
fi
but if I try it in a makefile, "$(ls -A mydir)" expands to nothing whatever if asdf is empty or not:
all:
if [ -z "$(ls -A mydir)" ]; then \
echo "empty dir"; \
else \
echo "non-empty dir"; \
fi
The ls command does not expand as I expect:
$ mkdir mydir
$ make
if [ -z "" ]; then \
echo "empty dir"; \
else \
echo "non-empty dir"; \
fi
empty dir
$ touch mydir/myfile
$ make
if [ -z "" ]; then \
echo "empty dir"; \
else \
echo "non-empty dir"; \
fi
empty dir
$ ls -A mydir
myfile
How do I make the command work inside the conditional?
I have little experience in writing makefiles. However I think you must use two dollar signs in your recipe:
all:
if [ -z "$$(ls -A mydir)" ]; then \
https://www.gnu.org/software/make/manual/make.html#Variables-in-Recipes:
if you want a dollar sign to appear in your recipe, you must double
it (‘$$’).
This is an example of output after I changed your makefile and added $$(ls -A mydir):
$ ls mydir/
1
$ make
if [ -z "$(ls -A mydir)" ]; then \
echo "empty dir"; \
else \
echo "non-empty dir"; \
fi
non-empty dir
$ rm mydir/1
$ make
if [ -z "$(ls -A mydir)" ]; then \
echo "empty dir"; \
else \
echo "non-empty dir"; \
fi
empty dir

Resources