如何从stdin读取到makefile变量中 [英] how to read from stdin into a makefile variable

查看:93
本文介绍了如何从stdin读取到makefile变量中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要编写一个Makefile来安装go程序和其他资产,所以我想要一个installdir.我想检查是否设置了GOBIN,GOPATH,如果没有设置,希望用户输入安装目录.

I want to write a Makefile to install go program and other assets, so I want a installdir. I want to check if GOBIN, GOPATH is set, if not, want user to enter a installdir.

我写了如下的Makefile,但是makefile变量installdir为空. echo什么也不输出.

I wrote the Makefile as following, but the makefile variable installdir is empty. echo output nothing.

installdir:=$(shell echo $(GOPATH) | cut -d':' -f1)

all: *.go
    @GO111MODULE=on GOPATH=$(GOPATH) go build -o trpc main.go

install:
ifeq ($(installdir),)
    installdir=$(shell echo $(GOBIN) | cut -d':' -f1)
endif
ifeq ($(installdir),)
    installdir=$(shell bash -c 'read -s -p "Please input installdir: " tmpdir; echo $$tmpdir')
endif
    echo $(installdir)

请帮助!

推荐答案

此代码:

install:
ifeq ($(installdir),)
        installdir=$(shell echo $(GOBIN) | cut -d':' -f1)
endif
ifeq ($(installdir),)
        installdir=$(shell bash -c 'read -s -p "Please input installdir: " tmpdir; echo $$tmpdir')
endif
        echo $(installdir)

根本行不通,这是对make运作方式的根本误解.

simply cannot work and represents a fundamental misunderstanding of how make operates.

Make在两个不同的阶段工作: first ,它读取并解析所有makefile,包括的makefile等. Second ,它确定哪些目标已过期和运行配方以更新那些目标.食谱将启动外壳程序,并将食谱文本传递给该外壳程序.当外壳退出时,make通过查看退出代码来确定它是否起作用.整个配方中的所有make变量和函数都首先展开 ,然后在结果上调用shell.此外,配方中的每条逻辑行均以不同的外壳开头.

Make works in two distinct stages: first, it reads and parses all the makefiles, included makefiles, etc. Second, it determines which targets are out of date and runs the recipes to update those targets. Recipes will start a shell and pass the recipe text to that shell. When the shell exits make determines whether it worked or not by looking at the exit code. All make variables and functions in the entire recipe are expanded first, the the shell is invoked on the results. Further, every logical line in the recipe is started in a different shell.

因此,在您的makefile中,随着读入makefile,在第一阶段将解析ifeq选项(它们是makefile构造).配方行直到第二阶段才会运行,因此更改为配方中的变量不会影响ifeq行.此外,make甚至看不到配方中对installdir的更改,因为它们发生在外壳中,然后外壳退出并且这些更改丢失了.

So in your makefile, the ifeq options (which are makefile constructs) are parsed during the first stage, as the makefile is read in. The recipe lines are not run until the second stage, so changes to the installdir variable in a recipe cannot impact the ifeq lines. Further, changes to installdir in a recipe cannot even be seen by make because they happen in a shell, then the shell exits and those changes are lost.

您必须使用 shell 语法编写全部内容,并将其全部放入配方中,如下所示:

You'll have to write this entire thing in shell syntax and put all of it into a recipe, something like this:

install:
        installdir='$(installdir)'; \
        [ -n "$$installdir" ] || installdir=$$(echo $(GOBIN) | cut -d':' -f1); \
        [ -n "$$installdir" ] || read -s -p "Please input installdir: " installdir; \
        echo $$installdir

(未测试).您必须使用shell构造,而不是make构造.实际上,您绝对不应该在配方内使用$(shell ...) make函数:配方已经在外壳中运行.而且,您必须使用反斜杠/换行符对,以确保make将整个配方视为一条逻辑行,否则将不在一行上设置在一行上设置的变量.

(untested). You have to use shell constructs, not make constructs. You should virtually never use the $(shell ...) make function inside a recipe: a recipe is already running in a shell. And you have to use backslash/newline pairs to ensure make considers the entire recipe one logical line, else variables set on one line will not be set on the next line.

最后,我应该指出,这(在make期间读取输入)通常是一个坏主意.例如,如果使用-j选项运行make install,则只有一个配方可以控制stdin,make会随机选择其大小.

Finally, I should point out that this (reading input during make) is just generally a bad idea. For example, if you run make install with the -j option, only one recipe can have control of stdin and make will choose more-or-less randomly which it is.

通常,您希望用户通过以下方式在命令行中传递值:

Generally instead you want to have the user pass the value on the command line, with something like:

$ make installdir=my/dir

因此,您在Makefile中签入的内容应该是这样的:

so your check in the makefile should instead be something like this:

install:
        installdir='$(installdir)'; \
        [ -n "$$installdir" ] || installdir=$$(echo $(GOBIN) | cut -d':' -f1); \
        [ -n "$$installdir" ] || { echo "Please add installdir=... on the command line"; exit 1; }; \
        echo $$installdir

这篇关于如何从stdin读取到makefile变量中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