msteveb/jimtcl

Compiling for Windows Using MSYS

gyrovorbis opened this issue · 10 comments

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!

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

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.

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.

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.

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?

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

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!

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.

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