scope of header files

Duncan Coutts duncan.coutts at
Wed Mar 12 22:18:48 EDT 2008

On Tue, 2008-03-11 at 16:25 -0700, Simon Marlow wrote:
> Duncan Coutts wrote:

> > from:
> >
> > 
> > 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

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

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
[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’:

     error: ‘stdscr’ undeclared (first use in this function)

     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.RealWorld
                       __label "stdscr"
                       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.


More information about the Glasgow-haskell-users mailing list