
I was under the impression that with ghc, ffi import declarations like this do not escape the module: foreign import ccall unsafe "foo.h foo" foo :: IO () However it seems that this one does: foreign import ccall unsafe "curses.h & stdscr" stdscrp :: Ptr WINDOWptr from: http://hackage.haskell.org/cgi-bin/hackage-scripts/package/mage-1.0 perhapsPbecause it's a pointer import it gets treated differently? Is this correct and expected behaviour? It's hard to tell what header files need to be used globally and inherited by client packages and which can safely be used privately. Duncan

On Wed, Mar 05, 2008 at 11:16:14PM +0000, Duncan Coutts wrote:
I was under the impression that with ghc, ffi import declarations like this do not escape the module:
foreign import ccall unsafe "foo.h foo" foo :: IO ()
GHC can inline the stub across module (and thus package) boundaries, so the #include can escape.
It's hard to tell what header files need to be used globally and inherited by client packages and which can safely be used privately.
No, it's easy: they're all potentially inherited.

On Wed, 2008-03-05 at 23:46 +0000, Ross Paterson wrote:
On Wed, Mar 05, 2008 at 11:16:14PM +0000, Duncan Coutts wrote:
I was under the impression that with ghc, ffi import declarations like this do not escape the module:
foreign import ccall unsafe "foo.h foo" foo :: IO ()
GHC can inline the stub across module (and thus package) boundaries, so the #include can escape.
I've been informed before that: foreign import ccall unsafe "foo" foo :: IO () can escape and needs -#include on the command line and for all client code. However for ghc: foreign import ccall unsafe "foo.h foo" foo :: IO () does not escape because ghc does not track which .h file should be #included later. It's not that it couldn't escape according to the FFI spec but that ghc currently does not do cross-module inlining for such declarations. That's what I've been told and it's the behaviour I've observed, except for the case I noted. Quite a few packages rely on ghc's behaviour on this, or just rely on the fact that in practise things do not get inlined that aggressively. If we started looking carefully I think we'd find most hackage packages that use FFI get this wrong.
It's hard to tell what header files need to be used globally and inherited by client packages and which can safely be used privately.
No, it's easy: they're all potentially inherited.
Which is really annoying :-) I'd like greater control over it, in particular a way to limit headers to package scope so that dependent code does not need the headers. Duncan

On Thu, Mar 06, 2008 at 12:23:35AM +0000, Duncan Coutts wrote:
However for ghc:
foreign import ccall unsafe "foo.h foo" foo :: IO ()
does not escape because ghc does not track which .h file should be #included later. It's not that it couldn't escape according to the FFI spec but that ghc currently does not do cross-module inlining for such declarations. That's what I've been told and it's the behaviour I've observed, except for the case I noted.
Ah yes, I remember that now.

On Thu, Mar 06, 2008 at 12:23:35AM +0000, Duncan Coutts wrote:
Which is really annoying :-) I'd like greater control over it, in particular a way to limit headers to package scope so that dependent code does not need the headers.
Ideally there would be no need for headers at all. Everything needed is inherently in the foreign declaration. If anything, the headers should just be used as a sanity check, not actually to affect the generated code. It would be nice if ghc just stopped relying on them and ignored them altogether. John -- John Meacham - ⑆repetae.net⑆john⑈

On Wed, 2008-03-05 at 17:37 -0800, John Meacham wrote:
On Thu, Mar 06, 2008 at 12:23:35AM +0000, Duncan Coutts wrote:
Which is really annoying :-) I'd like greater control over it, in particular a way to limit headers to package scope so that dependent code does not need the headers.
Ideally there would be no need for headers at all. Everything needed is inherently in the foreign declaration. If anything, the headers should just be used as a sanity check, not actually to affect the generated code. It would be nice if ghc just stopped relying on them and ignored them altogether.
We're going to have to figure out what to do with crazy header files that use lots of macros. For example the mage-1.1.0 package does not compile without -fvia-C. This is because of the curses.h interface. For example: foreign import ccall unsafe "curses.h & ACS_UARROW" acs_uarrow :: Ptr ChType And what is "ACS_UARROW"? We might hope it's a pointer with a corresponding linker symbol. Sadly not: #define ACS_UARROW NCURSES_ACS('-') /* arrow pointing up */ where: #define NCURSES_ACS(c) (acs_map[NCURSES_CAST(unsigned char,c)]) extern NCURSES_EXPORT_VAR(chtype) acs_map[]; Yay, it's an index into an array. So that obviously does not work. If we compile without going via C we get a linker error because there is no ACS_UARROW linker symbol. If we compile via C then through a bit of luck it seems to compile. There are rather too many of these C libs that define their public interfaces as macros. I had to adjust the zlib binding the other day to allow it to compile without -fvia-C. It now implements a couple macros in the Haskell code. I hope zlib don't change their macro in the next version. Duncan

