Can you make valid Makefiles without tab characters?

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?

68931 次浏览

这是 make的一个语法怪异/需求,它与 Mac OS X 没有任何关系。不幸的是,如果你要使用 make,你也无能为力。

编辑 : GNU Make 现在支持自定义配方前缀。

你不是第一个不喜欢 make这方面的人。引用 Unix 仇恨者手册:

Dennis 的 Makefile 的问题在于,当他添加注释行时,他无意中在第2行开头的制表符前面插入了一个空格。Tab 字符是 Makefiles 语法中非常重要的一部分。所有命令行(在我们的示例中以 cc 开头的行)必须以制表符开头。在他进行了更改之后,第2行没有进行更改,因此出现了错误。

“那又怎样?”你问,“那有什么问题?”

它本身并没有什么问题。只是当你考虑到其他编程工具在 Unix 中是如何工作的时候,使用制表符作为语法的一部分就像是绿色贝雷帽(书籍)中的一个尖刺陷阱: 一个来自堪萨斯州的可怜孩子走在约翰 · 韦恩面前,却没有看到绊网。毕竟,在堪萨斯的玉米地里没有绊网需要小心。砰!

不便于携带。某些风味的 make 绝对需要制表符。另一个选择制表符而不是空格的原因: -)

有一种复杂的方法可以不使用制表符来获得有效的 makefile。

如果将 makefile 更改为:

target: dependencies; command1; command2

如果你想在多行上使用它,那么你可以这样做:

target: dependencies; \
command1; \
command2

乱七八糟,但很管用。

在 vim 的插入模式下,可以使用 Ctrl-v <TAB>插入一个文字制表符,即使您已经设置了制表符键来插入空格。当然,这并不能回答您的问题,但是可以替代可用的方法,以避免需要文字选项卡。

如果你的配置文件中有一个 vimrc,你可以添加这一行来防止 vim 变成空格:

autocmd FileType make setlocal noexpandtab

我也在为此而挣扎,而这为我解决了这个问题。传播这个好消息!

自从最初提出这个问题以来,GNUMake 的一个版本已经发布,它允许您使用 Tab以外的东西作为前缀字符。返回文章页面

新的特殊变量: . RECIPEPREFIX 允许您重置配方 从默认值(TAB)到其他值的引入字符 这个变量值的第一个特征是新配方的介绍 如果变量设置为空字符串,则再次使用 TAB。 它可以随意设置和重置; 当 要检测这个特性,请检查 $(. RECIPEPREFIX)的值。

这个特性是在 GNU Make 3.82中添加的,于2010年7月发布(比这个问题最初的提问日期晚了6个月)。由于它已经反过来三年和变化,从那以后,它很可能是其他制造口味跟随 GNU 制造。

如果你想使用空格,这样就可以了

.RECIPEPREFIX +=

例子

如果使用的是 编辑配置,可以在 .editorconfig文件中添加以下代码行,以强制 IDE 使用制表符进行缩进,而不是使用 Makefile中的空格:

[Makefile]
indent_style = tab

在 ubuntu 中: vi Makefiles 用制表符替换空格(或者任何你想要的东西) :

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

用制表符替换8个空格:

:%s/        /^I/g

请注意: ^ I插入标签键,而不是 ^字符: D

直到 GNU 制造4.2

Steven Penny 的回答很有效。

.RECIPEPREFIX +=

我的评论中描述了这样做的原因。


自从 GNU Make 4.3 (2020年1月19日发布)

+=操作符的行为一直是 变了向后不兼容的。如果左操作数的值为空,则添加一个空格 不再是了

你可以用

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

,其中 <space>是一个单一的空间。虽然 $(.RECIPEPREFIX)被展开为一个空值,但是不要让 GNUMake 忽略 <space>。注意,这段代码甚至可以在 GNU Make 上使用,使用时间超过4.3版本。