How do I disable `-Werror` only when compiling as a library? - haskell

I have
ghc-options:
- -Wall
- -Werror
in my package.yaml and it builds fine for GHC 8.6.
But when using the project in a GHC 9 codebase, it errors because of an unnessessary MonadFail import.
How can I change the library such that it won't abort compilation when used in other projects?
I have tried
ghc-options:
"$everything": -Wwarn
in the downstream (dependent) project, but that doesn't seem to affect it. I expected -Wwarn to override the -Werror since $everything should cover even dependencies.

I believe, it is bad practice to specify -Werror on the library itself. Same goes for other compiler flags, such as optimization for example -O2.
Setting -Wall on the other hand is definitely good stuff, plus a few other warning flags of top of my head, eg. -Wincomplete-record-updates, -Wincomplete-uni-patterns, -Wredundant-constraints, etc.
If you want to turn build warnings into errors while working on the library or in CI, which is a sensible thing to do, then you can enable it in your
stack.yaml:
ghc-options:
my-library: -Werror
cabal.project:
package my-library
ghc-options: -Werror
That being said you can turn off -Werror for any library downstream by setting -Wwarn for that library in the exact same fashion as above, which will override the original flag.

Related

How do I get the location of linkable libraries in GHC?

I'm working on a project that produces a shared object (.so) file. The source code is in both C and Haskell. It needs to be linked with libraries for the GHC Runtime System and for the Hint Haskell module.
Currently, the command to compile the file is:
ghc -Weverything -Werror -fforce-recomp $^ -o $# -dynamic -shared -lHSrts-ghc8.10.5 -lHShint-0.9.0.4-7GR8UnOuwIbHNCqCSHKCK0-ghc8.10.5
There must be a way to automate the finding of the libraries instead of hard-coding the names. I want the Makefile to continue to work with future releases of GHC and Hint. It seems to be that ghc-pkg
should be able to provide this, but I can't find how.

Setting cabal configuration options in a stack project

In my stack project I have a myproject.cabal file. I would like to try the cabal option --disable-library-profiling documented here:
https://www.haskell.org/cabal/users-guide/installing-packages.html
However, I've been unable to figure out where that option must be used: wherever I put it, subsequent stack runs exit with failure (complaining in one way or another about the option).
My higher-level goal is to see if this speeds up ghc compilation for my project, but that's really secondary as far as this question goes: I'd really just like to know how these configuration options work (in the context of stack projects).
I'm using ghc 6.7. In particular, if I use cabal configure, the option ends up configured in ghc-options in my myproject.cabal file, but GHC then complains:
ghc: unrecognised flag: --disable-library-profiling
I'm already using other ghc-options without running into similar trouble -- stack completes successfully in this case:
ghc-options: -threaded -rtsopts -with-rtsopts=-N -O0 -j +RTS -A128m -n2m -RTS
but not in this case:
ghc-options: -threaded -rtsopts -with-rtsopts=-N -O0 -j +RTS -A128m -n2m -RTS --disable-library-profiling
The stack equivalent of --disable-library-profiling is:
$ stack build --no-library-profiling

Haskell dynamic library

