Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Makefile `echo -n' not working

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.

like image 611
Chris Avatar asked Jul 26 '12 17:07

Chris


People also ask

How do you make an echo in Makefile?

Let's create a small Makefile to see how make executes it: $ cat Makefile all: foo bar foo: printf "%s\n" "Target foo executing..." printf "%s\n" "Hello from foo!" bar: printf "%s\n" "Target bar executing..." printf "%s\n" "Hello from bar!"

What does @echo mean in Makefile?

The ' @ ' is discarded before the line is passed to the shell. Typically you would use this for a command whose only effect is to print something, such as an echo command to indicate progress through the makefile: @echo About to make distribution files.

How to suppress output of makefile?

If you want to inhibit the display of commands during a particular make run, you can use the -s option. If you want to inhibit the display of all command lines in every run, add the special target . SILENT to your makefile .


2 Answers

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.

like image 75
Nicolas Dudebout Avatar answered Oct 03 '22 23:10

Nicolas Dudebout


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. Make manual 5.3.2 Choosing the Shell specifies this hehavrior:

The program used as the shell is taken from the variable SHELL. If this variable is not set in your makefile, the program /bin/sh is used as the shell. The argument(s) passed to the shell are taken from the variable .SHELLFLAGS. The default value of .SHELLFLAGS is -c normally, or -ec in POSIX-conforming mode.

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?

like image 33
chepner Avatar answered Oct 04 '22 00:10

chepner