Makefile `echo -n' not working

2020-05-19 04:55发布

I am trying to have my Makefile echo text without the trailing new line, but am unable to. I am experiencing the behavior on OS X (on Linux everything works as expected).

Makefile

a:
    @echo -n "hello"

b:
    @echo -n hello

c:
    @/bin/echo -n "hello"

Output:

$make a
-n hello
$make b
hello$make c
hello$

In other words, the make a is broken. What exactly is happening? Is make using a built-in echo? Clearly the presence of the double quotes changes the behavior, but why?

Update

As discovered by @chepner, using the full path to /bin/echo in the makefile understands the -n flag correctly.

3条回答
女痞
2楼-- · 2020-05-19 05:23

echo is a bash shell builtin, but when you run it from makefile, it is the program version

查看更多
倾城 Initia
3楼-- · 2020-05-19 05:26

The problem comes from the unfortunate interaction of two facts.

First, make has two modes of operations depending on the complexity of the recipe to be run:

  • If the command is easy, make will directly run the recipe with its builtin commands. This is what happens in your b case.
  • If the command is complex, make will spawn a shell to interpret and run the recipe. This is what happens in your a case.

Second, make uses /bin/sh as a shell but the functionality of /bin/sh is implemented differently on Mac OS X and Linux:

  • On Mac OS X, the functionality of /bin/sh is implemented by bash. Also on Mac OS X, bash is compiled with --enable-strict-posix-default. One consequence of this flag is that the echo command does not understand the -n flag.
  • On Linux, the functionality of /bin/sh is implemented by dash which is less strict with respect to POSIX specification. Therefore the flag -n is implemented in the echo command.

BTW, the Makefile buitlin echo command understands the -n flag which explains why the b case always works.

The clean and portable way of fixing your problem is to replace your @echo -n recipes with @printf recipes.

查看更多
We Are One
4楼-- · 2020-05-19 05:27

Something about the quotes confuses make. Your code behaves the same for me, but the following works as expected:

help:
        @echo -n Shouldn\'t print a newline

Hardcoding the path to the executable also works:

help:
        @/bin/echo -n "Shouldn't print a newline"

The Mac OS X man page for echo, while discussing the existence of shell built-in echos, mentions that the echo of sh(1) does not support the -n option, but that fails to explain (to me, anyway) why my first alternative works.


Confirmation that make is using sh to execute the commands by default. In

SHELL = bash
help:
        @echo -n "Shouldn't print a newline"
        @echo -n Shouldn\'t print a newline

both echo statements behave the same (no newlines printed). So without that variable, we have bash pretending to be sh, but evaluating the two lines differently. Question 1: why? Question 2: is the second line the native bash echo or /bin/echo, rather than the emulated sh echo?

查看更多
登录 后发表回答