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
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
This is weird.. What happens if you remove the line export PATH := node_modules/.bin:$(PATH) and run make like this : $ PATH=node_modules/.bin:$PATH make test Is it working ?
5 Answers 5
In OSX you also need to also set SHELL:
PATH := node_modules/.bin:$(PATH) SHELL := /bin/bash
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.
Specifying path to «makefile» using «make» command
I would like to run a makefile from another place in the file system. How do I pass the location of the makefile to make? if I stand in «/» and I would like to run a makefile that resists in «/dir/dir2/dir3/makefile», how do I add that to the make command? I tried:
make --file=dir/dir2/dir3/makefile
ok, so -C is not guaranteed to work? I can’t make it work with /lfs/ampere4/0/brando9/proverbot9001/CompCert/configure x86_64-linux && make clean -C /lfs/ampere4/0/brando9/proverbot9001/CompCert only ./configure x86_64-linux && make seems to work.
2 Answers 2
All relative paths in the makefile will be relative to your current directory and not the directory of the makefile.
Assuming that you understand that and what you want to do is still going to work then you want the -f flag to specify the makefile to use. (Which is in the man page, the manual and the —help output.)
If, instead, what you mean is you want to cd to somewhere else and run make then perhaps you are looking for (cd /some/path && make) ?
Maybe the cd suggestion fits best. I guess that, the difference is whether I want the compiled files to be in the same folder as the make file (which would be the cd example), or if I want the files to be in the same dir where I stand. Am I right?
More than that. If you have a rule in the makefile that says foo: foo.c that will create a file foo in the current directory but will also look for foo.c in the current directory and it isn’t going to be there.
I have been messing around with my Makefile trying to get make to recognize CFLAGS arguments I specified therein. But it didn’t seem those args were getting passed to make . So I removed my local Makefile and ran make again, and it continued to run the same command ( cc -o ex4.c -o ex4 ). I was trying to pass -g -Wall via CFLAGS . Is there some master Makefile hanging around my OS?!
Adding directory to PATH through Makefile
I’m having some trouble in exporting the PATH I’ve modified inside the Makefile into the current Terminal. I’m trying to add to the PATH, the bin folder inside wherever the Makefile directory is. Here’s the relevant strip of the makefile:
PATH := $(shell pwd)/bin:$(PATH) install: mkdir -p ./bin export PATH echo $(PATH)
5 Answers 5
You simply can’t do this. There’s no way¹ the make process can change its parent’s environment (or its current directory, which you might be thinking of next).
In fact, even less is happending than you think.
- Not all make implementations reflect the assignment to the make PATH variable in the environment; GNU make (found on Linux and other systems) does, but BSD make doesn’t.
- Each command line under a target runs in a separate subshell. (Except in some older BSD make implementations.) So the export PATH line is running on a shell that terminates immediately afterwards. Not that this line would be doing anything in the first place — if PATH is defined at that point, it’s because it’s in the shell’s environment already.
Make is for building things automatically. If you want to set variables for your interactive environment, this isn’t the tool you should be looking at. Instead, write a shell snippet, and source it in the current shell:
In your makefile, source the script in every subshell. You can use a backslash to make a long command; remember that
- The backslash-newline sequence is stripped by make, so the shell won’t see a newline there.
- Remember to prefix each line by a tab nonetheless.
- Make’s error behavior is to abort if a command fails. The shell won’t do that by default, and the failure of any command but the last will go unnoticed by default, so you need to run set -e .
install: set -e; \ . ./define-my-variables.sh; \ mkdir -p bin; \ …
¹ Obligatory note: no sane way. Even remotely invoking chdir via ptrace from a debugger won’t work as is with most shells because they don’t like to have their current directory changed under their feet.
How I could add dir to $PATH in Makefile?
I want to write a Makefile which would run tests. Test are in a directory ‘./tests’ and executable files to be tested are in the directory ‘./bin’. When I run the tests, they don’t see the exec files, as the directory ./bin is not in the $PATH. When I do something like this:
EXPORT PATH=bin:$PATH make test
test all: PATH=bin:$ @echo $(PATH) x
Can you not just call the tests from the executable directory like ../test/test_to_run ? Sorry if I have misunderstood the question.
I want this file to be visible to the tests normally. I don’t want to play with the directories, as I refactoring that would be a nighmare.
The only way you can come close to this is to have the makefile write out a shell script containing the variable decls and then have the parent shell source that script with . . This is probably impractical however.
I believe that unix.stackexchange.com/questions/11530/… is a very different (stupid) question, unlike yours.
5 Answers 5
Did you try export directive of Make itself (assuming that you use GNU Make)?
export PATH := bin:$(PATH) test all: x
Also, there is a bug in you example:
test all: PATH=bin:$ @echo $(PATH) x
First, the value being echo ed is an expansion of PATH variable performed by Make, not the shell. If it prints the expected value then, I guess, you’ve set PATH variable somewhere earlier in your Makefile, or in a shell that invoked Make. To prevent such behavior you should escape dollars:
test all: PATH=bin:$$PATH @echo $$PATH x
Second, in any case this won’t work because Make executes each line of the recipe in a separate shell. This can be changed by writing the recipe in a single line:
test all: export PATH=bin:$$PATH; echo $$PATH; x
UNIX for Dummies Questions & Answers
100, 2
I would like to install a binary from source on a custom path, say /usr/local/myapps. There is no —prefix option in ./configure How can I «make install» at custom path. I tried this.
No --prefix root@server [/usr/src/libvpx-v1.1.0]# ./configure --help | grep prefix root@server [/usr/src/libvpx-v1.1.0]#
Make install root@server [/usr/src/libvpx-v1.1.0]# make install INSTALL_PATH=/usr/local/myapps [INSTALL] /usr/local/lib/libvpx.a [INSTALL] /usr/local/lib/libvpx.so.1.1.0 [LN] /usr/local/lib/libvpx.so [INSTALL] /usr/local/lib/pkgconfig/vpx.pc [INSTALL] /usr/local/bin/vpxdec [INSTALL] /usr/local/bin/vpxenc [INSTALL] /usr/local/bin/vp8_scalable_patterns make[1]: Nothing to be done for `install'.
6,384, 2,214
Obviously your make-file has no provisions for doing this. You will have to change (extend) it to do so. «make install» calls the command «make» which in turn uses its default rule file, «./Makefile». Have a look into this file and change the rules/actions under the target «install» according to your needs.
100, 2
I have doubt in the flags I set while I compile. For Eg. I compiled an extra library required for ffmpeg (libdc1394) at /usr/local/myapps/lib/libdc1394.so. I then set these ENV variables and compile ffmpeg using the below option.
LIBS=-L/usr/local/myapps/lib/ export LIBS PKG_CONFIG_PATH=/usr/local/myapps/lib/pkgconfig/ export PKG_CONFIG_PATH LDFLAGS=-L/usr/local/myapps/lib/ export LDFLAGS CPPFLAGS=-I/usr/local/myapps/include/ export CPPFLAGS PATH=/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin::/root/bin:/usr/local/myapps/bin export PATH
./configure --enable-libdc1394 make make install
# cat /usr/local/myapps/lib/pkgconfig/libdc1394-2.pc prefix=/usr/local/myapps exec_prefix=$ libdir=$/lib includedir=$/include Name: libdc1394 Description: 1394-based DC Control Library Version: 2.1.3 Libs: -L$ -ldc1394 Cflags: -I$
Ffmpeg binary compiled fine. But when I checked «/usr/local/myapps/bin/ffmpeg -v» with strace, I could find, it not taking the /usr/local/myapps/lib/libdc1394.so. It takes «/usr/lib/libdc1394.so.22». Please see the corresponding line in strace output.
open("/usr/lib/libdc1394.so.22", O_RDONLY) = 3
I need the /usr/local/myapps/lib/libdc1394.so.22 being used during ffpmeg install. There is NO option like «—enable-libdc1394=/path/to/libdc1394»