Arthur Caccavo
Arthur Caccavo

Reputation: 118

Why $(< file.txt) don't work on makefile?

Using the command line I get the desired output

 $ ./program $(< file.txt)
 ./program 1 2 3 4 5

But with a makefile

all: program file.txt
    ./program $(< file.txt)
    @rm -f program
    
program: program.c
    gcc program.c -o program

I get the output

gcc program.c -o program
./program

Upvotes: 2

Views: 218

Answers (2)

Because in a makefile, the $(...) syntax is used for variable interpolation. So your makefile tries to expand the value of a makefile variable / environment variable named < file.txt. And if unset, it expands to an empty string.

Proof:

all:
        echo $(< file.txt)

and file.txt containing

now it works

Then execute

% env '< file.txt=Hello world' make
echo Hello world
Hello world

i.e. by setting an environment variable named < file.txt to value Hello world , the greeting was printed. The fix is to escape the $ character by doubling it:

all:
        echo $$(< file.txt)

and then

% make
echo $(< file.txt)
now it works

Q.E.D.

Finally, while the $() interpolation syntax in POSIX shells, the $(< file.txt) is not but you can replace it with $(cat file.txt) so it works with minimally POSIX-conforming shells. Of course in a makefile you again need to double the dollar, therefore getting the maximally compatible

$$(cat file.txt)

Alternatively you can use the similar makefile facility which is $(shell ), i.e.

 $(shell cat file.txt)

would work too... (now with one $). Finally you can read files with $(file ) GNU makefile function too, i.e.

all:
        echo $(file <file.txt)

would work alike but wouldn't call shell at all.

Upvotes: 4

tripleee
tripleee

Reputation: 189457

The substitution you are trying to use is a Bash feature, but make out of the box runs the regular Bourne shell sh, where this syntax is not available (even when sh is a symlink to Bash, as is still common on some Linux distributions).

Requiring the contents of the file to be specified on the command line looks like a design flaw, anyway; it's probably much better if your C program simply reads and processes standard input (or perhaps accepts a list of file names, and falls back to stdin if none are specified, like many Unix file processing utilities).

If this is just for a test case to run the program with parameters from a file, check out xargs.

xargs ./program <file.txt

If you insist on using Bash-only syntax, add

SHELL=/bin/bash

(or whatever full path is correct on your system); but understand that this limits the portability of your Makefile.

Still, you'll need to double any literal dollar sign which should be passed through and exposed to the shell.

Upvotes: 0

Related Questions