I have been trying to check the existence of a file in a Makefile without success:
I tried:
.PHONY test:
ifeq ($(shell test -e "/opt/local/bin/lame" && echo -n "yes"),"yes")
#echo 'File exists'
else
#echo 'File does not exist'
endif
I always get "File does not exist" when I run make test. And yes the file does exist!
I also tried the following:
.PHONY test:
ifeq ($(shell echo -n "yes"),"yes")
#echo 'File exists'
else
#echo 'File does not exist'
endif
Again, I always get "File does not exist" when I run make test.
So I must not be using the conditional test right.
what I am missing here?
I found a way to check for the existence of the file in a Makefile using wildcard. See below:
.PHONY test:
ifneq ("$(wildcard /opt/local/bin/lame)","")
#echo 'File exists'
else
#echo 'File does not exist'
endif
I am still confused why my precious attempt did not work.
Related
I am very new to make and have wanted to learn more about conditionals.
I want to check the result of whoami in a makefile but keep getting errors
ifeq ($(whoami), "John")
echo "PC"
else
echo "Server"
endif
Here it gives me an error on the line echo "Server" saying *** missing separator how do I fix it?
You will want something like this:
#!/bin/bash
if [[ $(whoami) == "John" ]]; then
echo "PC"
else
echo "Server"
fi
As mentioned by Primitive, bash does not use ifeq and endif.
EDIT
As per chepner's comment, this question could be about Make and not Bash, in that case, this should work:
SHELL = /bin/sh
USER = $(shell whoami)
buildbegin:
ifeq ($(USER), John)
#echo PC
else
#echo Server
endif
Can be tested with make -f $MakeFile
I have the following lines in my makefile:
.PHONY : clean
clean:
#echo "Running Clean"
$(shell if [ -e exe ]; then rm exe; else echo "no files"; fi)
When I run:
make clean
I get the following output on the shell
Running Clean
no files
make: no: Command not found
Makefile:22: recipe for target 'clean' failed
make: *** [clean] Error 127
Any suggestions?
The problem is the use of $(shell ...). What you want is:
.PHONY : clean
clean:
#echo "Running Clean"
#if [ -e exe ]; then rm exe; else echo "no files"; fi
As far as an explanation of what's going wrong -- when you first run the clean target, make will expand all make variables and functions in the recipes before it starts running them -- because $(shell ...) only has one $, this is considered a make function. Make runs the command, which outputs no files to stdout, and replaces the call with that string, and then starts executing the recipes... So now make sees the following:
clean:
#echo "Running Clean"
no files
When it tries to run no files, due to the lack of a #, it echos the line to the screen, and then passes the command to the shell. Because the shell doesn't recognize the keyword no it outputs the error you're seeing. Make itself then fails because the shell returned an error.
Hey all I'm the same guy who asked this question but I found an answer right after I posted this, I think I'll leave this up (unless this is against stackoverflow etiquette) in case someone else has the same problems. My solution was echoing the string to stdout.
$(shell if [ -e exe ]; then rm exe; else echo "no files" >&2; fi)
Lets assume, i want to call
make somepath/abc.pot
which depends on somepath/somefiles.c
My target I've created so far looks like
%.pot: $(dir $#)*.c
#echo "it works"
ifeq (,$(wildcard $#))
# pot-file does not exist, do something
else
# pot-file already exists, do something else
endif
but does not work as the Automatic Variables
like $# are not available in the prerequisites.
If found, that i can enable second expansion
.SECONDEXPANSION:
%.pot: $$(dir $$#)*.c
#echo "it works"
ifeq (,$(wildcard $#))
# pot-file does not exist, do something
else
# pot-file already exists, do something else
endif
which allows me to use $# in the prerequisites but breaks my ifeq statement which then always results in the first branch. If I change the ifeq to
ifeq (,$$(wildcard $$#))
it's working again but I really don't get why.
Now there a two questions:
A) Is there another way but to enable second expansion to have the path of the target in my prerequisites?
B) Why does the ifeq (,$(wildcard $#)) statement always result in the first branch if second expansion is enabled?
Don't use ifeq in the recipe at all. Just use normal shell functionality. It works better.
.SECONDEXPANSION:
%.pot: $$(dir $$#)*.c
#echo "it works"
if [ ! -f $# ]; then \
: pot-file does not exist, do something; \
else \
: pot-file already exists, do something else; \
fi
That said using wildcard in prerequisite lists is generally a bad idea because the time that they are globbed is not reliable and can cause odd behaviors. See Pitfalls of Using Wildcards for one example of a problem.
If you need to write different recipe contents based on some external factor (like OS) then you need to detect that at make parse time and have two copies of your recipes/makefile that you switch between correctly. You can do that inline but you can't do that per-recipe inline.
Your original attempts (using ifeq in a recipe) do not work. They don't do what you think they do. They may appear to work but they aren't working the way you expect.
Consider this makefile:
all: c
a:
#touch a
c: a
.SECONDEXPANSION:
c d:
ifeq (,$(wildcard a))
#echo "a doesn't exist (make)"
else
#echo 'a does exist (make)'
endif
#if [ ! -f a ]; then \
echo "a doesn't exist (sh)"; \
else \
echo 'a does exist (sh)'; \
fi
ifeq (,$$(wildcard a))
#echo "a doesn't exist (make se)"
else
#echo 'a does exist (make se)'
endif
In an empty directory you would expect make to output (assuming ifeq works the way you want it to):
a does exist (make)
a does exist (sh)
a does exist (make se)
Right? But it doesn't. You get:
a doesn't exist (make)
a does exist (sh)
a does exist (make se)
Ok, you think, that's just things not working without secondary expansion. But the secondary expansion version is working correctly. But it isn't.
If you run make d in an empty directory (note the d target doesn't list a as a prerequisite so it won't create it) you would expect the following output:
a doesn't exist (make)
a doesn' exist (sh)
a doesn' exist (make se)
Right? But what you actually get is:
a doesn't exist (make)
a doesn't exist (sh)
a does exist (make se)
So it appears that the secondary expansion version isn't working either.
A look at the make database explains why not.
Run make -qprR | awk '/c: a/,/^$/; /d:/,/^$/' in an empty directory and you see:
c: a
# Implicit rule search has not been done.
# File does not exist.
# File has been updated.
# Needs to be updated (-q is set).
# variable set hash-table stats:
# Load=0/32=0%, Rehash=0, Collisions=0/2=0%
# commands to execute (from `Makefile', line 12):
#echo "a doesn't exist (make)"
#if [ ! -f a ]; then \
echo "a doesn't exist (sh)"; \
else \
echo 'a does exist (sh)'; \
fi
#echo 'a does exist (make se)'
d:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# commands to execute (from `Makefile', line 12):
#echo "a doesn't exist (make)"
#if [ ! -f a ]; then \
echo "a doesn't exist (sh)"; \
else \
echo 'a does exist (sh)'; \
fi
#echo 'a does exist (make se)'
Which, as you can see, doesn't contain the ifeq lines but just the "correct" branch of the ifeq logic.
And that's the problem, the ifeq conditionals are evaluated at make parse time which is well before any recipes run (and thus before any files can be created, etc.).
In my makefile I have
run_sh:
echo"run script";\
toolk -run -tcl sequence.tcl | tee ./log/catch.log;\
$(call chck "./log/catch.log")
I want to catch error status=0 message from above log file and check, if not "0" exit form make file. so i have written this function and calling it in my target run_sh.
define chck
log=$(1)
STAT=`cat $(1) | grep "exit status=0"`
ifneq ($(STAT),"exit status=0")
$(error error in script)
endif
endef
Is the correct way to write, because i am getting error.
How about this:
run_sh:
echo"run script"; toolk -run -tcl sequence.tcl | tee ./log/catch.log;
grep "error status=0" ./log/catch.log || exit
EDIT:
I don't have access to GNUMake 3.79.1, so we must perform some experiments. Set this rule:
run_sh:
exit
and try "make run_sh" (not "make" or "make all" or anything else). What is the result? (Don't just say "it doesn't work", show us the output.)
My open source project distributes a Makefile. "make" by itself works fine as long as the user has Boost and OpenSSL installed. If not, he gets a compilation error.
I would like to show the user an error message with instructions on how to fix rather than have him discern the issue from the compiler output.
I've put together a little script to embed inside a Makefile that will do a quick and dirty compilation to validate if a prerequisite header file exists before allowing the core code to build. It shows an error message and aborts the compile if the code won't compile. It seems to work good.
# BOOST_INCLUDE := -I/home/jselbie/boost_1_51_0
all: myapp
testforboost.o:
#echo "Testing for the presence of Boost header files..."
#rm -f testforboost.o
#echo "#include <boost/shared_ptr.hpp> " | $(CXX) $(BOOST_INCLUDE) -x c++ -c - -o testforboost.o 2>testerr; true
#rm -f testerr
#if [ -e testforboost.o ];\
then \
echo "Validated Boost header files are available";\
else \
echo "* ********************************************";\
echo "* Error: Boost header files are not avaialble";\
echo "* Consult the README file on how to fix";\
echo "* ********************************************";\
exit 1;\
fi
myapp: testforboost.o
$(CXX) $(BOOST_INCLUDE) myapp.cpp -o myapp
Is my script a good way to do this? I'm under the assumption that it's portable beyond Linux (Solaris, BSD, MacOS). Or are there other standard practices for doing this? I know that Autotools can do similar things, but I'm not too excited about learning all of Autotools and re-writing my Makefiles.
In principle it's possible like that. But since you're only preprocessing, and given that you can use any command as a condition, it can be simplified to:
.PHONY: testforboost
testforboost:
#echo "Testing for the presence of Boost header files..."
#if echo "#include <boost/shared_ptr.hpp> " | $(CXX) -x c++ -E - >/dev/null 2>&1;\
then \
echo "Validated Boost header files are available";\
else \
echo "* ********************************************";\
echo "* Error: Boost header files are not avaialble";\
echo "* Consult the README file on how to fix";\
echo "* ********************************************";\
exit 1;\
fi
OTOH, since you have the boost include path in a variable, why not just look for the file directly? That would need some string manipulation. Probably hard in make, but with makepp it would be $(map $(BOOST_INCLUDE),s/^-I//)