K.Mulier K.Mulier - 1 year ago 124
Bash Question

How to prompt user for [y/n] in my makefile (with pure make syntaxis)?

I am writing a makefile that should work on both Windows and Linux. So wherever possible, I avoid OS-specific shell commands.

Here is a snippet from my makefile with the

function at the end:

# OS specific part
# -----------------
ifeq ($(OS),Windows_NT)
RM = del /F /Q
MKDIR = -mkdir
ERRIGNORE = 2>NUL || (exit 0)
RM = rm -rf
RMDIR = rm -rf
MKDIR = mkdir -p
ERRIGNORE = 2>/dev/null
PSEP = $(strip $(SEP))

# Definitions for nullstring and space
# -------------------------------------
nullstring :=
space := $(nullstring) #End

# Lists of all files and folders to keep or remove
# -------------------------------------------------
buildFiles_toKeep := ... # I wrote some scripts to
buildDirs_toKeep := ... # automatically generate
buildFiles_toRemove := ... # these lists. But that would lead
buildDirs_toRemove := ... # us too far here.

.PHONY: clean
@echo ----------------------------------------------------------
@echo.$(space) __ ************** $(space)
@echo.$(space) __\ \___ * make clean * $(space)
@echo.$(space) \ _ _ _ \ ************** $(space)
@echo.$(space) \_`_`_`_\ $(space)
@echo.$(space) $(space)
@echo.$(space)Keep these files:
@echo.$(space) $(buildFiles_toKeep)
@echo $(space)Keep these directories:
@echo.$(space) $(buildDirs_toKeep)
@echo.$(space)Remove these files:
@echo.$(space) $(buildFiles_toRemove)
$(RM) $(buildFiles_toRemove)
@echo.$(space)Remove these directories:
@echo.$(space) $(buildDirs_toRemove)
$(RMDIR) $(buildDirs_toRemove)
@echo ----------------------------------------------------------

This makefile works great. Both on Windows and Linux, it replaces
with the proper shell commands to delete files and folders. But I would like to prompt the user such that he/she can press Y or N. I would not want to delete files he/she wants to keep. I've tried to insert some batch-commands into the recipees of the
target that prompt the user for input. But the prompt is not shown. Perhaps because GNU make defers the input stream.

I wonder if it is possible to generate a [Y/N] prompt with 'pure' make syntaxis (no OS-specific shell commands). I know that the make language has its limitations. Perhaps a clever solution can work on one operating system (eg. Linux) and be ported with minimal overhead to another (eg. Windows).

Anyone an idea?


I got referred to this link: How do I get `make` to prompt the user for a password and store it in a Makefile variable?

Gnu make will create the variable
by prompting the user:

$ cat Makefile
PASSWORD ?= $(shell bash -c 'read -s -p "Password: " pwd; echo $$pwd')

This way of prompting the user for input works fine as long as you want the prompt to appear at the moment your makefile is parsed. But my case is different. I want to prompt the user when the makefile is already running, in other words, when the recipees in the makefile are executing.


Prompting the user won't be possible when you run make multi-threaded. So I'm perfectly fine with calling the
function single-threaded:

>> make clean -j1

After all, the
function doesn't take long to finish. I do not intend to prompt the user for anything in the
function, so that can be executed multi-threaded :-)

>> make all -j8 --output-sync=target

Answer Source

Conceptually make is a very simple application with one purpose - build a tree of dependencies, and remake stuff that has a newer ancestor. Interaction shouldn't be a factor so make doesn't provide it natively, ideally make should already have all the information it needs. If you really need to you can work around this with shell, !=, or even provide your own extension using guile or load.

This doesn't really apply to the clean rule though, because clean doesn't remake anything in the first place, it's just a quick hack to allow you to conveniently express a non-make operation using make syntax.

Personally I don't see the value of prompting the user on file deletion, unless you're about to delete things you aren't responsible for, which is already an antipattern in itself.

If you're absolutely positive you need this then wrap the clean recipe in a script and provide two versions for bash and windows. You could also just assume that anyone running GNU make on windows is already using MSYS2, Cygwin, or MS's sanctioned release of bash for Windows 10, and forgo the cmd / powershell script altogether.