Can you make valid Makefiles without tab characters?
Asked Answered
B

11

136
target: dependencies
    command1
    command2

On my system (Mac OS X), make seems to require that that Makefiles have a tab character preceding the the content of each command line, or it throws a syntax error.

This is an annoyance when creating or editing Makefiles because I have my editor set up to be all-spaces-all-the-time.

Can you make valid Makefiles without tab characters?

Bandog answered 25/1, 2010 at 9:15 Comment(0)
F
137

This is a syntax oddity/requirement of make, it has nothing to do with Mac OS X. Unfortunately, there's nothing you can do about it if you are going to use make.

Edit: GNU Make now supports a custom recipe prefix. See this answer.

You are not the first one to dislike this aspect of make. To quote Unix Haters' Handbook:

The problem with Dennis’s Makefile is that when he added the comment line, he inadvertently inserted a space before the tab character at the beginning of line 2. The tab character is a very important part of the syntax of Makefiles. All command lines (the lines beginning with cc in our example) must start with tabs. After he made his change, line 2 didn’t, hence the error.

“So what?” you ask, “What’s wrong with that?”

There is nothing wrong with it, by itself. It’s just that when you consider how other programming tools work in Unix, using tabs as part of the syntax is like one of those pungee stick traps in The Green Berets: the poor kid from Kansas is walking point in front of John Wayne and doesn’t see the trip wire. After all, there are no trip wires to watch out for in Kansas corn fields. WHAM!

Fleetwood answered 25/1, 2010 at 9:19 Comment(6)
The issue with tabs is one of the first thing anyone using make learns - I've never found it to be a real problem.Woolgrower
@Neil, Me neither: I never said I agreed with the UHH, I was just saying some people don't like it. :-)Fleetwood
Seems like a good plug for using cmake. Not the only frustrating oddity in make syntax.Strikebound
I just found gnu.org/software/make/manual/html_node/Special-Variables.html (see .RECIPEPREFIX). One of the answers below also mentions that, and should be marked as "correct" instead of mine. stackoverflow.com/a/21920142Fleetwood
It's not a huge problem, but it is annoying. Each and every time. It is reliably annoying, and it is annoying in \omicron linear time.Toxin
Funny remark about make and tabs in the first point of this article :) "He did it this way, as he didn’t think that make would be used by anyone except for this small group of people. Later came the idea that make was a good thing and it would be nice to include it into the standard UNIX package. In order not to break the already written makefiles, (meaning written by these ten people), he decided not to change anything. Well, that’s how it goes… We all suffer because of those ten guys."Copycat
T
69

In the time since this question was originally asked, a version of GNU Make has been released that allows you to use something other than Tab as the prefix character. From the mailing list announcement:

New special variable: .RECIPEPREFIX allows you to reset the recipe introduction character from the default (TAB) to something else. The first character of this variable value is the new recipe introduction character. If the variable is set to the empty string, TAB is used again. It can be set and reset at will; recipes will use the value active when they were first parsed. To detect this feature check the value of $(.RECIPEPREFIX).

