Haddock breaks down on #if #else #endif clauses - haskell

I am trying to generate documentations for a github library using haddock. Here's the code I entered:
$ find -name '*.hs' | xargs haddock --html -o docs
src/Reflex/Dom/Xhr.hs:154:0:
error: missing binary operator before token "("
#if MIN_VERSION_aeson(1,0,0)
^
Then I looked up the relevant section of my source code Xhr.hs line 154:
import Data.Aeson
#if MIN_VERSION_aeson(1,0,0)
import Data.Aeson.Text
#else
import Data.Aeson.Encode
#endif
I didn't know #if, #else and #endif were part of Haskell but I could guess the meaning. Depending on the version, the code should import either Aeson.Text or Aeson.Encode. Just in case, I looked up the version:
$ ghc-pkg list | grep aeson
aeson-0.11.3.0
This was enough to give haddock difficulty. The info pages get sent to a folder called docs which contains a few empty html files waiting to be populated with the details of the Reflex.Dom library.

That code uses -cpp. Preprocessor directives are not part of the usual Haskell language. In order to correctly parse that code, you need to specify additional options to Haddock:
2.1. Using literate or pre-processed source
Since Haddock uses GHC internally, both plain and literate Haskell sources are accepted without the need for the user to do anything. To use the C pre-processor, however, the user must pass the the -cpp option to GHC using --optghc. [emphasis mine]
There are two problems, though. C preprocessor macro expansion you've posted will only work with GHC 8.0 (or later) if the package is exposed. It should, however, work with cabal haddock or stack haddock regardless of GHC's version. The latter variants are recommended if you try to build the documentation of a cabal/stack package, by the way.
If you still know what you're doing, use haddock --optghc=-cpp.

Related

How to link to a C# (i.e., managed) DLL from Haskell?

