1

In a Makefile, one can refer to arguments set at the command line at the time one invokes make. For instance, the recipe in a rule might include the command python/subsample.py $(subsample_size), which one invokes at the command line by typing something like make subsample subsample_size=0.1.

I would like to do the same thing with shake. I've written the following rule:

phony "echoEnvVar" $ do
    ev <- fromMaybe "undefined" <$> getEnv "ev"
    liftIO $ putStrLn ev

The problem is that shake is treating the command-line definition of the ev variable as another target:

jeff@jeff-ThinkCentre-M700:~/shake-studies$ stack exec  ./build.sh echoEnvVar ev=whatever
Error when running Shake build system:
* ev=whatever
Error, file does not exist and no rule available:
  ev=whatever
CallStack (from HasCallStack):
  error, called at src/Development/Shake/Internal/Rules/File.hs:180:58 in shake-0.16.4-7UipAYwzJlKKX7fQ0hMQ1b:Development.Shake.Internal.Rules.File

If I instead call that rule with no command-line arguments, it behaves as expected:

jeff@jeff-ThinkCentre-M700:~/shake-studies$ stack exec  ./build.sh echoEnvVar
undefined
Build completed in 0:01m
jeff@jeff-ThinkCentre-M700:~/shake-studies$
Jeffrey Benjamin Brown
  • 3,427
  • 2
  • 28
  • 40

2 Answers2

3

When you say

make subsample subsample_size=0.1

You invoke make with two arguments: subsample and subsample_size=0.1, and with the same environment the rest of your shell is in. make recognizes that subsample_size=0.1 has the form var=value, and it interprets this as a macro definition. Doing so happens to have the same effect as setting an environment variable. Shake does not support taking definitions on the command line, so you must actually set an environment variable.

The way you set the environment variable for Shake will depend on what program you are using to execute Shake. You are invoking Shake through a build.sh. Assuming this doesn't do anything too interesting, the script will pass its own environment to Shake unchanged. You are invoking build.sh through stack exec, which will pass your variable from its own environment unchanged as well (but it does change certain other variables). You are invoking stack exec through your own shell. Assuming that it is a POSIX shell, you can write

ev="Hello World!" stack exec ./build.sh echoEnvVar

to set the ev environment variable during the call to stack. You can also use the export builtin.

HTNW
  • 27,182
  • 1
  • 32
  • 60
1

If what you want is an environment variable then @HTNW's answer is spot on.

If what you really want is configuration options that are available in the program then you can use shakeArgsWith. As an example:

import System.Console.GetOpt

flags = [Option "" ["subsample_size"] (ReqArg readEither) "Set the subsample size (in %)."]

main = shakeArgsWith shakeOptions flags $ \flags targets -> return $ Just $ do
    -- now flags will contain a list of the passed subsample_size values
    ...
Neil Mitchell
  • 9,090
  • 1
  • 27
  • 85