Sorry for the delay in getting back to you.

I shouldn't have put `-subsystem=console` because it'd lead to
confusion in my example.  The point is that, when you compile with
`-subsystem=windows` (which all GUI applications do), you _have_ to
allocate a console; GUI apps have a graphical window but no
command-line interface upon starting.  It is a very common and
sensible usage case to want to have a console alongside your main
window.

In a console-based program, allocation and freopen is done
automatically; in a GUI app, you also need to freopen() or freopen_s()
the stdin/stderr/stdout streams, otherwise your printf outputs will
not show up on the newly allocated console.

In <stdio.h>, stdin/stderr/stdout are dependent on the definition of
either `_iob` or `_imp___iob`.

As mentioned in my earlier threads, both _iob and _imp___iob are
mis-configured in TCC's version of <stdio.h>; even the compiler itself
complains that they must've been declared with __declspec or
__atribute__ ((dllimport).  Also, that is the exact same way it's done
in new MinGW's headers, using the _CRTIMP macro.

I guess using TCC (at least for building full-fledged windows apps) is
rather niche in comparison to "mainstream" compilers (and its `-m32`
compiler even more so), explaining why no one has encountered/reported
this basic bug before.

the _MSVCRT_ macro is really not all that important here; it's just
telling <stdio.h> to use the latest MSVCRT.dll as opposed to "old"
versions of it.  Newer MSVCRT.dll only comes with _iob, because
_imp___iob has been deprecated.

I didn't compile my program with MinGW GCC, but this code is pretty
much the "hello world" equivalent of Win32 consoles and should work
anywhere; it's just a matter of header misconfiguration in TCC's
headers.

To be concise, both _iob and _imp___iob are external symbols that
ought to be provided at runtime via msvcrt.dll (or, in case of
_imp___iob, older versions thereof); the MinGW headers that you linked
correctly label them as __declspec((dllimport)), whereas TCC's headers
don't.  The reason this bug only shows up in the `-m32` version and
not `-m64` is because of line 94 in <stdio.h>

#ifdef _WIN64
  _CRTIMP FILE *__cdecl __iob_func(void);
#else

It "skips" those _iob and _imp__iob stuff on Win64.

On Sun, Nov 24, 2024 at 8:05 PM avih <avih...@yahoo.com> wrote:
>
> Can we maybe start from the begining again?
>
> If you compile with subsusyem=console, why do you need to allocate a console 
> in the first place and then reopen stdout? console apps already do that 
> automatically, like so:
>
> // test.c
> #include <stdio.h>
> int main() {
>     printf("press enter to exit\n");
>     fgetc(stdin);
>     return 0;
> }
>
> And you compile it simply as:
> tcc test.c
>
> Or as in your example (omitting -m32 because I use a native tcc 32, to reduce 
> the number of variables):
> tcc -std=c11 -Wall -Werror -Wl,-subsystem=console test.c
>
> Then if you run it in a console then it prints the message and waits for 
> "enter", and if you double click it in explorer then it opens a console and 
> prints the message in that console and waits for "enter".
>
> Isn't this what you're trying to achieve?
>
> Why is _MSVCRT_ defined in your example? Why is windows.h included in your 
> example?
>
> Maybe you have some other problem, and the example program which you attached 
> is your attempted solution, which didn't work, and now you try to make it 
> work?
>
> If that's the case, maybe you can go back and describe your original problem, 
> and the standard minimal program which you wrote to solve it (without 
> defining _MSVCRT_), and which compiles in mingw gcc or msvc.
>
> Please describe exactly how you compile it with mingw gcc, and then how you 
> tried to compile it with tcc, and what went wrong.
>
> - avih
>
>
>
>
> On Sunday, November 24, 2024 at 07:43:30 PM GMT+2, Fereydoun Memarzanjany via 
> Tinycc-devel <tinycc-devel@nongnu.org> wrote:
>
>
>
>
>
> If you use TinyCC in its 32-bit mode (`-m32`) to compile a sample
> program that uses any CRT function/symbol from `msvcrt.dll` (such as
> the snippet provided later in this message), you'll be met with
> compilation failures:
>
> `tcc.exe -std=c11 -Wall -Werror -Wl,-subsystem=console -m32 .\main.c`
> "tcc: error: undefined symbol '_iob', missing __declspec(dllimport)?"
>
> (This only happens under `-m32`, whereas `-m64` works perfectly fine.)
>
> `_iob` is not the only "unresolved" symbol, either; `printf`,
> `freopen`, `freopen_s`, and basically everything from the CRT will
> fail to link.
>
> Regardless of whether or not you use `-lmsvcrt`, `#pragma comment(lib,
> "msvcrt")`, `_declspec(dllimport)`, `attribute ((dllimport))`,
> `-static` or `-shared`, or even `-impdef` on
> "C:\Windows\SysWow64\msvcrt.dll" (or earlier versions thereof:
> "msvcrt40.dll"), TCC still complains.
>
> I've verified with `DUMPBIN.exe` that both 32- and 64-bit "msvcrt.dll"
> do, in fact, define `_iob` and other symbols.
>
> By some arcane logic, the following works perfectly fine: `tcc.exe
> -std=c11 -Wall -Werror -Wl,-subsystem=console -m64 .\main.c`
>
> `main.c`
> ```c
> //#pragma comment(lib, "msvcrt")
> //__attribute__((dllimport)) extern __declspec(dllimport) FILE _iob[];
>
> #include <windows.h>
>
> // _MSVCRT_ being defined will cause MinGW's stdio.h to use _iob as
> // opposed to _imp___iob; only the former is defined in msvcrt.dll.
> // However, even though _iob is exported by both the 32- and 64-bit
> // versions of said dll, TinyCC still fails to find _iob in the former.
> #define _MSVCRT_
> #include <stdio.h>
>
> void main() {
>     // AllocConsole() and basically everything from kernel32.dll or
>     // user32.dll work perfectly fine, both in -m32 and -m64; it's
>     // only msvcrt.dll that causes issues with TinyCC.
>     AllocConsole();
>
>     // Any CRT function (e.g., freopen, freopen_s, printf, etc.)
>     // fail to get linked properly ONLY in -m32; -m64 is fine.
>     // Even if I change the -I and -L paths to C:/Windows/SysWow64
>     // and/or use tcc.exe -impdef to create .def files from them,
>     // TCC still fails in finding _iob and other symbols.
>     // Also, using #pragma comment(lib, "msvcrt") or -lmsvcrt
>     // doesn't help at all.  Even if you do get TCC to somehow
>     // stop complaining about missing symbols, it'd just include
>     // a blank IAT.printf or IAT.freopen, causing segfaults.
>     freopen("CONOUT$", "w", stdout);
>     printf("This only compiles (and prints) under TCC in 64-bit mode.");
> }
> ```
>
> As mentioned earlier, this error in `-m32` happens regardless of other
> switches like `-std`, `-shared`, `-static`, `-lmsvcrt`, `-subsyetem`,
> etc.  So, at this point, I'm starting to think this might really be a
> bug with TinyCC 0.9.27 (Win32 & Win64 builds) itself.
>
> _______________________________________________
> Tinycc-devel mailing list
> Tinycc-devel@nongnu.org
> https://lists.nongnu.org/mailman/listinfo/tinycc-devel

_______________________________________________
Tinycc-devel mailing list
Tinycc-devel@nongnu.org
https://lists.nongnu.org/mailman/listinfo/tinycc-devel

Reply via email to