[tz] [PATCH] Support building zic.exe and zdump.exe natively on Windows with Visual Studio nmake.

Manuela Friedrich Manuela.Friedrich at actian.com
Wed Jan 31 16:17:38 UTC 2018

Hello Paul,

unfortunately, we allow our customers to download latest iana source at the customer site during installation of our product and as a result the only requirement we have is Visual Studio compiler.  MinGW is an extra requirement which is not native to Windows and complicates the setup as well as impacts usability of our product.  I am afraid nmake is a requirement for our adoption of iana.

We did more research on the topic and found a way that we can make 1 makefile work if we redefine a number of variables including some scripts (shell/batch code) in tools.ini for Visual Studio compiler and tools.gcc for gcc compiler and then reference these variables in Makefile, each compiler type will load their own compiler specific file with variables and all the variables will need to be parameterized in 1 platform independent makefile.

Alternatively, we can keep the two separate makefiles, it’s pretty common to have two separate makefiles to support both Unix-based and Windows based compilers.  Visual Studio/nmake are very popular on Windows, having support for nmake is likely to be beneficial to the adoption of iana on Windows and enhance iana community by adding a big group of developers using Visual Studio in their application development.

Regarding the Nameslashdot change on Windows stat() behaves differently. It always returns 0 when run on a filename with /. appended.
So the assumption that if the return value is 0 the path is a directory does not hold true.
Also Windows does not define S_ISDIR, but S_IFDIR and S_IFMT so I suggest this change:

@@ -987,6 +987,9 @@ itsdir(char const *name)
#ifdef S_ISDIR
        if (res == 0)
                return S_ISDIR(st.st_mode) != 0;
+#elif defined(S_IFDIR) && defined (S_IFMT)
+       if (res == 0)
+               return ((st.st_mode & S_IFMT) == S_IFDIR) !=0;
        if (res == 0 || errno == EOVERFLOW) {
                size_t n = strlen(name);

The new -DHAVE_STRTOLL=0 flag works well.

I will investigate the other points you raised.

Manuela Friedrich

From: Paul Eggert [mailto:eggert at cs.ucla.edu]
Sent: Samstag, 27. Januar 2018 04:04
To: Manuela Friedrich <Manuela.Friedrich at actian.com>; Time Zone Mailing List <tz at iana.org>
Subject: Re: [tz] [PATCH] Support building zic.exe and zdump.exe natively on Windows with Visual Studio nmake.

Thanks for sending us that. However, I'd like the source code to be kept
as POSIX-like as possible, to simplify maintenance, so I'd rather not
add a lot of #ifdefs in the code proper.

Can you use MinGW for the port instead? That should make maintenance
considerably simpler, since MinGW supports things like 'getopt' so we
wouldn't have to supply our own implementation. My impression is that
MinGW would avoid the need for many of the #ifdefs. See:


On 01/25/2018 01:31 AM, Manuela Friedrich wrote:
> In localtime.c use native localtime(), gmtime(), ctime() and mktime().
Why? localtime.c should be implementing localtime, not using the
MS-Windows-supplied localtime.

> Also use int or __int64 respectively for ssize_t type and check for Windows drive letters in tzloadbody().

For something like that how about just compiling with -Dssize_t=long.
That should be good enough for MS-Windows and will mean we don't need to
change the .c files.

> In private.h and zdump.c define strotimax depending on Visual Studio version.
> It needs to be strtol for up to VS 2010 and stroll for higher versions.

tzcode configures this sort of thing with CFLAGS in the makefile. I
applied the attached patch to the tz development version on GitHub
<https://github.com/eggert/tz<https://github.com/eggert/tz>>. So you should be able to build with
-DHAVE_STRTOLL=0 on older MS-Windows platforms.

> In zdump.c need prototype for gmtime_r() to suffice return type requirements.
> Also use __time64_t variables on Windows instead of time_t.
> In main() variable declarations had to be moved to the top to avoid compile errors.

I hope this is handled better in MinGW so that we don't have to worry
about redeclaring gmtime_r or using __time64_t instead of time_t. If
not, then this is better handled in private.h, which already does this
sort of thing.

> In zic.c dolink() need to have an extra mkdirs() call for Windows as we don't have link support here and the previous mkdirs() calls wouldn't have been called therefore.

Thanks, I put that into the attached patch too.

> Also itsdir() needs separate Windows part to check for directory flag as the namesslashdot Linux alternative alway returns directory on Windows.

Could you explain what goes wrong with namesslashdot on MS-Windows? I
don't see the bug here. nameslashdot tests whether a file F is a
directory by statting "F/.". Why doesn't this approach work on MS-Windows?

> Add nmake specific Makefile.nmake based on existing Makefile.

I hope MinGW makes this unnecessary.
> @@ -401,6 +409,13 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
> if (name[0] == ':')
> ++name;
> doaccess = name[0] == '/';
> +#ifdef _WIN32
> + /*
> + ** DOS drive specifier?
> + */
> + if (isalpha(name[0]) && name[1]==':' && name[2] == '\\')
> + doaccess = true;
> +#endif
> if (!doaccess) {
> size_t namelen = strlen(name);
> if (sizeof lsp->fullname - sizeof tzdirslash <= namelen)

This change should not be needed, as there's no need to support absolute
file names as TZ specifiers under MS-Windows. (Even if we did, the above
code would not work on some MS-Windows variants; it's better to avoid
this messy situation.)
> diff --git a/zdump.c b/zdump.c
> index 60a027e..fc90662 100644
> --- a/zdump.c
> +++ b/zdump.c
> @@ -4,6 +4,9 @@
> */
> #include "version.h"
> +#ifdef _WIN32
> +#include <stdlib.h>
> +#endif

I don't see why this is needed, as private.h includes stdlib.h.

> + struct tm * newtmp;
> bool iflag = false;
> + bool newtm_ok;
> cutlotime = absolute_min_time;
> cuthitime = absolute_max_time;
> @@ -531,7 +563,6 @@ main(int argc, char *argv[])
> for (i = optind; i < argc; ++i) {
> timezone_t tz = tzalloc(argv[i]);
> char const *ab;
> - time_t t;
> struct tm tm, newtm;
> bool tm_ok;
> if (!tz) {
> @@ -562,12 +593,12 @@ main(int argc, char *argv[])
> }
> }
> while (t < cuthitime) {
> - time_t newt = ((t < absolute_max_time - SECSPERDAY / 2
> + newt = ((t < absolute_max_time - SECSPERDAY / 2
> && t + SECSPERDAY / 2 < cuthitime)
> ? t + SECSPERDAY / 2
> : cuthitime);
> - struct tm *newtmp = localtime_rz(tz, &newt, &newtm);
> - bool newtm_ok = newtmp != NULL;
> + newtmp = localtime_rz(tz, &newt, &newtm);
> + newtm_ok = newtmp != NULL;
> if (tm_ok != newtm_ok
> || (tm_ok && (delta(&newtm, &tm) != newt - t
> || newtm.tm_isdst != tm.tm_isdst

I don't see why these changes are needed, as the code is valid C89 code
without them.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mm.icann.org/pipermail/tz/attachments/20180131/db055178/attachment-0001.html>

More information about the tz mailing list