ambs / Config-AutoConf

Config::AutoConf Perl Module
Other
2 stars 7 forks source link

t\03.link.t and printf/scanf under cl compiler since VS2014 #17

Open jddurand opened 1 year ago

jddurand commented 1 year ago

C.f. https://rt.cpan.org/Ticket/Display.html?id=144735

jddurand commented 1 year ago

Hi Jens,

1) especially for the patches, can you open a Pull Request on Github? > We can much easier give feedback then.

Sure sorry about that.

2) Can you imagine to figure out the cl parameter to turn off the inline/pragma behaviors? I remember clang had a similar issue, too. It was 'fixes' by using a compiler switch to avoid such false negatives.

In fact the source being tested contains no include, so compilation truely emits a dependency on "printf" symbol (_printf from linker point of view). In a sense Config::AutoConf generated source is correct IMHO. Adding a preprocessor flag like _NO_CRT_STDIO_INLINE changed indeed nothing. There is a pragma like __declspec(noinline) but for other purposes.

Generated source is:

/* defined when stdio.h is available */
#define HAVE_STDIO_H 1
/* end of conftest.h */

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C" {
#endif
char printf ();
#ifdef __cplusplus
}
#endif

  int
  main ()
  {
    return printf ();;
    return 0;
  }

As per https://learn.microsoft.com/en-us/cpp/porting/visual-cpp-change-history-2003-2015?redirectedfrom=MSDN&view=msvc-170#BK_CRT there is still a way to find "printf" symbol, starting from Visual Studio 2014! It is to link using a new library: legacy_stdio_definitions.lib . I tried and indeed this is working, by adding legacy_stdio_definitions.lib to Config::Autoconf constructor:

ok($ac_1 = Config::AutoConf->new(logfile => "config3.log", extra_link_flags => [ "legacy_stdio_definitions.lib" ]), "Instantiating Config::AutoConf for check_lib() tests"); /But/ I failed to use search_libs to determine if legacy_stdio_definitions.lib is available.

So I wonder what is the best solution according to you. I see now:

Thanks for your help,

Cheers, JD.

jddurand commented 1 year ago

The diff file discussed in RT that is "fixing" the issue by bypassing the symbols documented by Microsoft to be a CRT breakage. 03.link.t.corrected.diff.txt

rehsack commented 1 year ago

Hi Jens,

  1. especially for the patches, can you open a Pull Request on Github? > We can much easier give feedback then.

Sure sorry about that.

No worries, I meant only the patches :)

  1. Can you imagine to figure out the cl parameter to turn off the inline/pragma behaviors? I remember clang had a similar issue, too. It was 'fixes' by using a compiler switch to avoid such false negatives.

In fact the source being tested contains no include, so compilation truely emits a dependency on "printf" symbol (_printf from linker point of view). In a sense Config::AutoConf generated source is correct IMHO. Adding a preprocessor flag like _NO_CRT_STDIO_INLINE changed indeed nothing. There is a pragma like __declspec(noinline) but for other purposes.

Unfortunately I have no access to a Windows machine cl - so I cannot prove it on my own.

Generated source is:

/* defined when stdio.h is available */
#define HAVE_STDIO_H 1
/* end of conftest.h */

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C" {
#endif
char printf ();
#ifdef __cplusplus
}
#endif

  int
  main ()
  {
    return printf ();;
    return 0;
  }

As per https://learn.microsoft.com/en-us/cpp/porting/visual-cpp-change-history-2003-2015?redirectedfrom=MSDN&view=msvc-170#BK_CRT there is still a way to find "printf" symbol, starting from Visual Studio 2014! It is to link using a new library: legacy_stdio_definitions.lib . I tried and indeed this is working, by adding legacy_stdio_definitions.lib to Config::Autoconf constructor:

ok($ac_1 = Config::AutoConf->new(logfile => "config3.log", extra_link_flags => [ "legacy_stdio_definitions.lib" ]), "Instantiating Config::AutoConf for check_lib() tests"); /But/ I failed to use search_libs to determine if legacy_stdio_definitions.lib is available.

So I wonder what is the best solution according to you.

Easy: at the moment you cannot say whether cl from vc2014 supports printf() or any other inlined function. This prevents function oriented probes and you have to know how the compiler behaves. That is evil.

I see now:

  • change the symbols being tested
  • do not make the tests fatal
  • detect the existence of legacy_stdio_definitions.lib on MSWin32 ?

I see two more:

Thanks for your help,

Cheers, JD.

jddurand commented 1 year ago

Hello

study vc2014 tweaks to turn off this behavior

The only way I see is to compile with _NO_CRT_STDIO_INLINE but this will have an effect only if it includes stdio.h, and then... compilation will fail because of syntax error.

study vc2014 to find the analogous feature to https://metacpan.org/dist/Config-AutoConf/source/lib/Config/AutoConf.pm#L1661

Not available in cl.

rehsack commented 1 year ago

Hello

study vc2014 tweaks to turn off this behavior

The only way I see is to compile with _NO_CRT_STDIO_INLINE but this will have an effect only if it includes stdio.h, and then... compilation will fail because of syntax error.

