Set a target based on binary that may or may not exist in $ PATH

I want to add a Make object that runs a program with envdir.

ENVDIR := $(shell command -v envdir) serve: | $(ENVDIR) $(ENVDIR) /usr/local/myservice/env python -m SimpleHTTPServer 8000 

The idea is that if the user does not have envdir installed, he will install it for them. I need a channel symbol because I don't always want it to start; I just want some version of it to be present. Unfortunately, I cannot accurately predict where envdir will be installed.

 UNAME := $(shell uname) $(ENVDIR): ifeq ($(UNAME), Darwin) brew install daemontools endif ifeq ($(UNAME), Linux) sudo apt-get install daemontools endif # Add other operating systems here as appropriate... 

Another problem that I am facing is that if the user does not have envdir installed, the variable is evaluated with an empty string. So, a) My target install of “install envdir” does not actually start, and b) after it starts, $ (ENVDIR) is still set to an empty line, so loading it into the target service does not work.

Is there a way: a) to get the installation target, even if ENVDIR is undefined and b) to override the value of the variable at the end of the target install "install envdir" run?

Please do not answer “why you use envdir” - I am facing this problem with various different binaries that I rely on, it just turned out to be an easily accessible example.

+5
source share
2 answers

You can do this completely in a shell like this:

 ENVDIR := $( command -v envdir 2> /dev/null || ( install envdir > /dev/null && echo newEnvDirPath ) ) 

This is easiest, but causes the installation of envdir , even if it is not required for the current purpose. If you want it on target, you can do something like:

 ENVDIR:=$(cat .ENVDIR 2> /dev/null) $(type -v $(ENVDIR) > /dev/null || rm .ENVDIR ) .ENVDIR: command -v envdir 2> /dev/null > $@ || ( install envdir > /dev/null && echo newEnvDirPath > $@ ) $(eval ENVDIR:=$$(cat $@ )) shell: | .ENVDIR 

If the .ENVDIR file .ENVDIR not exist, it will run a recipe that will either write the installed path to .ENVDIR or install and write a new path to .ENVDIR . In any case, when the recipe line ends, .ENVDIR will contain the executable path. The target then runs $(eval) to install envdir . Note that the eval call causes the makefile to redraw, which is not ideal, but should only be done once on the system. (Also note the double $$ before the cat command, which does not allow make to extend this while reading ...).

Alternatively, if .ENVDIR exists, it will read the file to determine which envdir will try to use. The check is performed on the next line to make sure that this version still exists in the system, and if not, it deletes the file, forcing it to be recreated.

+1
source

For an “empty” problem, you can do this:

 ENVDIR := $(or $(shell command -v envdir),envdir) 

so if the shell function expands to an empty string, envdir will be replaced (the or function was added in GNU make 3.81). This will probably be enough to solve all your problems, because after installing in PATH the envdir command will now appear, so you do not need the full path.

0
source

Source: https://habr.com/ru/post/1271380/


All Articles