This feature was added in GNU Make 3.82, released in July 2010 (six months after this question's original ask date). Since it has in turn been three years and change since that, it's likely that other Make flavors have followed GNU Make.

Thrombus answered 20/2, 2014 at 21:36 Comment(3)
aaaand my up-to-date Mac OSX still uses version 3.81 from 2006. Totally unexpected.Chengteh
aaaand my up-to-date Mac OSX still uses version 3.81 from 2006. In 2021. You can update this with Homebrew but still.Tensiometer
Apple still uses GNU make? Seems they haven't found a suitable replacement yet…Estreat
G
56

There is a convoluted way of have a valid makefile without tabs.

If you change your makefile to read:

target: dependencies; command1; command2

If will work. If you want it on more than one line, then you can do:

target: dependencies; \
command1; \
command2

Messy, but it works.

Gauntlett answered 11/12, 2010 at 22:39 Comment(1)
Upgrading to a version of Make that supports .RECIPEPREFIX is probably the best approach. However, since I didn't feel like doing that, I ended up using a solution based on this one. Line 1: target:\ , Line 2: [four-space indentation] followed by ;commandSwung
R
37

If you have a vimrc in your profile you can add this line to prevent vim from changing to spaces:

autocmd FileType make setlocal noexpandtab

I too was struggling with this, and this fixed it for me. Spread the good word!

Rafat answered 14/10, 2013 at 2:20 Comment(0)
K
22

Try (note the space at the end):

.RECIPEPREFIX +=

Knit answered 5/10, 2014 at 7:8 Comment(7)
What version of make supports this? This doesn't work in GNU Make 4.1.Charteris
GNU Make 4.1 Built for x86_64-pc-linux-gnu i'm sorry but it does workPandorapandour
probably, it needs to mentioned, that this variable needs to be declared inside make file itself (prefixing dot easy not to spot)Pemberton
At least in version 4.2, this should work. The documentation says in the explanation of .RECIPEPREFIX that "If the variable is empty (as it is by default) that character is the standard tab character." This means the variable is defined by default. It is confirmed by using ifeq ($(origin .RECIPEPREFIX), undefined). Because += append a single space and the rhs to the lhs, var += sets var to a single space (plus an empty string) as long as var has already be defined. (If var isn't defined, += is the same as =.)Righthanded
If .RECIPEPREFIX isn't defined by default (though I don't know whether actually there is such a version of GNU Make), you can write .RECIPEPREFIX = right before .RECIPEPREFIX +=. The first definition create the variable (this is the important part) and set its value to null. Another technique to set any variable to whitespace(s) is explained here.Righthanded
This answer no longer works. See my answer for the latest solution.Righthanded
link is broken :(Egregious
T
15

If you are using EditorConfig, you can add the following lines to your .editorconfig file to force your IDE to use tab for indentation instead of spaces in Makefile:

[Makefile]
indent_style = tab
Tithonus answered 28/2, 2017 at 13:45 Comment(0)
C
14

In vim's insert mode, one can use Ctrl-v <TAB> to insert a literal tab, even if you have set the tab key to insert spaces. This doesn't answer your question, of course, but might be an alternative to the methods available to avoid needing literal tabs.

Calf answered 15/8, 2013 at 19:59 Comment(1)
This works for me... Awesome, after many years :)Presentment
R
13

Until GNU Make 4.2

Steven Penny's answer works.

.RECIPEPREFIX +=

The reason why this works is described in my comment.


Since GNU Make 4.3 (released on 19 Jan 2020)

Behavior of += operator has been changed in a backward-incompatible way. If the left operand has an empty value, a space is no longer added.

You can instead use

.RECIPEPREFIX := $(.RECIPEPREFIX)<space>

, where <space> is a single space. Although $(.RECIPEPREFIX) is expanded as an empty value, this is needed not to let GNU Make ignore <space>. Note this code works even on GNU Make older than version 4.3.

(For an essentially same but more readable solution, see @milahu's comment.)

Righthanded answered 23/2, 2020 at 14:20 Comment(4)
This is kinda crazy, given the above-mentioned fact that tabs were originally used to preserve backwards compatibility for 10 people!Chengteh
Thx! Now I can use gmake(version 4.4) with spaces on my Mac!Yucca
see also Special Characters to define a space variableBloated
trailing whitespace is bad. the shortest solution is .RECIPEPREFIX := $() #. the most popular solution on github is .RECIPEPREFIX := $(.RECIPEPREFIX) $(.RECIPEPREFIX)Bloated
G
2

in ubuntu: vi Makefiles replace space by tab (or anything else you want):

:%s/<space chars>/^I/g

For ex replace 8 spaces by tab:

:%s/        /^I/g

Be attention: ^I insert with tab key, not ^ and I characters :D

Galaxy answered 14/1, 2020 at 8:28 Comment(0)
A
1

The cleanest way to cause make to use spaces instead of tabs is:

.RECIPEPREFIX := $() $()
  • Makes no assumption about the previous value of .RECIPEPREFIX.
  • Requires no space at end of line.
  • Easy for a beginner to understand.
Artemas answered 29/9, 2023 at 17:46 Comment(0)
W
-6

Not portably. Certain flavours of make absolutely require tab characters. Yet another reason for preferring tabs over spaces :-)

Woolgrower answered 25/1, 2010 at 9:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.