I am trying to build a Windows DLL from my Haskell code. The functions in this DLL are supposed to be called from a managed code in C#. And, atleast one of the function (defined in the c# code) is to be called from a function in this DLL.
At the risk of over explaining, here's a small diagram to depict what I want:
+----------------------+ +------------------------+
| Managed C# code | | Haskell code (in DLL) |
| | (1) | |
| fn_calling_hs() -----------------> fn_called_from_cs() |
| | | |
| | | |
| fn_called_from_hs() <--------------- fn_calling_cs() |
| | (2) | |
+----------------------+ +------------------------+
I managed to make the (1) work perfectly, i.e., a Haskell function in the DLL is called by C# code, with correct marshalling of structures and arrays, and the results from the function execution in Haskell is also correct. So far, so good.
The problem is with (2), i.e., a function from Haskell (in the DLL) calling a managed function defined in C#. The problem is in the build itself - I have not yet gone past that to actually check the results of (2).
As the fn_called_from_hs() in the c# managed code is defined in C#, I only have the function symbol "imported" in the Haskell code (in DLL):
foreign import ccall fn_called_from_hs :: IO CString
Now, when I build my Haskell project with stack, it builds the Haskell DLL without problems, but the build continues to also link "main.exe" - and this fails (obviously), because there is no function fn_called_from_hs() defined anywhere in the Haskell code (it is defined in c#).
Is there any way that I can stop stack from continuing to build main.exe after building HsDLL.dll? I am ok with HsDLL.dll having unresolved symbol (fn_called_from_hs()) because this symbol will be found by the runtime linker during the loading of this DLL by the managed C# code.
So far, I have tried these steps, but none of them helped:
Removed the "executables" and "test" from package.yaml
Added the GHC option: -no-hs-main in the package.yaml. The package.yaml
portion that contains building of HsDLL looks like this:
library:
source-dirs:
- src
- src/csrc
include-dirs: src/csrc
ghc-options:
- -shared
- -fno-shared-implib
- -no-hs-main
Completely removed the Main module (i.e., removed Main.hs that was automatically created by stack from the "app" folder)
I added the -dynamic flag in the ghc-options in the hopes that GHC will assume that the unresolved symbols will be defined elsewhere, but this gave other problems: GHC now complains that it needs "dyn" libraries of base, etc.
So, finally, I always end up with this:
PS C:\workspace\Haskell\hscs\src\csrc> stack build
hscs-0.1.0.0: configure (lib)
Configuring hscs-0.1.0.0...
hscs-0.1.0.0: build (lib)
Preprocessing library for hscs-0.1.0.0..
Building library for hscs-0.1.0.0..
Linking main.exe ...
.stack-work\dist\5c8418a7\build\HsLib.o:fake:(.text+0x541): undefined reference to `fn_called_from_hs'
collect2.exe: error: ld returned 1 exit status
`gcc.exe' failed in phase `Linker'. (Exit code: 1)
-- While building custom Setup.hs for package hscs-0.1.0.0 using:
C:\tools\HaskellStack\setup-exe-cache\x86_64-windows\Cabal-simple_Z6RU0evB_2.0.1.0_ghc-8.2.2.exe --builddir=.stack-work\dist\5c8418a7 build lib:hscs --ghc-options " -ddump-hi -ddump-to-file -fdiagnostics-color=always"
Process exited with code: ExitFailure 1
So, my questions are:
(1) I have absolutely no idea how to stop linking "main.exe"! I know that the function fn_called_from_hs() is not defined within the HsDLL, but, as I said, I am ok because it is defined in the managed c# code. I just want main.exe not to be built.
OR
(2) Should I go ahead with adding -dynamic flag to GHC (keeping all the other flags as above)? In this case, how do I get stack to install the "dyn" libraries that GHC is complaining about?
Can somebody help me? Thanks in advance for your patience in reading this (rather) long question!
And so finally, I managed to solve this myself! After a week of struggle, that is. And any helpful comments to add it this answer is welcome.
I did this as follows:
In C# class DLL:
I had to find a way to "export" my function fn_called_from_hs() to unsafe native code. I found this is not really straight-forward, and there are really quite some amount of articles on the internet to explain how this is done. Everything amounts to actually disassembling the .NET DLL via the tool ildasm, and in the intermediate IL file generated, adding an ".export" prefix to the function that we want to export, and then again assembling the IL file back to the DLL form using ilasm.
I found all these steps are automated by the NUGetPackage Unmanaged Exports, so the first step is to install this package as a part of your .NET project, and then adding the DLLExport attribute to your function to be exported. Make sure you have RGiesecke.DllExport in your list of imports:
using RGiesecke.DllExport;
[DllExport("fn_called_from_hs", CallingConvention=CallingConvention.Cdecl)]
public static string FnCalledFromHs()
{
// Your function code here
}
As you can see, I have named the actual function as FnCalledFromHs() (in accordance with the naming convention in C#), but exported the same function as fn_called_from_hs (in accordance with the naming convention in Haskell). This way, when you look at the Haskell code, you will not see anything that looks out of place.
One of the most important steps for this to actually work is to make sure that the project in which you are exporting the function is made to target x64 or x86 - On default the projects target "Any CPU" - RGiesecke.DllExport does not work if the project targets "Any CPU".
Now build the project to get the csharp.dll which contains your exported fn_called_from_hs.
Before linking Haskell code
Mingw GCC (which ghc on Windows internally uses) can actually directly link with DLLs, provided they were created with gcc before. However, since we have created our C# DLL using the .NET compiler csc, we need to specifically create an import library that our Haskell can see.
We use two tools to our aid: gendef and dlltool, both of which are in the "mingw\bin" folder within your ghc installation (so, of course, you need to have this in your PATH env variable to access these tools).
Here's how I went about it:
Created a .def file which in-turn can be used for creating an import library:
gendef csharp.dll
Created an import library with dlltool:
dlltool -k -d csharp.def -l csharp.lib
Copied the above import lib to the same directory in which the DLL was present.
The last step (below) now will use this import library for actually linking with the csharp DLL.
Linking Haskell code with the above import library
This was a little trickier, and has possibly made me hit a bug in stack / GHC (not sure), but have already filed here.
I went about this as follows:
Added extra-lib-dirs in my stack.yaml, and added the directory in which the above import-lib was created:
extra-lib-dirs: ["<drive>:\\path\\to\\importlib"]
(Note that this could have also been added to your package.yaml under "libraries", but I chose to have it in my stack.yaml).
Added extra-libraries to my stack.yaml, under libraries.
extra-libraries: csharp
And, added also the options -l and -L to my ghc-options for linking my library. This is what I did to circumvent the (possible) bug that stack somehow is not passing the extra-lib-dirs and extra-libraries to ghc and ld during linking. So, my final "library" section in package.yaml looks like this (compare it to how it was before in my question above):
library:
source-dirs:
- src
- src/csrc
include-dirs: src/csrc
ghc-options:
- -shared
- -fno-shared-implib
- -lcslib
- -L<drive>:\\path\\to\\importlib
extra-libraries: csharp
Conclusion
With all this done, my Haskell code now simply builds well with the normal stack build command, without any "unreferenced symbols" error. On executing my Haskell code, I also checked that the c# function fn_called_from_hs was actually called, and the results got returned correctly.
Of course, there is more to this from the c# side: correct marshalling of parameters, etc., and I had to also work on those to get my result correct. The only place I can cover all of these nitty-gritties is in a blog :-)
Please feel free to cross-verify my solution, and also comment on any better way of doing this. This was the best way I could figure out after my struggles!

A workaround for the “Template Haskell + C” bug?

I've got the following situation:
Library X is a wrapper over some code in C.
Library A depends on library X.
Library B uses Template Haskell and depends on library A.
GHC bug #9010 makes it impossible to install library B using GHC 7.6. When TH is processed, GHCi fires up and tries to load library X, which fails with a message like
Loading package charsetdetect-ae-1.0 ... linking ... ghc:
~/.cabal/lib/x86_64-linux-ghc-7.6.3/charsetdetect-ae-1.0/
libHScharsetdetect-ae-1.0.a: unknown symbol `_ZTV15nsCharSetProber'
(the actual name of the “unknown symbol” differs from machine to machine).
Are there any workarounds for this problem (apart from “don't use Template Haskell”, of course)? Maybe library X has to be compiled differently, or there's some way to stop it from loading (as it shouldn't be called during code generation anyway)?
This is really one of the main reasons that 7.8 switched to dynamic GHCi by default. Rather than try to support every feature of every object file format, it builds dynamic libraries and lets the system dynamic loader handle them.
Try building with the g++ option -fno-weak. From the g++ man page:
-fno-weak
Do not use weak symbol support, even if it is provided by the linker. By default, G++ will use weak symbols if they are available. This option exists only for testing, and should not be used by end-users; it will result in inferior code and has no benefits. This option may be removed in a future release of G++.
There is another issue with __dso_handle. I found that you can at least get the library to load and apparently work by linking in a file which defines that symbol. I don't know whether this hack will cause anything to go wrong.
So in X.cabal add
if impl(ghc < 7.8)
cc-option: -fno-weak
c-sources: cbits/dso_handle.c
where cbits/dso_handle.c contains
void *__dso_handle;

Haddock - link to function in external module (whole module imported)

Suppose I have a Haskell module named MyModule that imports an external module like this:
import ModuleA hiding (a, b, c)
And I cannot modify this import statement, because the program is not exactly mine.
I wish to link to ModuleA.external_function in the documentation for ModuleA, in the comments above a function called my_function. So the code looks something like this:
-- | my_function makes use of 'ModuleA.external_function'
my_function :: Int -> Int
Using haddock 2.10.0, and running cabal haddock, the link to ModuleA.external_function is generated as dist/doc/html/MyModule/ModuleA.html#v:external_function . However, the problem is that the dist/doc/html/MyModule/ModuleA.html file does not exist.
How can I generate a link to the docs for ModuleA instead, like module-A-package/docs/ModuleA.html#v:external_function. In other words, something similar to what http://hackage.haskell.org/package/text-0.11.2.0/docs/Data-Text.html has for its links to the String type (they link to http://hackage.haskell.org/package/base-4.5.0.0/docs/Data-String.html#t:String)? Bear in mind that I cannot modify the import statement.
Thank you.
To make links to external packages in the Haddock documentation, you need to instruct it where to find the documentation for those packages.
It is done by using the --read-interface Haddock command-line option.
Using your example, it will be :
haddock --read-interface module-A-package/docs/,module-A-package/docs/module-A-package.haddock
The .haddock file is made when generating documentation for the package module-A-package using ----dump-interface Haddock command-line option.
More information can be found on the Haddock documentation or this HaskellWiki page.

Where can I learn about #ifdef?

I see this used often to make modules compatible with GHC and Hugs, but google is not helping me learn more about it.
What can I put inside the conditional? Can I make parts of a module conditional on what version of 'base' is in use?
EDIT 3/2017: This is a great resource: https://guide.aelve.com/haskell/cpp-vww0qd72
The GHC documentation has a section relating to the C pre-processor that documents some of the predefined
pre-processor macros.
The Cabal documentation has a section relating to conditional compilation that gives an example relating to base. If you are writing a portable package, you should be using Cabal, anyway.
In addition to the very useful flags defined by GHC (OS, architecture, etc), when using cabal other flags and macros are defined.
Check Package Versions
Here's a use from crypto-api that checks the version of the tagged package being used:
#if MIN_VERSION_tagged(0,2,0)
import Data.Proxy
#endif
Custom CPP Defines Based on Cabal Flags
You can define CPP symbols dependent on cabal flags. Here's an (unnecessarily complex) example from pureMD5 (from the .cabal file):
if arch(i386) || arch(x86_64)
cpp-options: -DFastWordExtract
Inside the .hs module you can then use #ifdef, for example:
#ifdef FastWordExtract
getNthWord n b = inlinePerformIO (unsafeUseAsCString b (flip peekElemOff n . castPtr))
#else
... other code ...
#endif
For more information you can see the Cabal users guide. This page has the "conditional compilation" information you're probably looking for.
#ifdef and friends are used by the C preprocessor (CPP). They provide a way to compile code conditionally. You can enable the use of the CPP by adding the pragma {-# LANGUAGE CPP #-} on top of a file.
Many programs that deal with Haskell code set some macros for the preprocessor (eg. GHC sets __GLASGOW_HASKELL__ to the version of GHC), so one can conditionally compile code, for instance to use different properitary libraries for Hugs and GHC.
If you run your Haskell compiler with the -cpp option, it will first preprocess the source files with the CPP (C Pre Processor).
Take a look at the section 4.11.3. Options affecting the C pre-processor here.

Haddock, Cabal: How to include source code examples?

I am the author of the operational package, which includes example code. I would like this example code to be hscolored and installed together with the API documentation, which is generated by Haddock.
I probably have to use a custom Cabal build type and create a user hook for the Haddock phase. However, I never managed to make this work. Hence, my question is:
How to include full modules as example code in Haddock?
Could you give an example of a Cabal user hook that applies hscolor to an additional source code file example.hs and joins the result with the generated Haddock documentation?
I'm a total Haskell nube and this is a shot in the dark, but couldn't you use hscolour to output the code as HTML and then do something along the lines of cabal haddock --executables --hyperlink-source to include the colorized HTML?

Resources