Is there a version of stdio.h online at microsoft?

study vc2014 to find the analogous feature to https://metacpan.org/dist/Config-AutoConf/source/lib/Config/AutoConf.pm#L1661

Not available in cl.

In a quick search, I only find Compiler intrinsics which unfortunately not covers printf :(

I also do not see any note regarding the changed linking behavior of e.g. printf.

Edit: I found VS2019 and _NO_CRT_STDIO_INLINE, how to explain this weirdo? - can you try the answer by compiling and linking with /D _NO_CRT_STDIO_INLINE ?

jddurand commented 1 year ago

Is there a version of stdio.h online at microsoft?

I attach the version as of Visual Studio 2022. stdio.h.txt

jddurand commented 1 year ago

Edit: I found VS2019 and _NO_CRT_STDIO_INLINE, how to explain this weirdo? - can you try the answer by compiling and linking with /D _NO_CRT_STDIO_INLINE ?

Yes, I've read this post previously as well, the author is hacking different sources in a different way, that include the header stiod.h for sure. Nevertheless here is the output that you are requesting:

The source generated by Config::Autoconf is:

C:\Users\jddfr\source\repos\ConfigAutoConf_03_links\ConfigAutoConf_03_links>type testprintf.c
/* defined when stdio.h is available */
#define HAVE_STDIO_H 1
/* end of conftest.h */

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C" {
#endif
char printf ();
#ifdef __cplusplus
}
#endif

  int
  main ()
  {
    return printf ();;
    return 0;
  }

Compilation:

C:\Users\jddfr\source\repos\ConfigAutoConf_03_links\ConfigAutoConf_03_links>cl -c /D_NO_CRT_STDIO_INLINE testprintf.c
Compilateur d'optimisation Microsoft (R) C/C++ version 19.32.31332 pour x86
Copyright (C) Microsoft Corporation. Tous droits réservés.

testprintf.c

Link:

C:\Users\jddfr\source\repos\ConfigAutoConf_03_links\ConfigAutoConf_03_links>link testprintf.obj
Microsoft (R) Incremental Linker Version 14.32.31332.0
Copyright (C) Microsoft Corporation.  All rights reserved.

testprintf.obj : error LNK2019: symbole externe non résolu _printf référencé dans la fonction _main
testprintf.exe : fatal error LNK1120: 1 externes non résolus

For the record (I do not think it would be a good solution to do that):

C:\Users\jddfr\source\repos\ConfigAutoConf_03_links\ConfigAutoConf_03_links>link testprintf.obj legacy_stdio_definitions.lib
Microsoft (R) Incremental Linker Version 14.32.31332.0
Copyright (C) Microsoft Corporation.  All rights reserved.

Thanks.

rehsack commented 1 year ago

Edit: I found VS2019 and _NO_CRT_STDIO_INLINE, how to explain this weirdo? - can you try the answer by compiling and linking with /D _NO_CRT_STDIO_INLINE ?

Yes, I've read this post previously as well, the author is hacking different sources in a different way, that include the header stiod.h for sure.

You didn't mention that and I try to find a way not breaking too much else by fixing that. I also took a look how autoconf itself fixes that and it's a bit more intrusive - nevertheless, probably the best way.

Nevertheless here is the output that you are requesting:

The source generated by Config::Autoconf is:

C:\Users\jddfr\source\repos\ConfigAutoConf_03_links\ConfigAutoConf_03_links>type testprintf.c
/* defined when stdio.h is available */
#define HAVE_STDIO_H 1
/* end of conftest.h */

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C" {
#endif
char printf ();
#ifdef __cplusplus
}
#endif

  int
  main ()
  {
    return printf ();;
    return 0;
  }

Compilation:

C:\Users\jddfr\source\repos\ConfigAutoConf_03_links\ConfigAutoConf_03_links>cl -c /D_NO_CRT_STDIO_INLINE testprintf.c
Compilateur d'optimisation Microsoft (R) C/C++ version 19.32.31332 pour x86
Copyright (C) Microsoft Corporation. Tous droits réservés.

testprintf.c

Link:

C:\Users\jddfr\source\repos\ConfigAutoConf_03_links\ConfigAutoConf_03_links>link testprintf.obj
Microsoft (R) Incremental Linker Version 14.32.31332.0
Copyright (C) Microsoft Corporation.  All rights reserved.

testprintf.obj : error LNK2019: symbole externe non résolu _printf référencé dans la fonction _main
testprintf.exe : fatal error LNK1120: 1 externes non résolus

For the record (I do not think it would be a good solution to do that):

C:\Users\jddfr\source\repos\ConfigAutoConf_03_links\ConfigAutoConf_03_links>link testprintf.obj legacy_stdio_definitions.lib
Microsoft (R) Incremental Linker Version 14.32.31332.0
Copyright (C) Microsoft Corporation.  All rights reserved.

Thanks.

Thank you.

My current approach would be following autoconf:

  1. testing for C standard
  2. testing functions based on found C standard

Since I'm short on time - when you could provide such a patch or do it together with me, we can be faster.

But let's sleep 1 or 2 days before hacking, maybe there comes something in mind we don't see right now.