Daniel
Daniel

Reputation: 341

variable doesn't get exanded for patsubst in makefile

I'm trying to write a rule that would replace a set of .c files with .o files for a variable.

To make sure it works, I'm echoing their values. the .c files are obtained from the current working directory via a shell wildcard

sources := *.c

However, nothing gets printed out for the .o files, as 'sources' doesn't seem to get expanded for this, whether I do with using patsubst or the handier $(src:%.c=%.o).

On the other hand, if I set the value of 'manually', everything works as expected, e.g.

sources := source1.c source2.c source3.c

The makefile:

sources := *.c
srcs = one.c two.c
objects := $(sources:.c=.o)
objs := $(patsubst %.c, %.o, $(srcs))

prints:
    @echo sources
    @echo $(sources)
    @echo objects
    @echo $(objects)
    @echo $(objs)

Output:

sources
source1.c source2.c source3.c source4.c
objects
*.o
one.o two.o

As you can see, 'objects' (based on the wildcard-using 'sources') is a no-go, but 'objs' (based on the manally-set 'srcs' works as expected).

What am I missing. I know it must have to do with when or how the expansion takes place.

Upvotes: 0

Views: 386

Answers (1)

MadScientist
MadScientist

Reputation: 100916

Make is not the shell. This line:

sources := *.c

sets the make variable sources to the literal string *.c. Then this line:

objects := $(sources:.c=.o)

sets objects to the literal string *.o.

Then this line:

@echo $(sources)

Sends echo *.c to the shell, and the SHELL expands the *.c to the list of files that match that glob.

Then this line:

@echo $(objects)

sends echo *.o to the shell, and since there are no files that match the *.o glob, it just prints the glob itself *.o.

If you want to get a list of files in make you have to use the wildcard function:

sources := $(wildcard *.c)

Also, you have fallen prey to two different common errors people make when they are trying to debug makefiles:

First, you should never, EVER use @ in your recipe lines to hide the commands. This is like trying to debug your makefile with a blindfold on. Seeing what make is sending to the shell gives you absolutely vital information as to what is happening here. I personally don't use @ even after my makefile is working, except for some trivial operations, and I definitely never use it while trying to debug.

Second, if you want to see the contents of make variables in recipes you should always use single quotes around them. If you leave them unquoted or use double quotes, then the shell will come along and mess with those values (depending on what the values are) and you won't be able to see what they really are. Either use '' around them or else use a make function like $(info ...) to see their value rather than a shell program like echo.

If you had written your test makefile like this:

prints:
        echo sources
        echo '$(sources)'
        echo objects
        echo '$(objects)'
        echo '$(objs)'

it would have been more immediately obvious what the problem was.

Upvotes: 2

Related Questions