Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiling for Windows Using MSYS #287

Open
gyrovorbis opened this issue Jan 8, 2024 · 10 comments
Open

Compiling for Windows Using MSYS #287

gyrovorbis opened this issue Jan 8, 2024 · 10 comments

Comments

@gyrovorbis
Copy link

gyrovorbis commented Jan 8, 2024

Hello jimtcl team!

Long story short, we've added support for this lovely library to the independent Sega Dreamcast SDK, KallistiOS, as another scripting language we wish to offer first-party support for as an add-on library within our package manager system. We already have at least one person using it for an upcoming Dreamcast engine as well.

That being said, KOS and its ports have to build on and get maintained for a myriad of host OSes, Windows, Mac, Linux, BSD, etc... Shortly after officially adding jimtcl, we ran into issues with only a single host platform: MSYS for Windows. It seems as though the configuration script immediately fails with the following error:

$ ./configure 
No installed jimsh or tclsh, building local bootstram jimsh0
No working C compiler found. Tried cc and gcc.

I played with this for maybe an hour or so this morning, attempting to manually set the CC or even CC_FOR_BUILD environment variables to no avail. It seems like no matter what I tried, autosetup-find-tclsh was unable to find the correct compiler? The following are the binary names for the toolchain used within the environment:

$ mingw
mingw-get-info          mingw32-gcc-9.2.0.exe   mingw32-gcc.exe
mingw-get.exe           mingw32-gcc-ar.exe      mingw32-make.exe
mingw32-c++.exe         mingw32-gcc-nm.exe      mingwm10.dll
mingw32-g++.exe         mingw32-gcc-ranlib.exe

I understand that perhaps MSYS has not been a priority or may not even be advertised as working yet. I also saw that everything did work just fine under Cygwin; however, most of our Windows users are using "DreamSDK" (https://www.dreamsdk.org/) which is completely built around MSYS (as Cygwin is typically the problem child for us)... Anyway, I was wondering if you guys had any pointers or advice in terms of just getting things configured? I'm unfamiliar with this particular build system, but once I'm past the configuration stage, if there are any actual code changes required to support MSYS, I believe we should be able to take care of them over here and PR them back to you if you're interested?

Anyway, sorry for the novel. Thank you very much for allowing us to bring Tcl to the Dreamcast. We look forward to showing you the cool stuff we're doing with it!

@msteveb
Copy link
Owner

msteveb commented Jan 9, 2024

If this is a native compile, it expects cc or gcc to be available. If cross compile, use —host=mingw32

@gyrovorbis
Copy link
Author

gyrovorbis commented Jan 15, 2024

Hello!!! Thank you! We've made more progress with our MSYS host. It's actually trying to build now, but we get the following errors (after removing the output redirection in autosetup-find-tclsh to /dev/null):

$ CC=kos-cc  ./configure --prefix=/opt/toolchains/dc/kos/../kos-ports/libjimtcl/inst --host=sh-elf --without-ext="aio,z
lib"
No installed jimsh or tclsh, building local bootstrap jimsh0
./autosetup/jimsh0.c: In function 'stdio_reader':
./autosetup/jimsh0.c:2146:13: error: 'ETIMEDOUT' undeclared (first use in this function); did you mean 'WSAETIMEDOUT'?
 2146 |     errno = ETIMEDOUT;
      |             ^~~~~~~~~
      |             WSAETIMEDOUT
./autosetup/jimsh0.c:2146:13: note: each undeclared identifier is reported only once for each function it appears in
./autosetup/jimsh0.c: In function 'stdio_error':
./autosetup/jimsh0.c:2159:14: error: 'ETIMEDOUT' undeclared (first use in this function); did you mean 'WSAETIMEDOUT'?
 2159 |         case ETIMEDOUT:
      |              ^~~~~~~~~
      |              WSAETIMEDOUT
./autosetup/jimsh0.c: In function 'clock_cmd_seconds':
./autosetup/jimsh0.c:6366:5: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
 6366 |     Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000000);
      |     ^~~~~~~~~~~~~~~~
      |     |
      |     struct __clockid__ *
./autosetup/jimsh0.c:698:46: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
  698 | JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
      |                                     ~~~~~~~~~^~~~
./autosetup/jimsh0.c: In function 'clock_cmd_clicks':
./autosetup/jimsh0.c:6372:5: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
 6372 |     Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW));
      |     ^~~~~~~~~~~~~~~~
      |     |
      |     struct __clockid__ *
./autosetup/jimsh0.c:698:46: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
  698 | JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
      |                                     ~~~~~~~~~^~~~
