I can easily read an environment variable using System.Environment.getEnv
. However, System.Environment
does not have any corresponding setEnv
function (as far as I could tell).
How do I set an environment variable from a Haskell program? I would prefer a cross-platform solution. (So just executing export VAR=val
or using System.Posix.Env
is not quite what I'm looking for.)
cross-env makes it so you can have a single command without worrying about setting or using the environment variable properly for the platform. Just set it like you would if it's running on a POSIX system, and cross-env will take care of setting it properly. Installation. Usage.
To set an environment variable, use the command " export varname=value ", which sets the variable and exports it to the global environment (available to other processes). Enclosed the value with double quotes if it contains spaces. To set a local variable, use the command " varname =value " (or " set varname =value ").
Note that base 4.7.0 now has a setEnv
in System.Environment
. So for the present or near future it's sorted out.
However if you need this feature in versions <4.7.0 (which is my case currently), I have also extracted from the commit that adds the feature the functions needed to make this work with an older base version.
However I seriously lost patience on this one and did it rather ugly but it works for me...
The mess is that there are 3 functions to call in a windows environment: putenv
, SetEnvironmentVariableA
(ASCII) and SetEnvironmentVariableW
(widechar, utf16). The patch that was committed to base 4.7 does this automatically, but I did something more ugly by lack of time (I may yet it clean it up).
Here's what I have:
setEnv_ :: String -> String -> IO ()
setEnv_ key value = withCString key $ \k -> withCString value $ \v -> do
success <- c_SetEnvironmentVariable k v
unless success (throwGetLastError "setEnv")
putEnv :: String -> IO ()
putEnv v = void (withCString v $ \vv -> c_putenv vv)
foreign import stdcall unsafe "windows.h SetEnvironmentVariableA"
c_SetEnvironmentVariable :: CString -> CString -> IO Bool
-- SetEnv_ :: String -> String -> IO ()
-- SetEnv_ key value = withCWString key $ \k -> withCWString value $ \v -> do
-- success <- c_SetEnvironmentVariable k v
-- unless success (throwGetLastError "setEnv")
--
-- Foreign import stdcall unsafe "windows.h SetEnvironmentVariableW"
-- c_SetEnvironmentVariable :: LPTSTR -> LPTSTR -> IO Bool
foreign import ccall unsafe "putenv" c_putenv :: CString -> IO CInt
Obviously use CPP
to put the whole thing in a #ifdef
for windows only. As you can see I have the code for the widechar call, but I commented it currently. I think for my use-case it would probably be enough to just call putenv
but well it works as it is. So here's how I call it then:
setEnv_ "LANG" localeStr
putEnv $ "LANG=" ++ localeStr
My problem is that I'm primarily a linux user at home and I don't like doing too much work on windows at home, and I put a lot of energy to get this and other things to work properly on windows, and I can't bring myself to clean this up further. But with this code and the original patch you should get this to work on base <4.7 without much problems.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With