msteveb / jimtcl

Official repository of Jim Tcl, an open-source, small footprint implementation of Tcl
http://jim.tcl.tk/
Other
445 stars 123 forks source link

Compiling for Windows Using MSYS #287

Open gyrovorbis opened 10 months ago

gyrovorbis commented 10 months ago

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 commented 10 months ago

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

gyrovorbis commented 10 months ago

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 commented 10 months ago

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 commented 10 months ago

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 commented 10 months ago

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 commented 10 months ago

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:

gyrovorbis commented 9 months ago

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 commented 9 months ago

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 commented 9 months ago

See also my previous branch fixing MSYS2 on Jim 0.79, at https://github.com/TheMarkitecht/jimtcl/commit/558f556b994f78816f71ee0cea01d0bfe067aa8d

msteveb commented 9 months ago

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.