./autosetup/jimsh0.c: In function 'clock_cmd_micros':
./autosetup/jimsh0.c:6378:5: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
 6378 |     Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME));
      |     ^~~~~~~~~~~~~~~~
      |     |
      |     struct __clockid__ *
./autosetup/jimsh0.c:698:46: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
  698 | JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
      |                                     ~~~~~~~~~^~~~
./autosetup/jimsh0.c: In function 'clock_cmd_millis':
./autosetup/jimsh0.c:6384:5: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
 6384 |     Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000);
      |     ^~~~~~~~~~~~~~~~
      |     |
      |     struct __clockid__ *
./autosetup/jimsh0.c:698:46: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
  698 | JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
      |                                     ~~~~~~~~~^~~~
./autosetup/jimsh0.c: At top level:
./autosetup/jimsh0.c:6665:10: fatal error: sys/wait.h: No such file or directory
 6665 | #include <sys/wait.h>
      |          ^~~~~~~~~~~~
compilation terminated.
./autosetup/jimsh0.c: In function 'stdio_reader':
./autosetup/jimsh0.c:2146:13: error: 'ETIMEDOUT' undeclared (first use in this function); did you mean 'WSAETIMEDOUT'?
 2146 |     errno = ETIMEDOUT;
      |             ^~~~~~~~~
      |             WSAETIMEDOUT
./autosetup/jimsh0.c:2146:13: note: each undeclared identifier is reported only once for each function it appears in
./autosetup/jimsh0.c: In function 'stdio_error':
./autosetup/jimsh0.c:2159:14: error: 'ETIMEDOUT' undeclared (first use in this function); did you mean 'WSAETIMEDOUT'?
 2159 |         case ETIMEDOUT:
      |              ^~~~~~~~~
      |              WSAETIMEDOUT
./autosetup/jimsh0.c: In function 'clock_cmd_seconds':
./autosetup/jimsh0.c:6366:5: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
 6366 |     Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000000);
      |     ^~~~~~~~~~~~~~~~
      |     |
      |     struct __clockid__ *
./autosetup/jimsh0.c:698:46: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
  698 | JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
      |                                     ~~~~~~~~~^~~~
./autosetup/jimsh0.c: In function 'clock_cmd_clicks':
./autosetup/jimsh0.c:6372:5: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
 6372 |     Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW));
      |     ^~~~~~~~~~~~~~~~
      |     |
      |     struct __clockid__ *
./autosetup/jimsh0.c:698:46: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
  698 | JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
      |                                     ~~~~~~~~~^~~~
./autosetup/jimsh0.c: In function 'clock_cmd_micros':
./autosetup/jimsh0.c:6378:5: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
 6378 |     Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME));
      |     ^~~~~~~~~~~~~~~~
      |     |
      |     struct __clockid__ *
./autosetup/jimsh0.c:698:46: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
  698 | JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
      |                                     ~~~~~~~~~^~~~
./autosetup/jimsh0.c: In function 'clock_cmd_millis':
./autosetup/jimsh0.c:6384:5: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
 6384 |     Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000);
      |     ^~~~~~~~~~~~~~~~
      |     |
      |     struct __clockid__ *
./autosetup/jimsh0.c:698:46: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
  698 | JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
      |                                     ~~~~~~~~~^~~~
./autosetup/jimsh0.c: At top level:
./autosetup/jimsh0.c:6665:10: fatal error: sys/wait.h: No such file or directory
 6665 | #include <sys/wait.h>
      |          ^~~~~~~~~~~~

These all look like trivial things to solve by adding #ifdefs for __MSYS__. I'm happy to add the code to get it to compile properly there... I see a few casts that need to be added for the clock_t types, a missing header (that I believe isn't needed on MSYS), and a missing ERRNO define...

However, after looking at the comment at the top of jimsh0.c, and checking the documentation for the boostrap, I just wanted to make sure that this is, indeed, a file that should be modified directly and that it's not autogenerated from the other source files anywhere or anything like that?

For our purposes, it looks as though this is the only file that will need to be modified, since it's the only issue with our build... Our actual target is sh-elf-gcc which can build the full libjimtcl just fine.

msteveb added a commit that referenced this issue Jan 15, 2024
@msteveb
Copy link
Owner

msteveb commented Jan 15, 2024

OK, that's promising. Because jimsh0.c has to build with no configuration step, it has to take a few shortcuts for autoconfiguration. Looks like we do need a few more checks for your platform. Note that jimsh0.c is build by build-make-bootstrap-jim so the changes should be made there or in the source files. Please try branch bootstrap-jimsh and let me know how it goes.