On Thu, Mar 06, 2008 at 02:18:08AM +0000, Duncan Coutts wrote:
foreign import ccall unsafe "curses.h & ACS_UARROW" acs_uarrow :: Ptr ChType
#define ACS_UARROW NCURSES_ACS('-') /* arrow pointing up */
You ought to use a C wrapper around these sorts of things. If you're lucky, the API docs will tell you which values and functions might be macros, e.g. http://www.opengroup.org/onlinepubs/007908799/xcurses/curses.h.html is clear about what is (or might be) what. I can't remember if it's been discussed before, but I think it might be a good idea for the FFI to be able to create these C stubs itself, if you give a certain keyword - or perhaps even by default as it's the safe thing to do, at the expense of performance. Thanks Ian

On Thu, Mar 06, 2008 at 02:39:35AM +0000, Ian Lynagh wrote:
I can't remember if it's been discussed before, but I think it might be a good idea for the FFI to be able to create these C stubs itself, if you give a certain keyword - or perhaps even by default as it's the safe thing to do, at the expense of performance.
The FFI defines an ABI spec, not an API one. As in, a C compiler is never inherently involved, (hence the ability to have Haskell compilers with a pure assembly back end). Tools like hsc2hs are there to bridge the gap to a particular language when needed. Some libraries guarantee an ABI, others just an API. Hopefully it is documented. :). In general, in order to support dynamic linking, the ABI must remain stable so tools like 'hsc2hs' often aren't needed when interfacing to C code. In any case, it is not the FFI's job, though of course, specific Haskell compilers are free to provide extensions. But I'd rather see GHC get further away from C idiosyncrasies instead of closer. John -- John Meacham - ⑆repetae.net⑆john⑈

On Thu, Mar 06, 2008 at 02:18:08AM +0000, Duncan Coutts wrote:
There are rather too many of these C libs that define their public interfaces as macros. I had to adjust the zlib binding the other day to allow it to compile without -fvia-C. It now implements a couple macros in the Haskell code. I hope zlib don't change their macro in the next version.
Yeah, I ran into the exact same issue with my curses binding. the solution was to use hsc2hs to create wrappers when needed. something like this: foreign import ccall "get_COLOR_PAIRS" colorPairsPtr :: Ptr CInt #def inline int * get_COLOR_PAIRS (void) {return &COLOR_PAIRS;} hsc2hs is needed anyway for portable C bindings so it isn't too onerous of a requirement. John -- John Meacham - ⑆repetae.net⑆john⑈

On Wed, 2008-03-05 at 18:46 -0800, John Meacham wrote:
On Thu, Mar 06, 2008 at 02:18:08AM +0000, Duncan Coutts wrote:
There are rather too many of these C libs that define their public interfaces as macros. I had to adjust the zlib binding the other day to allow it to compile without -fvia-C. It now implements a couple macros in the Haskell code. I hope zlib don't change their macro in the next version.
Yeah, I ran into the exact same issue with my curses binding. the solution was to use hsc2hs to create wrappers when needed.
something like this:
foreign import ccall "get_COLOR_PAIRS" colorPairsPtr :: Ptr CInt #def inline int * get_COLOR_PAIRS (void) {return &COLOR_PAIRS;}
The problem with that is that it doesn't follow the rules about scope of header files either. Technically the little .h file that hsc2hs generates for you needs to be installed and used by every client package.
hsc2hs is needed anyway for portable C bindings so it isn't too onerous of a requirement.
Or c2hs! :-) Duncan

On Thu, Mar 06, 2008 at 10:43:41AM +0000, Duncan Coutts wrote:
something like this:
foreign import ccall "get_COLOR_PAIRS" colorPairsPtr :: Ptr CInt #def inline int * get_COLOR_PAIRS (void) {return &COLOR_PAIRS;}
The problem with that is that it doesn't follow the rules about scope of header files either. Technically the little .h file that hsc2hs generates for you needs to be installed and used by every client package.
no, because your stub functions have a well defined ABI (that was the point of the stub functions after all), so you wouldn't need to keep the header around in general assuming the compiler supported header-less compilation (which ghc doesn't yet AFAIK). I always thought c2hs should actually generate hsc files. That would allow people to compile programs that use c2hs without having to install c2hs on their build machines. hsc2hs is the minimal tool needed to write portable C interfaces so needs to be installed on target systems anyway. John -- John Meacham - ⑆repetae.net⑆john⑈