http://www.vex.net/~trebla/haskell/so.xhtml describes how to compile shared library.
About compiling command:
ghc -O2 -dynamic -shared -fPIC -o libEval.so Eval.hs hsbracket.c -lHSrts-ghc7.6.3
it says:
(Could you omit -dynamic to request static libraries of other packages? Not really, they were not generated with -fPIC. In particular it is illegal on x86_64.)
Why is it so? What should one do to compile shared library without libHS* dependencies?
Since Kaiko contacted me privately for an answer, might as well post it here...
Short version
By omitting -dynamic you would be trying to take all the static .a libs and link them into one massive .so file. Those .a libs were themselves built without -fPIC. All code that ends up on a .so file must be built with -fPIC (at least on ELF x86-64). Thus the linking would fail in this case because -fPIC is required but the libs were not built with -fPIC.
Long version
There are a few things that vary between different ways of building
static and dynamic libraries:
Is it built as a .a archive or as a .so (or .dll/.dynlib) object?
Is it built with -fPIC, position independent code or not?
Are external symbols expected to be in the same DSO or an external DSO?
In principle, lots of different combinations of these things make sense
but in practice only a few are used.
On Linux (ELF), there are two standard approaches to building libraries,
fully static and fully dynamic. In the fully static approach the answer
to question 1,2,3 above are: .a archive, no -fPIC, same DSO. In the
fully dynamic approach the answers are: .so lib, -fPIC, external DSO.
Now what you want to do is different. You want all libraries to be built
as .a files, but with -fPIC and external symbols expected to be in the
same DSO. This would then let you link all those libraries together into
one huge shared library. So the crucial difference is the use of -fPIC,
since on ELF (specifically x86_64) code that ends up in a shared lib
must be built with -fPIC.
By contrast, on Windows, GHC can do exactly what you want, to link all
the Haskell libs (including the RTS etc) into one massive shared lib
(.dll). This is because on Windows (unlike ELF), position independent
code does not matter. So on Windows, one is able to take the static
libraries and link them into a big shared library.
In principle this should also be possible on Linux, if all of the
Haskell libraries were built statically but with -fPIC. This is not the
default, and that is the immediate reason why you cannot omit -dynamic
in this case on Linux.
So in principle, one could try rebuilding ghc and the core libraries
from source using the -fPIC flag and then see if it then works to omit
-dynamic and link everything into one huge shared lib.
Yes, compiling with -fPIC helps. Here is how to do that.
ghc-7.8.4/mk/build.mk:
SRC_HC_OPTS = -H64m -O
EXTRA_HC_OPTS = -fPIC
SRC_CC_OPTS = -fPIC -O
GhcStage1HcOpts = -fasm -O0
GhcStage2HcOpts = -fasm -O0
GhcLibHcOpts = -fasm -O2
GhcLibWays = v dyn
DYNAMIC_GHC_PROGRAMS = YES
DYNAMIC_BY_DEFAULT = NO
SplitObjs = NO
HADDOCK_DOCS = NO
BUILD_DOCBOOK_HTML = NO
BUILD_DOCBOOK_PS = NO
BUILD_DOCBOOK_PDF = NO
While you compile ghc:
export EXTRA_CONFIGURE_OPTS="--disable-library-profiling --enable-shared"
To build cabal packages with -fPIC use:
cabal install --enable-shared --ghc-option=-fPIC text
Test file foo.hs (Data.Text is used to see if cabal packages also work):
import Foreign.C as C
import Data.Text as T
import Data.Text.Foreign as T
foreign export ccall len :: CString -> IO CInt
len t = C.peekCString t >>= return . CInt . fromIntegral . T.length . T.pack
main = return ()
Dynamic build:
ghc -dynamic --make foo.hs
Dynamic mixed with static build (not sure if pthread is needed but it illustrates how to add dynamic linking):
ghc -fPIC -shared --make -o libfoo.so \
-optl-Wl,-Bstatic -lHSrts -lCffi \
-lHSbase-4.7.0.2 -lHSinteger-gmp-0.5.1.0 -lHSghc-prim-0.3.1.0 \
-optl-Wl,-Bdynamic -lpthread foo.hs

How to link custom object file with Haskell library?

