id,summary,reporter,owner,description,type,status,priority,milestone,component,version,resolution,keywords,cc,os,architecture,failure,testcase,blockedby,blocking,related,differential
2459,"can't link haskell without ""main"" function, or -no-hs-main broken on windows?",jvl,,"can't link haskell without ""main"" function, or -no-hs-main broken on windows?
The issue arose when trying to compile wxHaskell examples with a !WinMain entry point in
the executable rather than the standard ""main"" function, thereby stopping a new console
window being created when the application starts up, i.e. creating a ""windows"" application.
luckily (by chance, I think) the desired objective can be achieved without any change to the haskell
code as follows, with the support that gcc already provides for a !WinMain entry point,
utilising the wxHaskell example:
{{{
> ghc -o HelloWorl.o -fglasgow-exts -c HelloWorld.hs
> ghc -optl-mwindows -o HelloWorld.exe HelloWorld.o -package wxcore
}}}
OK, so what is the issue ? We what if we want to define our own !WinMain or utilise the
!WinMain or other entry point provided by another object file or code. According to the
ghc documentation the way it could be achieved would be, with this example ...
!MyHelloWorld.hs ..
{{{
> module Hello where
>
> foreign export ccall ""runHsMain"" runMain :: IO ()
>
> runMain = do
> putStrLn ""Hello World""
}}}
and mymain.c
{{{
#include ""HsFFI.h""
extern void __stginit_Hello ( void );
extern void runHsMain();
int main(int argc, char* argv[])
{
hs_init(&argc, &argv);
hs_add_root(__stginit_Hello);
runHsMain();
hs_exit();
return 0;
}
}}}
{{{
> ghc -c -fglasgow-exts -o MyHelloWorld.o MyHelloWorld.hs
> ghc -o hello.exe mymain.c MyHelloWorld.o MyHelloWorld_stub.o
> hello.exe
Hello World
}}}
all works fine, but dosn't ghc documentation say, the -no-hs-main option should be used ? OK so use it
{{{
> ghc -no-hs-main -c -fglasgow-exts -o MyHelloWorld.o MyHelloWorld.hs
> ghc -no-hs-main -o hello.exe mymain.c MyHelloWorld.o MyHelloWorld_stub.o
> hello.exe
Hello World
}}}
OK, works both with and without -no-hs-main, strange?
but how about if we want to define our own !WinMain or dllMain etc (i.e. no main at all)
winmain.c:
{{{
#include
#include ""HsFFI.h""
extern void __stginit_Hello ( void );
extern void runHsMain();
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
hs_init(0, 0);
hs_add_root(__stginit_Hello);
hs_exit();
return 0;
}
}}}
you can use the above haskell hello example or the wxHaskell !HelloWorld example
but with edits to main/module name as per !MyHelloWorld, call it !MyHelloWorldW.
But the above Haskell suffices as a test case, and is used in the
following.
linking with winmain, we get this error:
{{{
>ghc -no-hs-main -o winhello.exe winmain.c MyHelloWorld.o MyHelloWorld_stub.o
C:/apps/ghc/6.8.2/libHSrts.a(Main.o)(.text+0x7):Main.c: undefined reference to `
__stginit_ZCMain'
C:/apps/ghc/6.8.2/libHSrts.a(Main.o)(.text+0x36):Main.c: undefined reference to
`ZCMain_main_closure'
collect2: ld returned 1 exit status
}}}
it appears ghc does something like this (normal operation, for a standard haskell main)
* create bootstrapping that initialises the ghc runtime and adds the root !__stginit_ZCMain, and runs the haskell main
* create a ""c"" main that calls/executes the bootstrapping code
* the executables entry point will be set by default to the ""c"" ""main"" procedure
it seems that linking the haskell object with an object that already contains a main symbol will:
* suppress the creation of bootstrapping code
* executable entry point still set to the default (""main"")
this behaviour is exhibitted regardless of -no-hs-main option
When the haskell objects are linked with other objects and even though -no-hs-main option is
specified it appears that ghc:
* creates bootstrapping that initialises the ghc runtime and adds the root !__stginit_ZCMain, and runs the haskell main
* creates a main that calls/executes the bootstrapping code
* executable entry point still set to the default (""main"")
i.e. the same behaviour as for ""normal"" execution, this behaviour appears wrong, the behaviour should be:
* suppress the creation of bootstrapping code (initialisation of haskell
should be the responsibility of the external code, per guidlines)
* executable entry point still set to default
i.e., as in the above example hs_add_root initialises the root module (!__stginit_Hello)
and there is no requirement for an !__stginit_ZCMain.
you can get the above example to compile and link with ...
{{{
>ghc -main-is Hello.runMain -c -fglasgow-exts -o MyHelloWorld.o MyHelloWorld.hs
>ghc -o winhello.exe winmain.c MyHelloWorld.o MyHelloWorld_stub.o
}}}
but if this is the wxHaskell !HelloWorld example, you would see that the it still starts up as a console
application and not a !WinMain (windows) application.
the effect of using th -main-is option is to insert a ""!___stginit_ZCMain"" symbol into the !HelloWorld.o
object. A ""c"" ""main"" will be created, initialising haskell and invoking the haskell main Hell.runMain.
The entry point of the executable will be this ""main"", i.e. regard,
[link with ldl-mwindows to set entry to win32,see what happens]
{{{
> ghc -main-is Hello.runMain -c -fglasgow-exts -o MyHelloWorld.o MyHelloWorld.hs
> ghc -o winhello.exe winmain.c MyHelloWorld.o MyHelloWorld_stub.o
}}}
the above will compile and run but, will not invoke the winmain, rather it will invoke the
automatically generated ""main"".
the following
{{{
> ghc -main-is Hello.runMain -c -fglasgow-exts -o MyHelloWorld.o MyHelloWorld.hs
> ghc -optl-mwindows -o winhello.exe winmain.c MyHelloWorld.o MyHelloWorld_stub.o
>winhello
}}}
will invoke the !WinMain routine as a windows application, (in this example a popup will be displayed
reporting an error ""hPutChar invalid arg bad file descriptor"", as it should), ignoring the haskell
supplied main/init.
BUT you shouldn't have to compile the haskell module with -main-is ... in order to get the overall exe to link , i.e. the following should work
{{{
>ghc -no-hs-main -c -fglasgow-exts -o MyHelloWorld.o MyHelloWorld.hs
>ghc -optl-mwindows -o winhello.exe winmain.c MyHelloWorld.o MyHelloWorld_stub.o
}}}
but we get ...
{{{
C:/apps/ghc/6.8.2/libHSrts.a(Main.o)(.text+0x7):Main.c: undefined reference to `
__stginit_ZCMain'
C:/apps/ghc/6.8.2/libHSrts.a(Main.o)(.text+0x36):Main.c: undefined reference to
`ZCMain_main_closure'
collect2: ld returned 1 exit status
}}}
what should be:
* no-hs-main option should suppress the requirement for a !___stginit_ZCMain symbol, this should enable
the linking of, and specification of an arbitrary entry point into the executable external to the
haskell code.
i.e. the last example should work.
the -optl-mwindows on the ghc command line we can flip the .exe entry point for the executable to a windows
entry point, gcc seems to handle it as follows: if the above -mwindows option is given then the entry point
of the executable is set to !WinMainCRTStartup, which in turn calls the !WinMain function (if present) or
the supplied main, it also sets the subsystem to windows.",bug,new,lowest,7.12.1,Driver,6.8.2,,,dterei,Windows,Unknown/Multiple,Compile-time crash,,,,,