This issue is not unique to make
. Make executes commands in the context of a shell, and that shell can execute functions if they've been made available.
The problem is that when you launch a new shell (or shell script, or make command), Bash doesn't automatically forward all functions from the calling environment.
Explicitly specifying that the shell should be /bin/bash
ensures that make won't invoke a different shell interpreter, which could affect function handling. There are a couple ways of doing this. In the examples below, I use the targeted-specific approach.
As an example, the below makefile snippets invoke nvm
which is implemented as a collection of bash functions.
WARNING: Using previously-defined functions means the makefile depends on the (potentially uncontrolled) state of your shell environment, so this type of solution should be used judiciously.
Method 1: Run an "interactive" shell
In this example, the functions are assumed to be defined as part of a users's .bashrc file. Running Bash in interactive mode (with -i
) causes .bashrc to be processed into the command environment.
mytarget1: SHELL:=/bin/bash -i
mytarget1:
nvm install 14 && npm version
Method 2: Import the functions on demand
This approach explicitly sources the script that defines the functions of interest.
mytarget2:
. ~/.nvm/nvm.sh && nvm install 14 && npm version
For this, you might prefer:
Multi-line bash commands in makefile
Method 3: Export the function before running makefile
Invoke make
with: export -f nvm ; make mytarget3
to export the function to any sub-commands.
mytarget3: SHELL:=/bin/bash
mytarget3:
nvm install 14 && npm version
Note: This example won't work fully because nvm
, internally, relies on a large collection of sub-functions which would also need to be exported.