I've created a Haskell package that makes FFI calls to functions defined in CUDA code. I'd like to compile .cu file to an object (.o) file during package build and force linker to link it in.
So far, I tried to use a technique found this question. I've customized buildHook to:
run nvcc
run default buildHook
create ar library file with nvcc compiled code.
Setup.hs is available here.
This solution has a major disadvantage in restricting this package to static linking. Although cabal produces a shared library, it won't work because it has no way of resolving symbols located in the object file.
Is there a simpler way to link custom code during building?
I do a similar thing. I have a Haskell file which calls CUDA code.
Here's how I compile CUDA libraries and link with Haskell:
$(NVCC) -c -E $(NVCC_OPTS) -o build/file.i file.cu
$(NVCC) -c $(NVCC_OPTS) -o build/file.o file.cu
I then link everything into a C++ Shared Library called LibSO with Haskell options
$(CXX) -shared -Wl,-rpath=\$$$$ORIGIN $(CXX_LINK_LIBS) $(PACKAGE_RPATH) -Lbuild -rdynamic -L/usr/local/lib/ghc-7.6.3 -lHSrts-ghc7.6.3 -o build/LibSO.so build/file.o
where
CXX_LINK_LIBS = -Lbuild -lcudart -lcuda -lpthread -lcupti -lcurand -lnvidia-ml
NVCC_OPTS = --compiler-options -fPIC -maxrregcount=0 --machine 64 --DCUDA
I then take my Haskell files and compile them into o and hi files. (I compile twice because of TemplateHaskell)
ghc -v0 -Wall -rtsopts -threaded -stubdir build -ibuild/ -no-hs-main -o build/iop.o -ohi build/iop.hi -c haskell/iop.lhs
ghc -v0 -Wall -rtsopts -threaded -stubdir build -ibuild/ -no-hs-main -fPIC -dynamic -osuf dyn_o -hisuf dyn_hi -o build/iop.dyn_o -ohi build/iop.dyn_hi -c haskell/iop.lhs
So now we have haskell dynamic objects and a C++ shared library.
In the end, I link a main haskell file with everything:
ghc -optl "-Wl,-rpath=\$$ORIGIN" $(CXX_LINK_LIBS) -Lbuild -rtsopts -threaded -lstdc++ -lLibSO -o build/Main build/iop.dyn_o
Does this sort of help?

Override -Werror when installing from Cabal

I'm trying to install the nano-hmac-0.2.0 package (a dependency of a package I want) from Hackage using Cabal and GHC 6.12.1, but it fails with the following error:
Data/Digest/OpenSSL/HMAC.hsc:1:0:
Warning: Module `Prelude' is deprecated:
You are using the old package `base' version 3.x.
Future GHC versions will not support base version 3.x. You
should update your code to use the new base version 4.x.
<no location info>:
Failing due to -Werror.
Sure enough, the package's .cabal file has the following line in it:
ghc-options: -Wall -Werror -O2 -fvia-C
I'd like to be able to override the -Werror option so I can install the package without manually modifying the .cabal file, but can't find a way that will work. In particular, I tried passing --ghc-options to Cabal to stick a -Wwarn in GHC's argument list, like this:
$ cabal install nano-hmac-0.2.0 -v2 --ghc-options='-Wwarn'
This doesn't do what I want, though; the verbose output verifies that -Wwarn is getting added to the beginning of GHC's argument list, but the -Werror from the .cabal file appears later and seems to override it:
/usr/bin/ghc -Wwarn --make -package-name nano-hmac-0.2.0 -hide-all-packages -fbuilding-cabal-package -i -idist/build -i. -idist/build/autogen -Idist/build/autogen -Idist/build -optP-include -optPdist/build/autogen/cabal_macros.h -odir dist/build -hidir dist/build -stubdir dist/build -package-id base-3.0.3.2-0092f5a086872e0cdaf979254933cd43 -package-id bytestring-0.9.1.5-125aff5b9d19ec30231ae2684b8c8577 -O -Wall -Werror -O2 -fvia-C -XForeignFunctionInterface -XBangPatterns -XCPP Data.Digest.OpenSSL.HMAC
I also tried passing --constraint='base >= 4' to Cabal to force it to use a more recent version of base and avoid the warning entirely, but I get the same failure, and I still see the following in the verbose output:
Dependency base ==3.0.3.2: using base-3.0.3.2
Is there a way to get rid of or override the -Werror coming from the .cabal file via the Cabal command line, or am I stuck modifying the .cabal file myself?
Is there a way to get rid of or override the -Werror coming from the .cabal file via the Cabal command line, or am I stuck modifying the .cabal file myself?
Indeed. There's no way in general. You may be able to override package constraints such that the warnings go away, however, in general, you must modify the .cabal file.
These days Hackage prevents people uploading packages with -Werror in their .cabal file, so the issue will go away over time.

Resources