On Thursday 17 July 2025 23:32:50 Martin Storsjö wrote:
> On Thu, 17 Jul 2025, Pali Rohár wrote:
> 
> > When mingw-w64 is compiled with LTO support (-flto and -ffat-lto-objects in
> > CFLAGS and LDFLAGS) then simple C application
> > 
> >    int main(void) { return 0; }
> > 
> > cause LTO compile warning:
> > 
> >    $ gcc test.c -o test.exe -flto
> >    ./include/internal.h:113:17: warning: type of ‘main’ does not match 
> > original declaration [-Wlto-type-mismatch]
> >    test.c:1:5: note: type mismatch in parameter 1
> >     int main(void) { return 0; }
> >         ^
> >    test.c:1:5: note: type ‘void’ should match type ‘int’
> >    test.c:1:5: note: ‘main’ was previously declared here
> > 
> > This is because internal.h defines main as:
> > 
> >    int __CRTDECL main(int _Argc, char **_Argv, char **_Env);
> > 
> > Which does not match the main in test.c application.
> > 
> > Function main is somehow special that it can take from zero to three
> > parameters. So define it in internal.h file without parameters. This will
> > mute the gcc LTO warning which is printed by default.
> > 
> > Same applies for wmain() function.
> > ---
> > mingw-w64-crt/include/internal.h | 7 +++++--
> > 1 file changed, 5 insertions(+), 2 deletions(-)
> > 
> > diff --git a/mingw-w64-crt/include/internal.h 
> > b/mingw-w64-crt/include/internal.h
> > index 997a89b189a1..e68296a4123f 100644
> > --- a/mingw-w64-crt/include/internal.h
> > +++ b/mingw-w64-crt/include/internal.h
> > @@ -110,8 +110,11 @@ extern "C" {
> >   int __CRTDECL _wsetargv(void);
> >   int __CRTDECL __wsetargv(void);
> > 
> > -  int __CRTDECL main(int _Argc, char **_Argv, char **_Env);
> > -  int __CRTDECL wmain(int _Argc, wchar_t **_Argv, wchar_t **_Env);
> > +  /* Do not define main parameters because then it cause LTO compile
> > +   * warning (-Wlto-type-mismatch) about mismatches parameters when
> > +   * application defines main as: int main(void) { ... } */
> > +  int __CRTDECL main(/*int _Argc, char **_Argv, char **_Env*/);
> > +  int __CRTDECL wmain(/*int _Argc, wchar_t **_Argv, wchar_t **_Env*/);
> 
> How does this behave if compiling things in C23 mode (I guess both
> mingw-w64-crt and the end user application)? In C23, an empty parameter
> list, func(), should be equivalent to func(void), while it in earlier
> language versions allowed any number of parameters.

I did some tests. Source code:

    $ cat main.c
    int main(void) { return 0; }
    $ cat __main.c
    __attribute__((used)) void __main(void) {}

Compile flags (all without any -W warning flags):

    -flto -O2 mainCRTStartup.c main.c __main.c -o test.exe -nostartfiles 
-nostdlib -nodefaultlibs


Tests with all arguments in main prototype:

    $ cat mainCRTStartup.c
    int main(int argc, char **argv, char **envp);
    __attribute__((used)) int mainCRTStartup(void) { return main(1, (char *[]){ 
"arg0", (char *)0 }, (char **)0); }

    gcc-14 -std=c23 ... -std=c2x ... -std=c17 ... -std=c89

        mainCRTStartup.c:1:5: warning: type of 'main' does not match original 
declaration [-Wlto-type-mismatch]
            1 | int main(int argc, char **argv, char **envp);
              |     ^
        main.c:1:5: note: type mismatch in parameter 1
            1 | int main(void) { return 0; }
              |     ^
        main.c:1:5: note: type 'void' should match type 'int'
        main.c:1:5: note: 'main' was previously declared here


    gcc-12 -std=c2x ... -std=c17 ... -std=c89

        mainCRTStartup.c:1:5: warning: type of ‘main’ does not match original 
declaration [-Wlto-type-mismatch]
            1 | int main(int argc, char **argv, char **envp);
              |     ^
        main.c:1:5: note: type mismatch in parameter 1
            1 | int main(void) { return 0; }
              |     ^
        main.c:1:5: note: type ‘void’ should match type ‘int’
        main.c:1:5: note: ‘main’ was previously declared here


    gcc-8 -std=c17 ... -std=c89

        mainCRTStartup.c:1:5: warning: type of ‘main’ does not match original 
declaration [-Wlto-type-mismatch]
         int main(int argc, char **argv, char **envp);
             ^
        main.c:1:5: note: type mismatch in parameter 1
         int main(void) { return 0; }
             ^
        main.c:1:5: note: type ‘void’ should match type ‘int’
        main.c:1:5: note: ‘main’ was previously declared here


Tests without arguments in main prototype:

    $ cat mainCRTStartup.c
    int main();
    __attribute__((used)) int mainCRTStartup(void) { return main(1, (char *[]){ 
"arg0", (char *)0 }, (char **)0); }

    gcc-14 -std=c23 ... -std=c2x

        mainCRTStartup.c: In function 'mainCRTStartup':
        mainCRTStartup.c:2:57: error: too many arguments to function 'main'
            2 | __attribute__((used)) int mainCRTStartup(void) { return main(1, 
(char *[]){ "arg0", (char *)0 }, (char **)0); }
              |                                                         ^~~~
        mainCRTStartup.c:1:5: note: declared here
            1 | int main();
              |     ^~~~


    gcc-14 -std=c17 ... -std=c89

        (no warnings, no errors)


    gcc-12 -std=c2x ... -std=c17 ... -std=c89

        (no warnings, no errors)


    gcc-8 -std=c17 ... -std=c89

        (no warnings, no errors)


So my above change is fixing warnings for c17 and below, but is causing
new compile errors for c23 when compiling the mainCRTStartup.

Note that warning is printed automatically without specifying any -W
option and is for all applications which uses "int main(void) { ... }"

I have no idea now how to fix that compile warning with having crtexe.c
compatibility with c23 and up.

> (Also, I'm aware of your other older patches awaiting response - I'm
> currently vacationing so I don't have enough bandwidth to dig through all of
> my review backlog.)
> 
> // Martin

That is fine, just look at them when you are back and have time.


_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to