How do I use shell variables in Makefile actions?

I have the following in a Makefile for the purpose of recreating my database including destroying it if necessary. It does not work.

.PHONY: rebuilddb
    exists=$(psql postgres --tuples-only --no-align --command "SELECT 1 FROM pg_database WHERE datname='the_db'")
    if [ $(exists) -eq 1 ]; then
        dropdb the_db
    fi
    createdb -E UTF8 the_db

Running it results in an error:

$ make rebuilddb
exists=
if [  -eq 1 ]; then
/bin/sh: -c: line 1: syntax error: unexpected end of file
make: *** [rebuilddb_postgres] Error 2

Why is this wrong? It looks like valid Bash as far as I can tell? Are there special considerations I must make when doing this in a Makefile?

UPDATE:

Using the answer I arrived at a working version:

.PHONY: rebuilddb
    exists=$$(psql postgres --tuples-only --no-align --command "SELECT 1 FROM pg_database WHERE datname='the_db'"); \
    if [ "$$exists" == "1" ]; then \
        dropdb the_db; \
    fi;
    createdb -E UTF8 the_db

Answers


There are at least two considerations. $() references a Make variable. You must escape the $ to do command substitution. Also, the shell commands must be all on one line. Try:

exists=$$(psql postgres --tuples-only --no-align --command "SELECT 1 FROM \
    pg_database WHERE datname='the_db'"); \
    if [ "$$exists" -eq 1 ]; then \
        dropdb the_db; \
    fi; \
    createdb -E UTF8 the_db

On the other hand, it seems like it would be simpler to just always try to drop the database, and allow failure:

rebuilddb:
    -dropdb the_db  # Leading - instructs make to not abort on error
    createdb -E UTF8 the_db

For completness the usage in $(eval $(call ...)

The usage in dynamic generation rules you have to escape the shell variables with $$$$.

Here is an example which has been tested with "GNU Make 4.2.1":

MY_LIBS=a b c

a_objs=a1.o a2.o b_objs=b1.o b2.o b3.o c_objs=c1.o c2.o c3.o c4.o

default: libs

# function lib_rule(name, objs)

define lib_rule lib$(1).a: $(2) exit 1 | tee make.log ; test $$$${PIPESTATUS[0]} -eq 0 endef

# generate rules $(foreach L,$(MY_LIBS),$(eval $(call lib_rule,$(L),$($(L)_objs))))

# call generated rules libs: $(patsubst %,lib%.a,$(MY_LIBS))

# dummy object generation %.o:%.c touch $@

# dummy source generation %.c: touch $@

clean:: rm -f *.c *.o lib*.a make.log

The output: 'make -Rr'

exit 1 | tee make.log ; test ${PIPESTATUS[0]} -eq 0 make: *** [Makefile:18: liba.a] Error 1

Result of last command in pipe is true from tee. You can see bash variable PIPESTATUS[0] has the value false from exit 1

Watch the Database: 'make -Rrp'

define lib_rule lib$(1).a: $(2) exit 1 | tee make.log ; test $$$${PIPESTATUS[0]} -eq 0 endef

...

libc.a: c1.o c2.o c3.o c4.o exit 1 | tee make.log ; test $${PIPESTATUS[0]} -eq 0


Need Your Help

How do you use a variable in a regular expression?

javascript regex

I would like to create a String.replaceAll() method in JavaScript and I'm thinking that using a regex would be most terse way to do it. However, I can't figure out how to pass a variable in to a r...

Jquery events not working on ajax loaded content

jquery ajax

The below code works. If there is some better way please let me know.