@gyrovorbis
Copy link
Author

gyrovorbis commented Jan 15, 2024

OK, that's promising. Because jimsh0.c has to build with no configuration step, it has to take a few shortcuts for autoconfiguration. Looks like we do need a few more checks for your platform. Note that jimsh0.c is build by build-make-bootstrap-jim so the changes should be made there or in the source files. Please try branch bootstrap-jimsh and let me know how it goes.

We have progress! That fixed the ERRNO and wait() stuff. Now, unless I'm missing something, it's just complaining about a missing GetProcessId()? Down to one linker error!

gyrov@Windoez11VM /opt/toolchains/dc/kos-ports/libjimtcl/build/libjimtcl-1.0.0
$ CC=kos-cc  ./configure --prefix=/opt/toolchains/dc/kos/../kos-ports/libjimtcl/inst --host=sh-elf --without-ext="aio,z
lib"
No installed jimsh or tclsh, building local bootstrap jimsh0
./autosetup/jimsh0.c: In function 'clock_cmd_seconds':
./autosetup/jimsh0.c:6363:5: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
 6363 |     Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000000);
      |     ^~~~~~~~~~~~~~~~
      |     |
      |     struct __clockid__ *
./autosetup/jimsh0.c:699:46: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
  699 | JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
      |                                     ~~~~~~~~~^~~~
./autosetup/jimsh0.c: In function 'clock_cmd_clicks':
./autosetup/jimsh0.c:6369:5: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
 6369 |     Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW));
      |     ^~~~~~~~~~~~~~~~
      |     |
      |     struct __clockid__ *
./autosetup/jimsh0.c:699:46: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
  699 | JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
      |                                     ~~~~~~~~~^~~~
./autosetup/jimsh0.c: In function 'clock_cmd_micros':
./autosetup/jimsh0.c:6375:5: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
 6375 |     Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME));
      |     ^~~~~~~~~~~~~~~~
      |     |
      |     struct __clockid__ *
./autosetup/jimsh0.c:699:46: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
  699 | JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
      |                                     ~~~~~~~~~^~~~
./autosetup/jimsh0.c: In function 'clock_cmd_millis':
./autosetup/jimsh0.c:6381:5: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
 6381 |     Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000);
      |     ^~~~~~~~~~~~~~~~
      |     |
      |     struct __clockid__ *
./autosetup/jimsh0.c:699:46: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
  699 | JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
      |                                     ~~~~~~~~~^~~~
./autosetup/jimsh0.c: In function 'Jim_GetTimeUsec':
./autosetup/jimsh0.c:7330:9: warning: 'gettimeofday' is deprecated [-Wdeprecated-declarations]
 7330 |         gettimeofday(&tv, NULL);
      |         ^~~~~~~~~~~~
In file included from ./autosetup/jimsh0.c:6247:
c:\dreamsdk\include\sys\time.h:106:53: note: declared here
  106 | int __cdecl __MINGW_NOTHROW __POSIX_2008_DEPRECATED gettimeofday
      |                                                     ^~~~~~~~~~~~
./autosetup/jimsh0.c: In function 'Jim_CreateInterp':
./autosetup/jimsh0.c:11312:42: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
11312 |     i->lastCollectTime = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
      |                                          ^~~~~~~~~~~~~~~~~~~
      |                                          |
      |                                          struct __clockid__ *
./autosetup/jimsh0.c:7316:35: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
 7316 | jim_wide Jim_GetTimeUsec(unsigned type)
      |                          ~~~~~~~~~^~~~
./autosetup/jimsh0.c: In function 'Jim_TimeCoreCommand':
./autosetup/jimsh0.c:19420:29: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
19420 |     start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
      |                             ^~~~~~~~~~~~~~~~~~~
      |                             |
      |                             struct __clockid__ *
./autosetup/jimsh0.c:7316:35: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
 7316 | jim_wide Jim_GetTimeUsec(unsigned type)
      |                          ~~~~~~~~~^~~~
./autosetup/jimsh0.c:19429:31: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
19429 |     elapsed = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
      |                               ^~~~~~~~~~~~~~~~~~~
      |                               |
      |                               struct __clockid__ *
./autosetup/jimsh0.c:7316:35: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
 7316 | jim_wide Jim_GetTimeUsec(unsigned type)
      |                          ~~~~~~~~~^~~~