On Thu, 2008-03-06 at 03:11 -0800, John Meacham wrote:
On Thu, Mar 06, 2008 at 10:43:41AM +0000, Duncan Coutts wrote:
something like this:
foreign import ccall "get_COLOR_PAIRS" colorPairsPtr :: Ptr CInt #def inline int * get_COLOR_PAIRS (void) {return &COLOR_PAIRS;}
The problem with that is that it doesn't follow the rules about scope of header files either. Technically the little .h file that hsc2hs generates for you needs to be installed and used by every client package.
no, because your stub functions have a well defined ABI (that was the point of the stub functions after all), so you wouldn't need to keep the header around in general assuming the compiler supported header-less compilation (which ghc doesn't yet AFAIK).
Well ghc does both. If you compile the above -fvia-C then you may well get warnings from gcc about missing prototypes, if you compile -fasm then ghc believes the ABI given by the FFI decl. It also seems I thought the ffi spec said more about headers than it actually does. :-)
I always thought c2hs should actually generate hsc files. That would allow people to compile programs that use c2hs without having to install c2hs on their build machines. hsc2hs is the minimal tool needed to write portable C interfaces so needs to be installed on target systems anyway.
c2hs has to read the header files on your system to be able to check any consistency. I'm not sure why hsc2hs is the minimal tool. It relies on a C compiler where c2hs does not. What happens with Haskell implementations that do not bundle a C compiler (eg ghc in future on win32)? Duncan

On Thu, Mar 06, 2008 at 12:41:56PM +0000, Duncan Coutts wrote:
c2hs has to read the header files on your system to be able to check any consistency.
I'm not sure why hsc2hs is the minimal tool. It relies on a C compiler where c2hs does not. What happens with Haskell implementations that do not bundle a C compiler (eg ghc in future on win32)?
Hmm... I am not quite sure how c2hs works then. like, how can it figure out the offsets of fields in data structures without knowing the field layout algorithm for a given architecture/os combo without invoking a c compiler? Though, if there were a way to figure that stuff out without a c compiler in a portable way, that would be cool. John -- John Meacham - ⑆repetae.net⑆john⑈

On Thu, 2008-03-06 at 04:50 -0800, John Meacham wrote:
On Thu, Mar 06, 2008 at 12:41:56PM +0000, Duncan Coutts wrote:
c2hs has to read the header files on your system to be able to check any consistency.
I'm not sure why hsc2hs is the minimal tool. It relies on a C compiler where c2hs does not. What happens with Haskell implementations that do not bundle a C compiler (eg ghc in future on win32)?
Hmm... I am not quite sure how c2hs works then. like, how can it figure out the offsets of fields in data structures without knowing the field layout algorithm for a given architecture/os combo without invoking a c compiler?
It's calculated directly.
Though, if there were a way to figure that stuff out without a c compiler in a portable way, that would be cool.
It is specified by the platform C ABI. So it varies from one platform to another, but it is specified for most platforms, that's what allows you to link code compiled by different C compilers and have it work. Duncan

On Fri, Mar 07, 2008 at 03:04:46AM +0000, Duncan Coutts wrote:
Though, if there were a way to figure that stuff out without a c compiler in a portable way, that would be cool.
It is specified by the platform C ABI. So it varies from one platform to another, but it is specified for most platforms, that's what allows you to link code compiled by different C compilers and have it work.
Yeah, I was thinking about a potentially unknown platform, so you can distribute portable code that is only localized when it is finally compiled for the given platform. Though, I should look at that code for calculating the offsets in c2hs, those could come in handy. I have some code in jhc to take a generic jhc library and specialize it for a given architecture, adding the ability to figure out structure offsets would be useful too. The idea is that to install a jhc library all you need to do is grab a single 'hl' file and drop it somewhere, but you can optionally re-optimize it specifically for your platform, (presumably after pulling it down from the web or hackage or somewhere..) John -- John Meacham - ⑆repetae.net⑆john⑈

