Makefile: write conditional statement for the shell - bash

I used this post as a basis for how to pass arguments to a make target.
I would like to perform a string comparison on this command line arg, using this post as inspiration for doing string equality comparisons in a makefile.
Update using the suggested answer below:
%:
#:
test:
if [ '$(filter-out $#,$(MAKECMDGOALS))' = hi ]; \
echo "WON"; \
else \
echo "LOST"; \
fi
where I do 8 spaces instead of indents, nothing prints. When I do tabs instead of spaces, I get the following errors:
if [ 'hi' = hi ]; \
echo "WON"; \
else \
echo "LOST"; \
fi
/bin/sh: -c: line 0: syntax error near unexpected token `else'
/bin/sh: -c: line 0: `if [ 'hi' = hi ]; echo "WON"; else echo "LOST"; fi'
make: *** [test] Error 2
Original attempt:
%:
#:
test:
ifeq ($(filter-out $#,$(MAKECMDGOALS)),hi)
echo "WON"
else
echo "LOST"
endif
However, when I run, make test hi, I get
arg="hi"
ifeq (hi,hi)
/bin/sh: -c: line 0: syntax error near unexpected token `hi,hi'
/bin/sh: -c: line 0: `ifeq (hi,hi)'
make: *** [test] Error 2
What is the unexpected token ?

ifeq is a make directive. By indenting it with a TAB, you have put it into the recipe, and all commands in the recipe are passed to the shell. The shell has no idea what an ifeq command is, and can't understand all the parens here, so you get these errors.
If you want to conditionalize on an automatic variable like $#, which are only available in the recipe, you have to write a shell conditional statement you can't use a make conditional statement:
test:
if [ '$(filter-out $#,$(MAKECMDGOALS))' = hi ]; then \
echo "WON"; \
else \
echo "LOST"; \
fi

Leaving this answer as the one posted doesn't work as it is missing a then
test:
if [ '$(filter-out $#,$(MAKECMDGOALS))' = hi ]; then \
echo "WON"; \
else \
echo "LOST"; \
fi
shell conditionals go if [] then ... else ... fi

Related

Makefile: Syntax error /bin/sh: -c: syntax error: unexpected end of file

I have a simple Makefile:
git_repo := some_git_repo
repo:
if [ -v $(git_repo) ]; then \
echo "exists!" \
else \
echo "not exist!" \
fi;
clean: repo
Running make clean gives me an error:
/bin/sh: -c: line 4: syntax error: unexpected end of file
make: *** [repo] Error 2
I'm not quite sure what's the cause for this error. I've double checked the syntax countless times, checked many different StackOverflow questions and even tried running the bash code under the repo rule separately and it works fine. What am I doing wrong here?
You need semicolons. The "\" effect is to put everything on the same line.
repo:
if [ -v $(git_repo) ]; then \
echo "exists!"; \
else \
echo "not exist!"; \
fi;
See the echo ends with a semicolon now.
The backslashes cause all the shell lines to be concatenated into one long line, which means you need semi-colons at the end of each line to separate the statements.
if [ -v $(git_repo) ]; then \
echo "exists!"; \
else \
echo "not exist!"; \
fi
After the backslashes and newlines are removed (and $(git_repo) is substituted) the shell sees:
if [ -v some_git_repo ]; then echo "exists!"; else echo "not exist!"; fi

How to force an error if file is missing?

This snippet of a makefile shall stop the execution if the file myFile does not exist:
test:
if [ -e myFile ] ; then \
echo "Error Message"; \
fi;
If I replace the echo-statement by $(error: Error Message); \ the make file is being stopped in both cases. But I need the makefile to be stopped if the file exists.
$(error ) is interpreted by make itself, so if it is hit during reading of the file, the error is produced. If you need an error during execution of a recipe, you have to run a command that returns an error exit code. Most straight-forward would be false for that, e.g.
test:
if [ -e myFile ] ; then \
echo "Error Message"; false; \
fi;
Of course, you could check for the file using $(shell ), without a recipe:
ifeq ($(shell test -e myFile && echo yes),)
$(error Error Message)
endif

Is conditional statement in Makefile valid syntax

I have the following Makefile
~/w/i/craft-api git:develop ❯❯❯ cat Makefile ⏎ ✱ ◼
test:
echo "TODO: write tests"
generate-toc:
if ! [ -x "$(command -v doctoc)" ]; then
echo "Missing doctoc. Run 'npm install doctoc -g' first"
else
doctoc ./README.md
fi
I'm encountering this error
~/w/i/craft-api git:develop ❯❯❯ make generate-toc ✱ ◼
if ! [ -x "" ]; then
/bin/sh: -c: line 1: syntax error: unexpected end of file
make: *** [generate-toc] Error 2
What is incorrect in my Makefile syntax / usage?
edit 1
Adding line-continuing backslashes doesn't appear to fix the issue:
~/w/i/craft-api git:develop ❯❯❯ cat Makefile ⏎ ✱ ◼
test:
echo "TODO: write tests"
generate-toc:
if ! [ -x "$(command -v doctoc)" ]; then \
echo "Missing doctoc. Run 'npm install doctoc -g' first" \
else \
doctoc ./README.md \
fi
~/w/i/craft-api git:develop ❯❯❯ make generate-toc ✱ ◼
if ! [ -x "" ]; then \
echo "Missing doctoc. Run 'npm install doctoc -g' first" \
else \
doctoc ./README.md \
fi
/bin/sh: -c: line 1: syntax error: unexpected end of file
make: *** [generate-toc] Error 2
Every line is treated as a separate command and is passed to a different shell instance. You can use \ continuations to combine all of the lines so make knows to pass them as one long string to a single shell. This removes the newlines so you also need to add ; at the end of each command.
if ! [ -x "$$(command -v doctoc)" ]; then \
echo "Missing doctoc. Run 'npm install doctoc -g' first"; \
else \
doctoc ./README.md; \
fi
You'll also want to escape the $, otherwise make will interpret it rather than the shell.

Shell script condition checking in Makefile

I've got the following Makefile script which calls a python test suite that writes the results to a file called test_results.txt. Then I display the files and read the last line which has a status that indicates whether all the test cases have been executed or not. Based on that value I echo a statement.
target: test.py
$(PYTHON) test.py
#cat test/test_results.txt
#if [ $(shell sed -e '$$!d' test/test_results.txt) = 0 ]; then\
echo "\nAll tests passed successfully";\
else \
echo "\nNot all the tests were passed";\
fi
When I run it, I get the following error: 0/bin/sh: 1: [: =: unexpected operator
It's much simpler to make test.py have a non-zero exit status if any test fails. Then your recipe is simply
target: test.py
#if $(PYTHON) test.py; then\
echo "\nAll tests passed successfully";\
else \
echo "\nNot all the tests were passed";\
fi
#cat test/test_results.txt

'#' doesn't work, how to stop echo between if..fi in makefile?

I have the following command in makefile:
$(OUT)/classes.jar: $(JavaFileList) $(libJars) $(ANDROID_JAR) | $(OutClasses)
#echo javac: `wc -l < $(JavaFileList)` source files
if [ $$ENABLE_MV = 'YES' ]; then \
echo Backup $(OutClasses) to $(OutClasses).bak; \
fi
but it will print the following command each time:
if [ $$ENABLE_MV = 'YES' ]; then \
echo Backup $(OutClasses) to $(OutClasses).bak; \
fi
how to stop this? "#" dosn't work in if..fi, this error will occur: /bin/sh: line 1: #echo: command not found
Every logical line must start with a # to be suppressed. A logical line is a physical line plus all subsequent lines that are combined using a backslash at the end of the line. So in your case, you need the # before the if, because the previous line (echo) does not end in a backslash so this is a new logical line. You don't need the # on the subsequent lines because they are the same logical line (connected with backslashes).
$(OUT)/classes.jar: $(JavaFileList) $(libJars) $(ANDROID_JAR) | $(OutClasses)
#echo javac: `wc -l < $(JavaFileList)` source files
#if [ $$ENABLE_MV = 'YES' ]; then \
echo Backup $(OutClasses) to $(OutClasses).bak; \
fi

Resources