Makefile中的Heredoc?

时间:2011-05-03 17:02:46

标签: makefile gitignore heredoc

这有可能吗?如何?

更新我需要这个,因为我从动态和静态数据创建了一个文件。

用例:我有一个测试目录。每个C文件生成一个测试可执行文件与

SRCS = $(wildcard [a-z]*.c)

我可以根据需要添加新的测试,make会找到新的测试,编译,运行和valgrind它们。我也用git。我希望.gitignore包含可执行文件。

那么。如何创建.gitignore并包含静态数据,即我想要忽略的文件(*.odepend)以及动态可执行文件?

7 个答案:

答案 0 :(得分:22)

另一个GNU Make解决方案。

您可以使用defineexport命令执行此操作,如下所示:

define GITIGNOREDS
*.o
depend
endef

SRCS = $(wildcard [a-z]*.c)
EXES = $(SRCS:.c=)


export GITIGNOREDS
.gitignore: $(SRCS)
    echo $(EXES) | sed 's/ /\n/g' > $@
    echo "$$GITIGNOREDS" >> $@

你必须小心定义块内的扩展(即$(x))。

答案 1 :(得分:8)

是的,你可以。正如其他人所说,你可能不应该,但你可以。 Ash's answer有一个涉及定义命令的解决方案,但这很简洁,并且可以使变量扩展到正确的值变得棘手。另一个技巧是使用.ONESHELL: special target

  

有时您希望将配方中的所有行传递给shell的单个调用。通常有两种情况,这是有用的:首先,它可以通过避免额外的进程来提高makefile中的性能,其中配方由许多命令行组成。其次,您可能希望在配方命令中包含换行符(例如,您可能正在使用与SHELL非常不同的解释器)。如果.ONESHELL特殊目标出现在makefile中的任何位置,则每个目标的所有配方行将提供给shell的单个调用。配方行之间的换行符将被保留。

几句警告:

  • 这将影响Makefile中所有配方的工作方式。
  • 诸如-@之类的行前缀运算符可以抑制输出或忽略错误仅适用于所有配方的第一行,并对所有后续行生效。< / LI>
  • 某些旧版本或GNU Make(例如默认情况下在Travis的CI系统上运行,即使在新容器中)也可能会忽略此指令,从而导致奇怪的错误和陷阱。确保您了解目标环境。

关于这一点,以下是生成降价文件的样子:

SHELL = bash
.ONESHELL:
MYVAR = "Some Title"

file.md:
    cat <<- EOF > $@
        $(MYVAR)
        ========

        This stuff will all be written to the target file. Be sure
        to escape dollar-signs and backslashes as Make will be scanning
        this text for variable replacements before bash scans it for its
        own strings.

        Otherwise formatting is just as in any other bash heredoc. Note
        I used the <<- operator which allows for indentation. This markdown
        file will not have whitespace at the start of lines.

        Here is a programmatic way to generate a markdwon list all PDF files
        in the current directory:

        `find -maxdepth 1 -name '*.pdf' -exec echo " + {}" \;`
    EOF

注意另外一个问题是Make跳空行。如果你的heredoc内容中有一个空行是很重要的,你需要确保用适当的空白级别缩进该行以匹配heredoc,否则Make会吃它而不是将它传递给cat!

答案 2 :(得分:4)

这取决于你的决心。最好假设它不起作用。编写要启动的shell脚本,而不是makefile中的here文档。

失败1

heredoc:
    cat - <<!
    This is the heredoc.
    !

这会产生:

cat - <<!
This is the heredoc.
make: This: No such file or directory
make: *** [heredoc] Error 1

每一行都是单独执行的 - 哎呀。

失败2

heredoc:
    cat - <<! \
    This is the heredoc.\
    !

这产生了:

cat: This: No such file or directory
cat: is: No such file or directory
cat: the: No such file or directory
cat: heredoc.!: No such file or directory
make: *** [heredoc] Error 1

可能有使用特定版本的make的方法(例如,GNU make,可以在单个子shell中执行操作的所有命令,我相信),但是你必须指定你的可移植性要求。对于常规(比如POSIX兼容)make,假设这里的文档不起作用。

答案 3 :(得分:3)

GNU Makefile可以执行以下操作。它很难看,我不会说你应该这样做,但我在某些情况下会这样做。

.profile = \
\#!/bin/sh.exe\n\
\#\n\
\# A MinGW equivalent for .bash_profile on Linux.  In MinGW/MSYS, the file\n\
\# is actually named .profile, not .bash_profile.\n\
\#\n\
\# Get the aliases and functions\n\
\#\n\
if [ -f \$${HOME}/.bashrc ]\n\
then\n\
  . \$${HOME}/.bashrc\n\
fi\n\
\n\
export CVS_RSH="ssh"\n  
#
.profile:
        echo -e "$($(@))" | sed -e 's/^[ ]//' >$(@)

make .profile会创建.profile文件(如果不存在)。

此解决方案用于应用程序仅在POSIX shell环境中使用GNU Makefile的情况。该项目不是一个开源项目,其中平台兼容性是一个问题。

目标是创建一个Makefile,以便于设置和使用特定类型的工作区。 Makefile带来了各种简单的资源,而不需要像其他特殊存档那样的东西等。从某种意义上说,它是一个shell存档。然后,程序可以说将此Makefile放在要处理的文件夹中。设置工作区输入make workspace,然后执行等等,输入make blah等。

什么可能变得棘手的是弄清楚要引用什么。上面做了这个工作,并接近在Makefile中指定here文档的想法。对于一般用途来说,这是一个好主意是另一个问题。

答案 4 :(得分:2)

如果您正在使用Gnu Make,请使用&#39;定义&#39;创建多行文本变量,以及将其回显到文件中的规则。请参见6.8定义https://www.gnu.org/software/make/manual/make.html#Appending

的多行变量

像这样:

  define myvar
  # line 1\nline 2\nline 3\n#etc\n
  endef

  myfile.txt:
         /bin/echo -e "$(myvar)) >myfile.txt

要创建它,有助于使用编辑器,创建您想要的文件,附加&#34; \ n&#34;到每一行的末尾,然后将它们全部连接成一个字符串。将其粘贴到您的makefile中。

在linux上使用GNU Make 3.81进行测试。

答案 5 :(得分:0)

按杰克凯利的要求:

SRCS = (wildcard [a-z]*.c)
EXES = $(SRCS:.c=)
GITIGNOREDS = *.o depend

.gitignore: $(SRCS)
        echo $(EXES) | sed 's/ /\n/g' > $@
        echo $(GITIGNOREDS) | sed 's/ /\n/g' > $@

重要的是GITIGNOREDS行。我更喜欢像

这样的heredoc
GITIGNOREDS = <<EOT
*.o
depend
EOT

但我也很满意文件列表,用空格分隔,以及用于将空格转换为换行符的sed脚本。

编辑正如Ryan V. Bissell所建议的:使用您添加到gitignore的单独的测试子目录。一切都落到了位置。这很简单。

答案 6 :(得分:0)

似乎无法在Makefile中执行here-document。但是,有一种可能的解决方法。使用echo发送here-document数据:

all:
    echo "some text" | myScript.sh