Philip Walton
Philip Walton

Reputation: 30431

Problems setting PATH in Makefile

I'm new to make and Makefiles, but I'm trying to create one for my next project and I'm running into PATH issues. I keep getting the error: "No such file or directory"

I've created a simple target called test that runs all my tests using mocha.

Mocha is installed as a local node module, so its executable can be found at ./node_modules/.bin/mocha. I'm altering my PATH as described in this make tutorial so I can refer to it as mocha instead of typing the full path, but something doesn't seem to be working.

Here's what I have so far:

export PATH := node_modules/.bin:$(PATH)

test:
    which mocha
    mocha

.PHONY: test

When I run make test I get the following output:

which mocha
node_modules/.bin/mocha
mocha
make: mocha: No such file or directory
make: *** [test] Error 1

As you can see from the output, which mocha is correctly printing the path to the mocha executable, but when I simply run mocha, it can't find it.

What am I doing wrong? Is there bigger picture about variable scope or persistence in Makefiles that I'm missing?

P.S. If it's important, I'm using a Mac and the version of make that comes with the XCode developer tools. This is what I get when I run make -v

GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

This program built for i386-apple-darwin11.3.0

Upvotes: 13

Views: 14238

Answers (5)

arielf
arielf

Reputation: 5952

I'm using GNU make version 4.1 on Ubuntu 16.04.4

I had a similar issue and none of the suggested solutions worked for me.

Settings to PATH do not seem to be in effect when later variable settings take place (at least in this version of make).

export PATH := /usr/local/bin:/bin:/usr/bin
# Path setting is not in effect here, 'which' returns an empty string
# even when 'vw' is installed in /usr/local/bin/vw 
VW = $(which vw)

The solution that worked for me was to inject the earlier PATH setting explicitly into the particular sub-shell used to assign a later make variable, like this:

VW = $(shell env PATH=$(PATH) which vw)

The following Makefile example demonstrates the case that works vs the one that doesn't:

SHELL := /bin/bash
export PATH := /usr/local/bin:/bin:/usr/bin

# Expecting 'vw' to be found, due to PATH setting above
#       ('vw' is in /usr/local/bin/vw)

VW_NOT_OK = $(which vw)
VW_OK = $(shell env PATH=$(PATH) which vw)

all:
        # -- Doesn't work:
        @echo "VW_NOT_OK='$(VW_NOT_OK)'"
        # -- Works:
        @echo "VW_OK='$(VW_OK)'"

Reproducing the problem and solution:

$ make --version| head -1
GNU Make 4.1

$ make
# -- Doesn't work:
VW_NOT_OK=''
# -- Works:
VW_OK='/usr/local/bin/vw'

Upvotes: 3

kenorb
kenorb

Reputation: 166319

This should work:

PATH  := $(PATH):$(PWD)/node_modules/.bin
SHELL := env PATH=$(PATH) /bin/bash

Upvotes: 2

tom
tom

Reputation: 718

In OSX you also need to also set SHELL:

PATH  := node_modules/.bin:$(PATH)
SHELL := /bin/bash

Upvotes: 13

MadScientist
MadScientist

Reputation: 100781

I can't reproduce your results (using GNU make 3.81 on a GNU/Linux system). It appears that there may be some difference in either the way the Apple system works, or that Apple has made some kind of patch to the GNU make version they ship that is causing this problem.

GNU make has two ways of running recipes: the normal way, where it invokes a shell and passes the recipe to the shell to be run, and the "fast path", where, if make sees that the command is "simple enough" (that is if it contains no shell special characters), it will chop up the command into words and directly execute the command without invoking the shell. The latter is much faster, but since it's being invoked directly it inherits the PATH setting from GNU make itself not from the shell.

It appears that for some reason the version of GNU make shipped by Apple is not working properly in that it's not setting the environment correctly for commands which are run directly by GNU make, via the "fast path".

I have a very vague recollection of something like this being discussed on the GNU make mailing lists, but after spending some time searching I wasn't able to come up with anything.

You can "fix" this problem by forcing your command to use the slow path, by introducing some shell special characters (globbing, ;, pipes, etc.). Or you can use a fully-qualified path to the program.

Or, you can go get the source code for GNU make and build it yourself; if this difference is a result of a "fix" by Apple that should make it work better. Or install GNU make from homebrew or ports, which will also get you a newer version with more features, I expect.

Upvotes: 12

G.G.
G.G.

Reputation: 674

I am afraid that you can't do that Try with "local" variables instead

NODE_MODULES := node_modules/.bin

test:
    @ $(NODE_MODULES)/mocha

Upvotes: 0

Related Questions