can't link haskell without "main" function, or -no-hs-main broken on windows?
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 <windows.h>
#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.
Trac metadata
Trac field | Value |
---|---|
Version | 6.8.2 |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Driver |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture | Unknown |