3

In my makefile, I am trying to capture the output from a shell function call on a make variable containing the command string without success. When I run the shell function on the string directly, it works. I don't understand what the difference is between running the shell function on the command string versus running the shell function on a make variable containing the command string.

PG_CONFIG = "/usr/pgsql-9.4/bin/pg_config/"

PG_INCLUDE1 = $(shell $$PG_CONFIG)
PG_INCLUDE2 = $(shell /usr/pgsql-9.4/bin/pg_config --includedir-server)

.PHONY: print

print:
    @echo "PG_CONFIG="$(PG_CONFIG)
    @echo "PG_INCLUDE1="$(PG_INCLUDE1)
    @echo "PG_INCLUDE2="$(PG_INCLUDE2)

The output is:

$make -f Makefile.test print
PG_CONFIG=/usr/pgsql-9.4/bin/pg_config/
PG_INCLUDE1=
PG_INCLUDE2=/usr/pgsql-9.4/include/server
1
  • try PG_INCLUDE1 = $(shell $(PG_CONFIG)) Commented Apr 16, 2015 at 17:46

2 Answers 2

3

As it stands in GNU Make Manual:

Variable and function references in recipes have identical syntax and semantics to references elsewhere in the makefile. They also have the same quoting rules: if you want a dollar sign to appear in your recipe, you must double it (‘$$’). For shells like the default shell, that use dollar signs to introduce variables, it’s important to keep clear in your mind whether the variable you want to reference is a make variable (use a single dollar sign) or a shell variable (use two dollar signs).

The $$ is replaced with a single dollar. In your example:

PG_INCLUDE1 = $(shell $$PG_CONFIG)

becomes:

PG_INCLUDE1 = $(shell $PG_CONFIG)

Next, $PG_CONFIG is executed in shell just as if you typed it in the terminal. And as there is no PG_CONFIG variable defined in the current subshell $PG_CONFIG is replaced with nothing. However, if you defined PG_CONFIG environment variable before running make it would work as you wished with $$ in Makefile:

$ export PG_CONFIG="aoeuidhtn"
$ make
PG_CONFIG=/usr/pgsql-9.4/bin/pg_config/
PG_INCLUDE1=aoeuidhtn
Sign up to request clarification or add additional context in comments.

5 Comments

Always use := when assigning values to variables within make files.
@mhradek: Because?
Per https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_6.html the colon tells the processor to only read and assign once.
First, link you posted describes an ancient version of make - 3.79.1 was released in 2000 ftp.gnu.org/gnu/make. Second, you said what := does but didn't explain why should it always be used?
Same applies: gnu.org/software/make/manual/make.html Perhaps always is too strong of a word. How about "Consider using simple assignment over recursive assignment whenever possible to be explicit and avoid inadvertent assignment issues".
2

I see two problems. The definition of PG_CONFIG ends with a "/" so it is being treated as a directory. And your variable reference in PG_INCLUDE1 should be $(PG_CONFIG) not $$PG_CONFIG.

Try this:

PG_CONFIG = "/usr/pgsql-9.4/bin/pg_config"

PG_INCLUDE1 = $(shell $(PG_CONFIG))
PG_INCLUDE2 = $(shell /usr/pgsql-9.4/bin/pg_config --includedir-server)

.PHONY: print

print:
    @echo "PG_CONFIG="$(PG_CONFIG)
    @echo "PG_INCLUDE1="$(PG_INCLUDE1)
    @echo "PG_INCLUDE2="$(PG_INCLUDE2)

3 Comments

There's also no reason to keep the make variables outside the quoted string in the shell lines (they can even go inside a single quoted string).
Your example yields Makefile:9: *** missing separator. Stop.
Nevermind. Needed to replace the spaces before @echo with tabs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.