John Meacham wrote:
On Thu, Mar 06, 2008 at 12:23:35AM +0000, Duncan Coutts wrote:
Which is really annoying :-) I'd like greater control over it, in particular a way to limit headers to package scope so that dependent code does not need the headers.
Ideally there would be no need for headers at all. Everything needed is inherently in the foreign declaration. If anything, the headers should just be used as a sanity check, not actually to affect the generated code. It would be nice if ghc just stopped relying on them and ignored them altogether.
Yeah, I'd like -fvia-C to be headerless. We talked about it a while back (on the haskell-prime list I think). The main issue is that GHC would have to generate prototypes based on the FFI declaration, and since it can't guarantee to generate a prototype that is exactly the same as the C prototype given in the header file (e.g. it doesn't know about const), we would have to ensure that there really are no other prototypes in scope, to prevent errors from the C compiler. One reason I want to do this is that it would make via-C compilation less fragile, particularly in terms of getting the .cabal file right. Via-C compilation is about to get a lot less common - in 6.10 it'll only be used for bootstrapping, so we don't want a significant fraction of libraries fail to work when bootstrapped via C due to missing include-files declarations. Cheers, Simon

On Tue, Mar 11, 2008 at 02:47:37PM -0700, Simon Marlow wrote:
Yeah, I'd like -fvia-C to be headerless. We talked about it a while back (on the haskell-prime list I think). The main issue is that GHC would have to generate prototypes based on the FFI declaration, and since it can't guarantee to generate a prototype that is exactly the same as the C prototype given in the header file (e.g. it doesn't know about const), we would have to ensure that there really are no other prototypes in scope, to prevent errors from the C compiler.
I was thinking that you just wouldn't include any extra c headers at all then, just write out the appropriate c code to call with the conventions specified in the ffi import specification and you won't need external headers at all so there isn't anything to conflict with. John -- John Meacham - ⑆repetae.net⑆john⑈

John Meacham wrote:
On Tue, Mar 11, 2008 at 02:47:37PM -0700, Simon Marlow wrote:
Yeah, I'd like -fvia-C to be headerless. We talked about it a while back (on the haskell-prime list I think). The main issue is that GHC would have to generate prototypes based on the FFI declaration, and since it can't guarantee to generate a prototype that is exactly the same as the C prototype given in the header file (e.g. it doesn't know about const), we would have to ensure that there really are no other prototypes in scope, to prevent errors from the C compiler.
I was thinking that you just wouldn't include any extra c headers at all then, just write out the appropriate c code to call with the conventions specified in the ffi import specification and you won't need external headers at all so there isn't anything to conflict with.
Yes, pretty much. There are a bunch of C headers that define the macros used by the generated C code, and we have to be careful that they don't include anything external - in the past we used to #include several things from /usr/include, but I think we're much cleaner these days. Cheers, Simon

Simon Marlow wrote:
John Meacham wrote:
On Tue, Mar 11, 2008 at 02:47:37PM -0700, Simon Marlow wrote:
Yeah, I'd like -fvia-C to be headerless. We talked about it a while back (on the haskell-prime list I think). The main issue is that GHC would have to generate prototypes based on the FFI declaration, and since it can't guarantee to generate a prototype that is exactly the same as the C prototype given in the header file (e.g. it doesn't know about const), we would have to ensure that there really are no other prototypes in scope, to prevent errors from the C compiler.
I was thinking that you just wouldn't include any extra c headers at all then, just write out the appropriate c code to call with the conventions specified in the ffi import specification and you won't need external headers at all so there isn't anything to conflict with.
Yes, pretty much. There are a bunch of C headers that define the macros used by the generated C code, and we have to be careful that they don't include anything external - in the past we used to #include several things from /usr/include, but I think we're much cleaner these days.
FYI, I've now done this: GHC 6.10 will consistently ignore c-includes and header files in FFI declarations. Cheers, Simon

On Sat, Mar 15, 2008 at 12:32:29AM -0700, Jason Dusek wrote:
Simon Marlow
wrote: GHC...can't guarantee to generate a prototype that is exactly the same as the C prototype given in the header file (e.g. it doesn't know about const)...
Why doesn't GHC know about const?
Because the Ptr type doesn't indicate const-ness (perhaps it should).

Hello Jason, Saturday, March 15, 2008, 9:55:38 PM, you wrote:
Because the Ptr type doesn't indicate const-ness (perhaps it should).
If it did, could we read constant strings without unsafePerformIO?
probably no; at least for getArgs it was argued that it should have IO return type because its result is different from run to run -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

Bulat Ziganshin
Saturday, March 15, 2008, 9:55:38 PM, you wrote:
...the Ptr type doesn't indicate const-ness (perhaps it should).
If it did, could we read constant strings without unsafePerformIO?
probably no; at least for getArgs it was argued that it should have IO return type because its result is different from run to run
What does getArgs have to do with it? I'm assuming that reading n elements from a const array will always return the same elements -- is this an error? -- _jsn

Hello Jason, Saturday, March 15, 2008, 10:08:31 PM, you wrote:
probably no; at least for getArgs it was argued that it should have IO return type because its result is different from run to run
What does getArgs have to do with it?
I'm assuming that reading n elements from a const array will always return the same elements -- is this an error?
like getArgs, it may return different values on different runs -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

Bulat Ziganshin
Saturday, March 15, 2008, 10:08:31 PM, you wrote:
What does getArgs have to do with it?
I'm assuming that reading n elements from a const array will always return the same elements -- is this an error?
like getArgs, it may return different values on different runs
Oh, I get it now. Even though it won't change for the life of a process, it can change each time the program is run. However, there is a difference with the array -- because it is statically linked into my Haskell program. Now, it's true that this can not be expected in general (though it's very common for Haskell). -- _jsn

Jason Dusek wrote:
Ross Paterson
wrote: Jason Dusek wrote:
Why doesn't GHC know about const? Because the Ptr type doesn't indicate const-ness (perhaps it should).
If it did, could we read constant strings without unsafePerformIO?
That would be unsound since a const pointer doesn't necessarily point to const data. Constness here only means that the data can't be modified through this particular pointer. Roman

On Sat, Mar 15, 2008 at 12:56:33PM +0000, Ross Paterson wrote:
Because the Ptr type doesn't indicate const-ness (perhaps it should).
Even many of the C people think adding const to the language was a bad idea.. for instance, is strchr(3) const char *strchr(const char *s, int c); or char *strchr(char *s, int c); ? both are useful, the C standard split the different and went with the equally incorrect char *strchr(const char *s, int c); In any case, 'const' is defined to not affect the calling convention at all for a function (in C, I am not sure if this is the case in C++) so there is no need to worry about it for the haskell FFI spec. John -- John Meacham - ⑆repetae.net⑆john⑈

If, following this thread, you conclude that GHC should do something different than what it does, can you submit a Trac ticket? With a small example? Thanks S | -----Original Message----- | From: glasgow-haskell-users-bounces@haskell.org [mailto:glasgow-haskell-users-bounces@haskell.org] On Behalf Of | Duncan Coutts | Sent: 06 March 2008 00:24 | To: Ross Paterson | Cc: glasgow-haskell-users@haskell.org | Subject: Re: scope of header files | | | On Wed, 2008-03-05 at 23:46 +0000, Ross Paterson wrote: | > On Wed, Mar 05, 2008 at 11:16:14PM +0000, Duncan Coutts wrote: | > > I was under the impression that with ghc, ffi import declarations like | > > this do not escape the module: | > > | > > foreign import ccall unsafe "foo.h foo" foo :: IO () | > | > GHC can inline the stub across module (and thus package) boundaries, | > so the #include can escape. | | I've been informed before that: | | foreign import ccall unsafe "foo" foo :: IO () | | can escape and needs -#include on the command line and for all client | code. However for ghc: | | foreign import ccall unsafe "foo.h foo" foo :: IO () | | does not escape because ghc does not track which .h file should be | #included later. It's not that it couldn't escape according to the FFI | spec but that ghc currently does not do cross-module inlining for such | declarations. That's what I've been told and it's the behaviour I've | observed, except for the case I noted. | | Quite a few packages rely on ghc's behaviour on this, or just rely on | the fact that in practise things do not get inlined that aggressively. | If we started looking carefully I think we'd find most hackage packages | that use FFI get this wrong. | | > > It's hard to tell what header files need to be used globally and | > > inherited by client packages and which can safely be used privately. | > | > No, it's easy: they're all potentially inherited. | | Which is really annoying :-) I'd like greater control over it, in | particular a way to limit headers to package scope so that dependent | code does not need the headers. | | Duncan | | _______________________________________________ | Glasgow-haskell-users mailing list | Glasgow-haskell-users@haskell.org | http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

On Thu, 2008-03-06 at 11:12 +0000, Simon Peyton-Jones wrote:
If, following this thread, you conclude that GHC should do something different than what it does, can you submit a Trac ticket? With a small example?
It's probably not worth quibbling about the issue I raised about "foo.h &foo" imports escaping a module when the whole behaviour of "foo.h foo" declarations not escaping is not specified. I'll file a feature request for more explicit control over scope of header files instead. Duncan

Duncan Coutts wrote:
I was under the impression that with ghc, ffi import declarations like this do not escape the module:
foreign import ccall unsafe "foo.h foo" foo :: IO ()
However it seems that this one does:
foreign import ccall unsafe "curses.h & stdscr" stdscrp :: Ptr WINDOWptr
from: http://hackage.haskell.org/cgi-bin/hackage-scripts/package/mage-1.0
perhapsPbecause it's a pointer import it gets treated differently?
I just tried this and couldn't reproduce the problem. ----------------- module Test where import Foreign data WINDOWptr foreign import ccall unsafe "curses.h & stdscr" stdscrp :: Ptr WINDOWptr ----------------- Using -ddump-simpl we can see the declaration marked as NEVER inline, and indeed it doesn't appear in the .hi file. The code that does this is in DsForeign.csCImport, and it certainly looks like it handles the &foo case in addition to normal foreign calls. Maybe there's something else going on.. can you boil down the example at all? Cheers, Simon

On Tue, 2008-03-11 at 16:25 -0700, Simon Marlow wrote:
Duncan Coutts wrote:
from: http://hackage.haskell.org/cgi-bin/hackage-scripts/package/mage-1.0
perhapsPbecause it's a pointer import it gets treated differently?
I just tried this and couldn't reproduce the problem.
Maybe there's something else going on.. can you boil down the example at all?
I can reproduce the problem with the mage-1.0 tarball with the following changes: add -fvia-C to the ghc-options add include-dirs: src Inspecting Main.hc we find things like: _s2oT = *((P_)(W_)&stdscr); that is references to the stdscr pointer. I was trying to get a boiled down example. I started with src/Main and commented stuff out. By commenting out the call to clear_screen the error went away. That's because it's clear_screen from src/Curses.hsc that references stdscrp. I swear it's non-deterministic, even when removing the .hi files before each run. Here's the smallest I can get it: module Curses (screen_size) where import Foreign data WINDOW = WINDOW type WINDOWptr = Ptr WINDOW foreign import ccall unsafe "curses.h & stdscr" stdscrp :: Ptr WINDOWptr screen_size :: IO () screen_size = do stdscr <- peek stdscrp return () module Main (main) where import Curses main = print =<< screen_size And (re-)building using: $ rm Main.hi Curses.hi; ghc-6.8.2 --make -O2 -fvia-C -fffi Main.hs -keep-hc-files [1 of 2] Compiling Curses ( Curses.hs, Curses.o ) [2 of 2] Compiling Main ( Main.hs, Main.o ) In file included from /usr/lib64/ghc-6.8.2/include/Stg.h:150, from Main.hc:3:0: Main.hc: In function ‘Main_a_entry’: Main.hc:46:0: error: ‘stdscr’ undeclared (first use in this function) Main.hc:46:0: error: (Each undeclared identifier is reported only once Main.hc:46:0: error: for each function it appears in.) Inspecting Main.hc we see _sFH = *((P_)(W_)&stdscr); inside the Main_a_entry. The Curses.hc does #include "curses.h" as required. It's Main.hc that does not, despite using &stdscr. Seems that -O2 is not necessary, -O also elicits the failure. ghc --show-iface Curses.hi shows us these interesting exports: screen_size :: GHC.IOBase.IO () {- Arity: 1 HasNoCafRefs Strictness: L Unfolding: (Curses.a `cast` (sym ((GHC.IOBase.:CoIO) ()))) -} a :: GHC.Prim.State# GHC.Prim.RealWorld -> (# GHC.Prim.State# GHC.Prim.RealWorld, () #) {- Arity: 1 HasNoCafRefs Strictness: L Unfolding: (\ s :: GHC.Prim.State# GHC.Prim.RealWorld -> case @ (# GHC.Prim.State# GHC.Prim.RealWorld, () #) GHC.Prim.readAddrOffAddr# @ GHC.Prim.RealWorld __label "stdscr" 0 s of wild2 { (# s2, x #) -> (# s2, GHC.Base.() #) }) -} (re-indented to fit) The __label "stdscr" in a's unfolding is particularly interesting. That looks like the route by which "stdscr" escapes the Curses module and ends up in Main, outside of the scope of the header file. Duncan
participants (10)
-
Bulat Ziganshin
-
Duncan Coutts
-
Ian Lynagh
-
Jason Dusek
-
John Meacham
-
Roman Leshchinskiy
-
Ross Paterson
-
Simon Marlow
-
Simon Marlow
-
Simon Peyton-Jones