2012-02-14 4 views
9

Posso leggere facilmente una variabile d'ambiente usando System.Environment.getEnv. Tuttavia, System.Environment non ha alcuna funzione corrispondente setEnv (per quanto posso dire).Come posso impostare una variabile di ambiente in modo multipiattaforma?

Come si imposta una variabile di ambiente da un programma Haskell? Preferirei una soluzione multipiattaforma. (Quindi, solo l'esecuzione di export VAR=val o utilizzando System.Posix.Env non è proprio quello che sto cercando.)

+1

Si noti che base 4.7.0 ora ha un 'setEnv'. –

+0

@EmmanuelTouzery: Fantastico. Potresti metterlo come risposta per una maggiore visibilità? Grazie. –

risposta

3

Si noti che la base 4.7.0 ora ha un setEnv in System.Environment. Quindi per il presente o per il futuro prossimo è risolto.

Tuttavia, se questa funzione è necessaria nelle versioni < 4.7.0 (che è il mio caso attualmente), ho estratto anche da the commit that adds the feature le funzioni necessarie per farlo funzionare con una versione di base precedente.

Tuttavia ho seriamente perso la pazienza su questo e lo ha fatto piuttosto brutto ma funziona per me ...

Il pasticcio è che ci sono 3 funzioni per chiamare in un ambiente Windows: putenv, SetEnvironmentVariableA (ASCII) e SetEnvironmentVariableW (widechar, utf16). La patch che è stata commessa alla base 4.7 lo fa automaticamente, ma ho fatto qualcosa di più brutto per mancanza di tempo (potrei ancora ripulirlo).

Ecco quello che ho:

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 

Ovviamente usano CPP di mettere il tutto in una #ifdef solo per le finestre. Come puoi vedere, ho il codice per la chiamata widechar, ma l'ho commentato al momento. Penso che per il mio caso d'uso sarebbe probabilmente sufficiente chiamare lo putenv ma funziona così com'è. Quindi, ecco come lo chiamo io, allora:

setEnv_ "LANG" localeStr 
putEnv $ "LANG=" ++ localeStr 

Il mio problema è che sono in primo luogo un utente Linux a casa e non mi piace fare troppo lavoro sulle finestre a casa, e ho messo un sacco di energia per far funzionare correttamente questa e altre cose su Windows, e non riesco a portarmi a ripulire ulteriormente. Ma con questo codice e la patch originale dovresti farlo funzionare sulla base < 4.7 senza molti problemi.

3

Sulle piattaforme POSIX è possibile utilizzare System.Posix.Env, che ha una funzione putEnv. È più portatile che eseguire export, anche se sfortunatamente non è veramente multipiattaforma.

+1

Grazie per la risposta. In realtà ho visto quel modulo dopo aver postato la domanda, ma mi piacerebbe davvero qualcosa che funzionasse su Windows. –

3

Un suggerimento che questo non è possibile su più piattaforme è che l'API Java non ha un putenv. Vedi anche questo related post.

La soluzione per il caso di utilizzo più frequente è passare un ambiente adeguatamente costruito quando i programmi exec -ing.