./autosetup/jimsh0.c: In function 'Jim_TimeRateCoreCommand':
./autosetup/jimsh0.c:19465:29: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
19465 |     start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
      |                             ^~~~~~~~~~~~~~~~~~~
      |                             |
      |                             struct __clockid__ *
./autosetup/jimsh0.c:7316:35: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
 7316 | jim_wide Jim_GetTimeUsec(unsigned type)
      |                          ~~~~~~~~~^~~~
./autosetup/jimsh0.c:19469:33: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
19469 |         delta = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
      |                                 ^~~~~~~~~~~~~~~~~~~
      |                                 |
      |                                 struct __clockid__ *
./autosetup/jimsh0.c:7316:35: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
 7316 | jim_wide Jim_GetTimeUsec(unsigned type)
      |                          ~~~~~~~~~^~~~
./autosetup/jimsh0.c:19477:29: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
19477 |     start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
      |                             ^~~~~~~~~~~~~~~~~~~
      |                             |
      |                             struct __clockid__ *
./autosetup/jimsh0.c:7316:35: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
 7316 | jim_wide Jim_GetTimeUsec(unsigned type)
      |                          ~~~~~~~~~^~~~
./autosetup/jimsh0.c:19481:36: warning: passing argument 1 of 'Jim_GetTimeUsec' makes integer from pointer without a cast [-Wint-conversion]
19481 |         overhead = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
      |                                    ^~~~~~~~~~~~~~~~~~~
      |                                    |
      |                                    struct __clockid__ *
./autosetup/jimsh0.c:7316:35: note: expected 'unsigned int' but argument is of type 'struct __clockid__ *'
 7316 | jim_wide Jim_GetTimeUsec(unsigned type)
      |                          ~~~~~~~~~^~~~
./autosetup/jimsh0.c: In function 'JimProcessPid':
./autosetup/jimsh0.c:23513:12: warning: implicit declaration of function 'GetProcessId'; did you mean 'GetProcessHeap'? [-Wimplicit-function-declaration]
23513 |     return GetProcessId(pid);
      |            ^~~~~~~~~~~~
      |            GetProcessHeap
c:/dreamsdk/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: C:\Users\gyrov\AppData\Local\Temp\ccLAVTXy.o:jimsh0.c:(.text+0x29fe6): undefined reference to `GetProcessId'
c:/dreamsdk/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: C:\Users\gyrov\AppData\Local\Temp\ccLAVTXy.o:jimsh0.c:(.text+0x2a0c7): undefined reference to `GetProcessId'

I have confirmed that we have getpid() from MINSYS in <unistd.h>, btw.

@msteveb
Copy link
Owner

msteveb commented Jan 17, 2024

Hmmm, still seem strange to me. GetProcessId() should be included in processthreadsapi.h, which is included by winbase.h
Why isn't that included for you (gcc -E can help here)?

Also I would be concerned about CLOCK_REALTIME being defined, but not an int. Are you somehow picking up some cygwin things?

@msteveb
Copy link
Owner

msteveb commented Jan 17, 2024

Oh, I see. Need at least WinXP compatibility. I pushed a small change. With this, jimsh0.exe builds. However I still see a few issues:

  • Can't run the cc wrapper around gcc (something to do with backslashes and paths)
  • stdout isn't correctly initialised with line buffering

@gyrovorbis
Copy link
Author

Just wanted to follow up with you here. I was able to get as far as you said on your updated branch, definitely got jimsh0.exe built (whooo!!!), but then the build seemed to fail on some compiler subsequent checks.

Is there anything you need us to check or try out on our end? Thanks for helping to support us, btw. We really appreciate it!

@msteveb
Copy link
Owner

msteveb commented Jan 27, 2024

I'll get to it. I just have limited access to a Windows machine that can run the SDK so when I next get back to it I'll take a look at the outstanding issues. Should be this week.

@The-Markitecht
Copy link
Contributor

See also my previous branch fixing MSYS2 on Jim 0.79, at TheMarkitecht@558f556

@msteveb
Copy link
Owner

msteveb commented Feb 14, 2024

I did have a bit more of a look at this. Not being able to detect isatty() reliably is annoying. I took a look at how git does it and it is complicated. And the exec issue is messy. In the case I found it was trying to exec a shell script, but that's not a standard windows thing. That is an msys2 thing. So I think there needs to a build for msys2 separate from mingw, but how you detect the difference and what to do about it, I don't know. I don't have reliable access to a Windows platform so I'm inclined to leave all this to someone who does and can test reliably across mingw, msys2 and cygwin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants