I'm trying to have a submodule in my program compile conditionally to switch small parts of the code between release builds and development builds.
Currently I'm attempting to use cpphs however when I change the flags passed into GHC to define a variable and change an ifdef statement stack won't recompile those files.
For example, I've got a port number that I want to switch based on which target I have built. The code I have defining this number looks like this.
#ifdef StableRelease
port = 12345
#else
port = 54321
#endif
the stable build has the following options in its cabal file
ghc-options: -threaded -rtsopts -with-rtsopts=-N -pgmP cpphs -optP "-DStableRelease"
When I run stack build though it doesn't seem to actually pre-process the code above.
Does anyone have experience with cpphs or another preprocessing solution?
I would solve this with the help of flags
cppstuf.cabal-file
name: cppstuf
version: 0.1.0.0
...
cabal-version: >=1.10
flag StableRelease {
Description: Stable release settings like port ...
Default: False
}
executable cppstuf
main-is: Main.hs
build-depends: base >=4.9 && <5.00
default-language: Haskell2010
extensions: CPP
if flag(StableRelease) {
GHC-Options: -DSTABLE
}
Main.hs
module Main where
main :: IO ()
main =
#if STABLE
putStrLn "Hello, Haskell!"
#else
putStrLn "Hello, Haskell?"
#endif
and compiling it
stack build
or
stack build --flag cppstuf:stablerelease
Personal Note aside from the answer
I would not use CPP to manage configuration options - either providing command-line options I like optparse-applicative but there is also cmdargs,and or a configuration file I have used configurator for that, but there are several options out there on hackage. One being configurator-ng as #Shersh said - the other one is not being developed anymore.
CPP on the other hand I tend to use for making libraries work across multiple GHC/library versions.
Update - w\ regards to the comment.
If I deliver a program, the operations team should be able to change ports, hostname or handle file location of input files etc. without knowing haskell let alone recompiling a project.
It makes error chasing a lot easier if your production source code does not differ from your development sources, say you would have a postgres db in dev mode, but an oracle in production - you'll never find the oracle specific bug.
For things like optimization levels - I don't mind too much.
But make sure you test multi-threaded stuff properly, I once ran out of file handles because I was opening a lot but not closing fast enough - If your dev-setting is single threaded you'll deliver a bug.
Related
I have a stack project using Sound.ALUT. The project was building fine on both Windows and Mac before I added sound. (Sound.ALUT is a library layered over OpenAL.) Got thinks working on MacOS but those changes broke the Windows build. Still builds fine on MacOS.
The offending snippit from the "stack build" console log on Windows looks like this
GLUT > [22 of 24] Compiling Graphics.UI.GLUT.Callbacks.Global
GLUT > [23 of 24] Compiling Graphics.UI.GLUT.Callbacks
GLUT > [24 of 24] Compiling Graphics.UI.GLUT
GLUT > copy/register
GLUT > Installing library in C:\sr\snapshots\87ecdd59\lib\x86_64-windows-ghc-8.10.7\GLUT-2.7.0.16-2jeyeunHWey2D1Huuhst8j
GLUT > Registering library for GLUT-2.7.0.16..
OpenAL > configure
OpenAL > Configuring OpenAL-1.7.0.5...
OpenAL > Cabal-simple_Z6RU0evB_3.2.1.0_ghc-8.10.7.exe: Missing dependency on a foreign
OpenAL > library:
OpenAL > * Missing (or bad) C library: OpenAL32
OpenAL > This problem can usually be solved by installing the system package that
OpenAL > provides this library (you may need the "-dev" version). If the library is
OpenAL > already installed but in a non-standard location then you can use the flags
OpenAL > --extra-include-dirs= and --extra-lib-dirs= to specify where it is.If the
OpenAL > library file does exist, it may contain errors that are caught by the C
OpenAL > compiler at the preprocessing stage. In this case you can re-run configure
OpenAL > with the verbosity flag -v3 to see the error messages.
OpenAL >
Progress 10/21
Cleary it can't find OpenAL. I've tried:
installing OpenAL using the Windows installer from https://www.openal.org/downloads
cloning and building openal-soft https://github.com/kcat/openal-soft on windows
setting the --extra-include-dirs and --extra-lib-dirs inslide my stack.yaml to point to where the libraries should be.
I had similar issues getting Sound.ALUT working on the Mac build. In that case building from the sources seemed to solve the problems. I have more trouble building on Windows since the build environment is less familiar. My Windows work has mostly been centered around installing Cygwin and making it look like Unix. But this time, I'm trying to get by on what stack's mingw-w64 provides. I was pulling down things with stack exec -- pacman trying to find something that would install OpenAL as a side effect but no luck.
Some subtleties arise from the fact that stack want to install things in its own self-contained environment. It tries to keep installs localized inside the project directory and not muck around with directories elsewhere. My stack environment looks like this
C:\Users\Mark\slgjff>stack path
snapshot-doc-root: C:\sr\snapshots\aff7b821\doc
local-doc-root: C:\Users\Mark\slgjff\.stack-work\install\f5431f41\doc
local-hoogle-root: C:\Users\Mark\slgjff\.stack-work\hoogle\f5431f41
stack-root: C:\sr
project-root: C:\Users\Mark\slgjff
config-location: C:\Users\Mark\slgjff\stack.yaml
bin-path: .;C:\sr\snapshots\87ecdd59\bin;C:\sr\compiler-tools\x86_64-windows\ghc-8.10.7\bin;C:\Users\Mark\AppData\Local\Programs\stack\x86_64-windows\ghc-8.10.7\bin;C:\Users\Mark\AppData\Local\Programs\stack\x86_64-windows\ghc-8.10.7\mingw\bin;C:\Users\Mark\AppData\Local\Programs\stack\x86_64-windows\msys2-20220503\mingw64\bin;C:\Users\Mark\AppData\Local\Programs\stack\x86_64-windows\msys2-20220503\usr\bin;C:\Users\Mark\AppData\Local\Programs\stack\x86_64-windows\msys2-20220503\usr\local\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Git\cmd;C:\Users\Mark\AppData\Roaming\local\bin;C:\Users\Mark\AppData\Local\Microsoft\WindowsApps
programs: C:\Users\Mark\AppData\Local\Programs\stack\x86_64-windows
compiler-exe: C:\Users\Mark\AppData\Local\Programs\stack\x86_64-windows\ghc-8.10.7\bin\ghc-8.10.7.exe
compiler-bin: C:\Users\Mark\AppData\Local\Programs\stack\x86_64-windows\ghc-8.10.7\bin
compiler-tools-bin: C:\sr\compiler-tools\x86_64-windows\ghc-8.10.7\bin
local-bin: C:\Users\Mark\AppData\Roaming\local\bin
extra-include-dirs: C:\Users\Mark\AppData\Local\Programs\stack\x86_64-windows\msys2-20220503\mingw64\include
extra-library-dirs: C:\Users\Mark\AppData\Local\Programs\stack\x86_64-windows\msys2-20220503\mingw64\lib, C:\Users\Mark\AppData\Local\Programs\stack\x86_64-windows\msys2-20220503\mingw64\bin
snapshot-pkg-db: C:\sr\snapshots\87ecdd59\pkgdb
local-pkg-db: C:\Users\Mark\slgjff\.stack-work\install\363b2fd8\pkgdb
global-pkg-db: C:\Users\Mark\AppData\Local\Programs\stack\x86_64-windows\ghc-8.10.7\lib\package.conf.d
ghc-package-path: C:\Users\Mark\slgjff\.stack-work\install\363b2fd8\pkgdb;C:\sr\snapshots\87ecdd59\pkgdb;C:\Users\Mark\AppData\Local\Programs\stack\x86_64-windows\ghc-8.10.7\lib\package.conf.d
snapshot-install-root: C:\sr\snapshots\87ecdd59
local-install-root: C:\Users\Mark\slgjff\.stack-work\install\363b2fd8
dist-dir: .stack-work\dist\274b403a
local-hpc-root: C:\Users\Mark\slgjff\.stack-work\install\363b2fd8\hpc
local-bin-path: C:\Users\Mark\AppData\Roaming\local\bin
ghc-paths: C:\Users\Mark\AppData\Local\Programs\stack\x86_64-windows
I'm not sure the configure needs to be happy. I wish I could construct a checklist run through, but I don't understand enough to write that checklist. Do it need the C source for header files? Don't know. Certainly it must need the .lib and .dlls on the path somewhere. But which path exactly?
My package.yaml -- which works fine on MacOS
ghc-options:
#- -dynamic
- -static
dependencies:
- base >= 4.7 && < 5
- random
- gloss
- gloss-juicy
- ALUT
library:
source-dirs: src
executables:
slgjff-exe:
main: Main.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- slgjff
tests:
slgjff-test:
main: Spec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- slgjff
And my stack.yaml -- which also works fine on MacOS
resolver:
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/24.yaml
packages:
- .
extra-deps:
- gloss-1.13.2.1#sha256:273d02d30e1896932d45424dab6022a16986c0ed3eef6937776b5f40854ce51c,4075
- JuicyPixels-3.3.6#sha256:03bd32c3a884ac8a32f49334f14695469a710945c84cef9a1e059a79ac416996,3911
- gloss-juicy-0.2.3
And because it may be helpful, here are the includes at top of my program.
import System.Exit ( exitSuccess, exitFailure )
import System.IO ( hPutStrLn, stderr )
import Data.List
import Graphics.Gloss
import Graphics.Gloss.Interface.Pure.Game
import Graphics.Gloss.Interface.IO.Game
import Graphics.Gloss.Data.Vector
import Graphics.Gloss.Juicy
import Control.Monad( when, unless )
import Sound.ALUT as S
I got so desperate I stuck C:/Windows/System32 on the path and almost spilled my drink when the build tried to delete files from C:/Windows/System32. So, I took that out. Running out of ideas.
My sense is that out of inexperience with ghc on Windows, I must be missing something that would be really obvious to someone with more experience. Thanks in advance for any insights.
P.S. I created a stripped down version of the project and put it up on github at https://github.com/markcornwell/alut-glitch
See the README for the project for instruction on how to reproduce the error.
I have a Haskell library that I am developing using Stack. As I am developing the library, I like to write small test/experimentation programs that use the library. I keep a collection of these test programs for myself in a directory locally. These test modules are very quick and informal, and not appropriate to include as unit tests in the committed library code. Typically, most of them aren't even maintained and won't compile against the latest version of the library, but I keep them around in case I want to update them later. When I'm working on a test program, I want it to build against my working copy of the library, with any changes that I've made to the library locally.
How should I set up my Stack build environment for this situation? Here are some options I've tried, and the problems with each options.
Two Cabal packages, one Stack configuration. The stack.yaml file lists both packages and defines the build environment for both at once.
Problem: The stack.yaml file needs to be included as part of the committed library source code, so that other developers can build the library from source reproducibly. I don't want the public stack.yaml file for my library to include build information for my local test projects.
Problem: As far as I know, to make this work I need to have a .cabal file that lists all the executables and modules for my test programs. This is annoying to update whenever I want to throw together a quick experimental script, and will fail to build any of the test programs if I have even a single module that doesn't compile. I can't have a .cabal file with no sections, because Cabal gives "No executables, libraries,tests, or benchmarks found. Nothing to do.", and because this offers nowhere to list build-depends.
Create a Cabal sandbox for the test programs. Use cabal sandbox add-source to add the local library as a package. See also this answer.
Problem: Using Cabal sandboxes instead of Stack reintroduces a lot of the dependency problems that Stack is supposed to fix, such as using the system-global GHC instead of the GHC defined by the resolver.
Have a separate stack.yaml for the test programs. Add the library under packages as location: 'C:\Path\To\Local\Library' and set extra-dep: true for that dependency. (See here for more info on this feature.) Don't put any other Cabal packages under packages in the stack.yaml for the test programs. Use stack runghc to invoke test programs within the scope of their stack.yaml.
Problem: I just can't get this one to work. Running stack build inside the test program directory gives "Error parsing targets: The project contains no local packages (packages not marked with 'extra-dep')". Running stack runghc acts as if no dependencies are present at all. I don't want to add a Cabal package for the test programs because this has the same problem as option 1 with needing to construct an explicit .cabal file describing the modules to build.
Problem: Stack build configuration info that I want to be identical between the library and the test programs has to be copied manually. For example, if I change the resolver in my library's stack.yaml, I also need to change it in the stack.yaml for my test programs separately.
Have a directory inside my working copy of the library that contains all of my test programs. Use stack runghc to invoke test programs in the context of the library.
Problem: I'd like the directory with my test programs to be outside of the directory containing my library source code and build configuration, so that I don't have to tell the version control for my library to ignore my test code, and can have my own local version control just for the test programs.
Problem: Only works with a single local library dependency. If my test programs need to depend on local working copies of two different libraries with their own stack.yaml files, I'm out of luck.
Add a symbolic link inside my working copy of the library to a separate directory that contains all of my test programs. Navigate through the symlink and use stack runghc to invoke test programs in the context of the library.
Problem: Super awkward to use, especially since I'm on Windows and Windows has terrible symlink support.
Problem: Still need to tell my version control system to ignore the symlink.
Problem: Still only works with a single library dependency.
If only one local library is involved, I use option 4. You can put your tests outside the directory of your library, and either invoke stack from the directory of your library, or using --stack-yaml path/to/library/stack.yaml.
Otherwise, I use option 3, creating a separate stack project without setting extra-dep.
...
packages:
- 'path/to/package1'
- 'path/to/package2'
...
I can't think of a good workaround for the issue of configuration duplication. There would otherwise be conflicts if multiple packages specified different resolvers/package versions.
Edit: Actually a stub library works better, so edited to add.
I think the way to get #3 to work is -- under your scratch program directory -- (1) add . under packages in stack.yaml alongside the location/extra-dep: true package:
packages:
- '.'
- location: ../mylib
extra-dep: true
(2) create an executable clause in scratch.cabal that points to a stub main program (i.e., a "Hello World" program that compiles but need not do anything) which depends on your library:
executable main
hs-source-dirs: src
main-is: Stub.hs
build-depends: base
, mylib
default-language: Haskell2010
or a library clause with no exposed modules, again that depends on your mylib library:
library
hs-source-dirs: src
build-depends: base >= 4.7 && < 5
, mylib
default-language: Haskell2010
and (3) run stack build in the scratch directory. This should build and register mylib, and now stack runghc Prog1.hs should work fine for running programs that depend on mylib modules.
If you use the executable approach, the stub program is compiled as a side effect but otherwise ignored. If you use the library approach, it looks like the stub library isn't even built; and you then have the option of actually building a scratch library by adding some exposed modules of shared code for your test programs to use, if it's convenient, so the stub library might be best.
None of this solves the problem of keeping stack.yaml info like the resolver version in sync, but it seems to address all the problems you list in 1, 2, 4, and 5. In particular, it should work fine for test programs that depend on multiple local libraries you're developing.
I have a project which exports a shared static library and I use the following part in my project.cabal file
executable libsxp.so
main-is: Somefile.hs
default-language: Haskell2010
ghc-options: -shared -dynamic -fPIC -lHSrts-ghc7.10.2
The version of GHC is controlled using Stack, so is there a way wherein I can either get and append the version to make -lHSrts-ghc{version} or is there some config for it? I tried setting
stack build --ghc-options='-O0 -lHSrts-ghc7.10.2'
but it doesn't seem to pick it.
Also to clarify, cabal install is called by Stack and not by me.
Does that cabal file work? If so, then it should be sufficient to do something like this:
executable libsxp.so
ghc-options: -shared -dynamic -fPIC
if impl (ghc >= 7.10.2 && < 7.10.3)
ghc-options: -lHSrts-ghc7.10.2
else if impl (ghc >= 7.10.3 && < 7.10.4)
ghc-options: -lHSrts-ghc7.10.3
else if ...
BTW, why does your executable end in .so? I've never seen that in an executable clause.
Are you sure you're using 7.10.2 and not 7.10.3? Try stack exec -- ghc --version
The general principle is described in this answer: https://stackoverflow.com/a/6034881/1663197
Using the configure style in Cabal, you can write a little configure
script that substitutes a variable for the output of the sdl-config
command. The values will then be replaced in a $foo.buildinfo.in file,
yielding a $foo.buildinfo file, that Cabal will include in the build
process.
First you need to switch your cabal build-type to Configure in project.cabal. Configure style is described in cabal users guide. For build type Configure the contents of Setup.hs must be:
import Distribution.Simple
main = defaultMainWithHooks autoconfUserHooks
In case of handling GHC runtime version you can have a variable #GHC_VERSION# corresponding to it in a project.buildinfo.in file:
ghc-options: -lHSrts-ghc#GHC_VERSION#
Finally you write a configure bash script that gets GHC version as mgsloan suggested and generates project.buildinfo file by substitution of #GHC_VERSION# varibale in project.buildinfo.in file:
GHC_VERSION=$(stack exec -- ghc-pkg field ghc version --simple-output)
sed 's,#GHC_VERSION#,'"$GHC_VERSION"',' project.buildinfo.in > project.buildinfo
This way when build is started it will first execute configure script, then read project.buildinfo file and merge with project.cabal.
Also it may be worth to populate extra-source-files with configure and
project.buildinfo.in; extra-tmp-files with project.buildinfo in project.cabal.
A more sophisticated solution may be inspired by this answer: https://stackoverflow.com/a/2940799/1663197
I am using ghc 7.6.3. I installed wxHaskell from here: https://github.com/wxHaskell/wxHaskell
It worked, the sample programs compile and the run successfully.
The only problem now is that I want to distribute a wxHaskell application on mac OS X. I tried using macosx-app and cabal-macosx (https://github.com/michaelt/cabal-macosx) to make an "app" file. It runs fine on my machine, but it fails to run on another computer. I get the following error:
Dyld Error Message: Library not loaded: /Users/user/.cabal/lib/wxc-0.90.1.0/ghc-7.6.3/libwxc.dylib.
I am using OS X 10.8.4 (Mountain Lion), but I would be also interested in compiling apps on Windows and redistribute them too.
What would be the best way to redistribute wxHaskell apps?
Setup.hs
-- Example Setup.hs for the wxHello app.
import Distribution.MacOSX
import Distribution.Simple
main :: IO ()
main = defaultMainWithHooks $ simpleUserHooks {
postBuild = appBundleBuildHook guiApps -- no-op if not MacOS X
}
guiApps :: [MacApp]
guiApps = [MacApp "WxHello"
(Just "resources/WxHello.icns")
Nothing -- Build a default Info.plist for the icon.
[] -- No other resources.
[] -- No other binaries.
ChaseWithDefaults -- Try changing to ChaseWithDefaults
]
wxHello.cabal:
Name: wxHello
Version: 0.1.0
Stability: Alpha
Synopsis: wxWidgets `Hello World' example for cabal-macosx
Description:
Example showing how to use cabal-macosx to build an application
bundle for a simple `Hello World' program using the wxWidgets GUI
toolkit.
Category: Data
License: BSD3
License-file: LICENSE
Copyright: Andy Gimblett <haskell#gimbo.org.uk>
Author: Andy Gimblett <haskell#gimbo.org.uk>
Maintainer: Andy Gimblett <haskell#gimbo.org.uk>
Build-Type: Custom
Cabal-Version: >=1.6
Executable WxHello
hs-source-dirs: src
Main-is: Main.hs
Build-Depends: base >= 3 && < 5, cabal-macosx, wx
ghc-options: -fwarn-tabs -threaded -Wall
Here are the dylib files inside the generated package:
WxHello.app $ find . | grep dylib
./Contents/Frameworks/Users/user/.cabal/lib/wxc-0.90.1.0/ghc-7.6.3/libwxc.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_baseu-2.9.5.0.0.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_baseu_net-2.9.5.0.0.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_baseu_xml-2.9.5.0.0.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_osx_cocoau_adv-2.9.5.0.0.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_osx_cocoau_aui-2.9.5.0.0.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_osx_cocoau_core-2.9.5.0.0.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_osx_cocoau_gl-2.9.5.0.0.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_osx_cocoau_html-2.9.5.0.0.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_osx_cocoau_propgrid-2.9.5.0.0.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_osx_cocoau_qa-2.9.5.0.0.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_osx_cocoau_ribbon-2.9.5.0.0.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_osx_cocoau_richtext-2.9.5.0.0.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_osx_cocoau_stc-2.9.5.0.0.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_osx_cocoau_webview-2.9.5.0.0.dylib
./Contents/Frameworks/Users/user/temp/wxWidgets-2.9.5/build-release/lib/libwx_osx_cocoau_xrc-2.9.5.0.0.dylib
./Contents/Frameworks/usr/lib/libc++abi.dylib
./Contents/Frameworks/usr/lib/libexpat.1.dylib
./Contents/Frameworks/usr/lib/libiconv.2.dylib
./Contents/Frameworks/usr/lib/libstdc++.6.dylib
./Contents/Frameworks/usr/lib/libz.1.dylib
The last redistributable I made in Windows with wxHaskell needed the files
mingwm10.dll and
wxmws28u_gcc.dll
to be in the same folder as the .exe (not just somewhere on my path).
This was using a previous version of wxHaskell, which compiled against a previous version of wxWidgits itself, so presumably you'd need the wx dll to have 29 in it rather than 28.
I compiled with static linking too:
ghc -static -optl-static -optl-mwindows Main -o Project.exe
the -optl-mwindows gets rid of the command prompt window which would otherwise appear alongside your app.
It might be helpful to include your .cabal and Setup.hs files.
From the documentation on cabal-macosx, it seems that you need to ensure that your MacApp data value in Setup.hs gets the appropriate mode for ChaseDeps (use ChaseWithDefaults instead of DoNotChase) in order to build redistributable app bundles.
If you have done that but still get the same error, I would check inside the resulting app bundle to see if the necessary libraries got copied in there at all. You may find enough information to file a bug with the cabal-macosx maintainer.
Edit
Based on what you've included, the setup looks correct, and it appears to have at least copied the library dependencies in. I think the problem is probably with the cabal-macosx package.
Looking at the source code to the dependency-fixup code, it looks like it should have printed a bunch of "Updating <library>'s dependence on <path> to <path>" lines as it was building the bundle. Did you see those? Were there any lines updating the binary itself?
I am not very experienced with the OS X linking process, but I would think that unless the binary is linked after copying the libraries, it would need to be updated as well. You should be able to use /usr/bin/otool -L <filename> and /usr/bin/install_name_tool to manually fix up the paths in binaries the install process may have missed.
Here are the man pages for those two tools:
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/install_name_tool.1.html
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/otool.1.html
Is it possible somehow to configure cabal project to use different compiler than GHC? Additional is it possible to control this by some flags?
I want to compile my project with GHC or Haste (to JavaScript) based on some compilation flags.
It would be ideal if I could set my cabal configuration or my custom script to do something like:
-- target JS
cabal configure --target=js
cabal build
-- target Native
cabal configure --target=native
cabal build
To build a Cabal project with either GHC or Haste, use the cabal binary for the former, and haste-inst (comes with haste) for the latter.
To have conditional code in in your modules, add {-# LANGUAGE CPP #-} and use #ifdef __HASTE__, which will only be defined by haste, but not by GHC. Note that __GLASGOW_HASKELL__ is defined in both cases (which makes sense, as haste builds on GHC for large parts of the compilation). So you would use it like
{-# LANGUAGE CPP #-}
module Module where
compiler :: String
#ifdef __HASTE__
compiler = "haste"
#else
compiler = "GHC"
#endif
Theoretically, for conditional settings in the Cabal file something like this should work:
library
exposed-modules:
Module
if impl(ghc)
exposed-modules:
Module.GHC
if impl(haste)
exposed-modules:
Module.GHC
build-depends: base ==4.6.*
but it seems that even with haste-inst, impl(ghc) is true; bug report is filed.
While it's currently not possible to use impl(haste) in your cabal files, you can now check for flag(haste-inst) to see if your package is being built using haste-inst.