我想用输入变量运行makefile。我想要的是,如果我写下项目名称,将创建一个具有该名称的文件夹。
所以我写
read
命令:
CC = gcc
CFLAGS = -W -Wall
FILE := hi
src = $(wildcard *.c)
OBJ = $(src:.c=.o)
all : $(FILE)
$(FILE) : $(OBJ)
$(CC) $(CFLAGS) -o $@ $^
.PHONY: clean
clean :
rm *.o $(FILE)
move :
mkdir -p ../../bin/$(FILE);
mkdir -p ../../exe/$(FILE);
mv *.o ../../bin/$(FILE);
mv $(FILE) ../../exe/$(FILE)
afterclean :
rm ../../bin/$(FILE)/*.o;
rm ../../exe/$(FILE)/$(FILE)
execute :
./../../exe/$(FILE)/$(FILE)
read :
@read -p "Enter : " enter; \
$(FILE) := enter; \
echo $FILE
我想做的是如果我通过
FILE
获得read
名字我想改变FILE
变量,但我不能改变它。我该怎么做?
简而言之,您不能轻易做到这一点(您可能不想这样做,向下滚动以了解基本原理)。如果你仔细看看你的
Makefile
你会发现你混合了 make
和 shell 语法......以及它们的上下文。
在你的例子中,它从字面上将以下字符串传递给 shell(
SHELL
的值,可能默认为 /bin/sh
)和 -c
:
read -p "Enter : " enter; \
hi := enter; \
echo ILE
显示了混合语法的效果。
$(FILE)
(值 hi
)和 $F
(未设置 -> 空)是在调用 shell 之前由 make 替换的 make 变量。 (虽然根本没有使用 read
到 enter
变量,而是使用文字字符串 enter
尝试在正在运行的 shell 中进行变量分配。)
如果你想运行一个 shell 命令并从它所做的/学到的东西中分配一个值给 make 变量,你必须使用
shell
函数(或者生成一个(临时)文件你会 include
,但这更混乱):
FILE := $(shell read -p "Enter: " enter ; echo $${enter})
然而,这总是会问......除非你使用条件赋值(
?=
),在这种情况下你可以从命令行中选择(make FILE=something
,此时我们即将关闭圆圈)。我通常不确定您的意图是如何告诉make
何时询问以及何时使用hi
的默认值。
这让我明白为什么这个概念一开始对我来说听起来很可疑,以及为什么 @HolyBlackCat 提出的建议是自定义调用
make
. 的更好方式
此外,任何运行时用户交互通常都会破坏自动化(这是我们
make
的目的)并且还会使构建不可重现。因此,最好避免使用它们。
换句话说,如果你真的需要,我会说为这种类型的调用写一个
interactive_make_call.sh
:
#!/bin/bash
read -p "Enter : " enter
make FILE="${enter}" "$@"
甚至:
#!/bin/bash
read -p "Enter : " enter
if [[ -n "${enter}" ]] ; then
make FILE="${enter}" "$@"
else
make "$@"
fi
如果您只需按
enter,则从
FILE
回退到Makefile
的默认值。
这与其说是对原始发帖人问题的回答,不如说是澄清:是的, 可以在 Makefile 配方中读取用户输入。您只是不能指望从
read
读取的值会传播到 Makefile 中的其他配方,而没有其他令人震惊的杂乱无章,例如 $(eval …)
,或写入临时文件或类似的东西。
这是 OP 试图在
read
目标中完成的正确语法,并带有上述警告:
read :
@read -p "Enter : " enter; \
echo $$enter
回想一下 make 的默认行为是在其自己的 shell 中运行配方的每一行;作为副作用,
$enter
的值在分号-反斜杠停止后失去范围。所以它的生命周期只存在于 Makefile 中的那条语句中。
额外的琐事:如果您已经定义了
SHELL = bash
,那么就没有必要分配一个变量来保存回复;默认情况下使用环境变量REPLY
。但是,Bourne shell 并非如此,我不能代表其他 shell。