Tcl Source Code

View Ticket
Login
Ticket UUID: 565088
Title: Bring tcl.h into the 1990s
Type: RFE Version: None
Submitter: jenglish Created on: 2002-06-05 23:33:17
Subsystem: 52. Portability Support Assigned To: jenglish
Priority: 3 Low Severity:
Status: Closed Last Modified: 2002-06-18 08:32:42
Resolution: Fixed Closed By: davygrvy
    Closed on: 2002-06-18 01:32:42
Description:
Brief summary: <tcl.h> contains several preprocessor
macros intended to aid source-level compatibility
between ANSI C and K&R C compilers.  However, the
#ifdef logic tends to assume K&R C by default and
enables modern features based on the presence of
__STDC__ and/or other special cases.

Since pre-ANSI compilers are a rarity nowadays (2002),
and many compilers do not define __STDC__ in the
default (non-strict-ansi) mode even though they do in
fact support all the relevant features, it would make
more sense to assume modern C by default and only
enable the backwards-compatibility macros on a
special-case basis.

I'll put together a patch in the next couple of days.

Detailed analysis (from a post to comp.lang.tcl):

From: [email protected] (Joe English)
Newsgroups: comp.lang.tcl
Subject: Re: Build problem using aCC on HP-UX
Date: 5 Jun 2002 15:32:02 GMT
Message-ID: <[email protected]>

[...]
The Tcl core was C89-compatible until the recent
(8.4a2? 3?)
addition of "long long", which is a C99 feature. 
(Actually,
I'm not sure under which conditions 'long long' is
actually
used -- it's tough to decipher what's going on in the
#ifdef
chain in tcl.h).

However, the core also includes backwards-compatibility
#defines for several features which were not present in
K&R C (VOID, CONST, USE_PROTOTYPE, USE_STDARG, etc.).
The choice of whether to use C89 or K&R features is
determined by whether or not __STDC__ is #define'd,
or, in many cases, with an additional list of special
cases, e.g.

    #   if defined(__STDC__) || defined(__cplusplus) ||
defined(__BORLANDC__)

Most compilers nowadays (in my experience) are C89, but
do not yet fully support C99.  Many of these support
C9X features like "long long", but only when invoked in
"extensions-enabled" mode.

Here's where the problem comes up: "long long" is
standard C99,
but it's an extension to C89; thus 20th century
compilers don't
enable it in "strict ANSI" mode and Tcl 8.4 can't be
compiled
in that mode.  Most compilers -- GCC being a notable
exception --
don't define __STDC__ when extensions are enabled, so
all of
the backwards-compatibility cruft in tcl.h gets
activated
(except on platforms which have been accounted for by a
special-case preprocessor test as above).

The correct way to proceed is IMO to bring tcl.h into
the 1990s:
it should assume C89 features are present by default
(void, const,
stdarg.h, etc.), and only enable the
backwards-compatibility
cruft on a special-case basis, instead of the other way
around.
For example, instead of:

    #if ((defined(__STDC__) || defined(SABER)) &&
!defined(NO_PROTOTYPE)) \
        || defined(__cplusplus) ||
defined(USE_PROTOTYPE)
    #   define _USING_PROTOTYPES_ 1
    #   define _ANSI_ARGS_(x)   x
    #   define CONST const
    #else
    #   define _ANSI_ARGS_(x)   ()
    #   define CONST
    #endif

use something like:

        #if defined(ANCIENT_COMPILER)
        #       define CONST
        #       define _ANSI_ARGS_(x)
        #else
        #       define _ANSI_ARGS_(x) x
        #       define CONST const
        #endif

where ANCIENT_COMPILER is undefined by default.
User Comments: davygrvy added on 2002-06-18 08:32:42:
Logged In: YES 
user_id=7549

adapted the rc files in Tcl and Tk to support the 
RC_INVOKED change and committed it.  Thanks.

hobbs added on 2002-06-18 05:54:47:
Logged In: YES 
user_id=72656

just closing ... if problems, resurface, we know who to 
blame. ;)

jenglish added on 2002-06-18 01:32:46:
Logged In: YES 
user_id=68433

Patch committed (generic/tcl.h r1.125 -> r1.126), including
davygrvy's RC_INVOKED changes below.

Leaving this item open for now in case any problems surface.

davygrvy added on 2002-06-08 10:28:31:

File Added - 24665: more_tcl_h_Hunks.txt

davygrvy added on 2002-06-08 10:28:30:
Logged In: YES 
user_id=7549

works good on windows.  Can I sneak a few hunks into the 
patch, or am I off-topic?  This changes the Tcl specific use of 
RESOURCE_INCLUDED to be the proper RC_INVOKED as 
done by the windows rc compiler all on it's own.

jenglish added on 2002-06-08 08:27:35:

File Deleted - 24650: 



File Added - 24664: tcl.h.patch

Logged In: YES 
user_id=68433

> Could we put JOIN back? 

Done.  Patch version 7 uploaded.

davygrvy added on 2002-06-08 07:27:57:
Logged In: YES 
user_id=7549

Could we put JOIN back?  I've been known to use it such as 
in my expect-win32 port:

/*
 *  Version stuff.
 */

#define EXP_MAJOR_VERSION   6
#define EXP_MINOR_VERSION   0
#define EXP_RELEASE_LEVEL   TCL_ALPHA_RELEASE
#define EXP_RELEASE_SERIAL  0

#define EXP_VERSION   STRINGIFY(JOIN
(EXP_MAJOR_VERSION,JOIN(.,EXP_MINOR_VERSION)))

#ifEXP_RELEASE_LEVEL == 
TCL_ALPHA_RELEASE
#define EXP_PATCH_LEVEL \
STRINGIFY( \
JOIN(JOIN
(EXP_MAJOR_VERSION, \
JOIN(., 
EXP_MINOR_VERSION)), \
JOIN(a, 
EXP_RELEASE_SERIAL)))

#elifEXP_RELEASE_LEVEL == 
TCL_BETA_RELEASE
#define EXP_PATCH_LEVEL \
STRINGIFY( \
JOIN(JOIN
(EXP_MAJOR_VERSION, \
JOIN(., 
EXP_MINOR_VERSION)), \
JOIN(b, 
EXP_RELEASE_SERIAL)))

#elifEXP_RELEASE_LEVEL == 
TCL_FINAL_RELEASE
#define EXP_PATCH_LEVEL \
STRINGIFY( \
JOIN(JOIN
(EXP_MAJOR_VERSION, \
JOIN(., 
EXP_MINOR_VERSION)), \
JOIN(., 
EXP_RELEASE_SERIAL)))

#else
#include "bad/release/level/used"
#endif

jenglish added on 2002-06-08 05:47:11:

File Deleted - 24644: 



File Added - 24650: tcl.h.patch

Logged In: YES 
user_id=68433

Also tested on Solaris 8/Workshop and Linux/Alpha/gcc (dgp),
and, after a couple of go-arounds, on MSVC 6 (kkb).  Patch
'take 6' should be OK.

jenglish added on 2002-06-08 05:18:53:

File Added - 24644: tcl.h.patch

jenglish added on 2002-06-08 04:58:11:

File Deleted - 24641: 



File Added - 24642: tcl.h.patch

jenglish added on 2002-06-08 04:50:14:

File Deleted - 24640: 



File Added - 24641: tcl.h.patch

jenglish added on 2002-06-08 04:45:12:

File Added - 24640: tcl.h.patch

Logged In: YES 
user_id=68433

One more time,  this time with 'diff -c' instead of 'diff
-u'

jenglish added on 2002-06-08 04:31:37:

File Added - 24639: tcl.h.patch

Logged In: YES 
user_id=68433

OK, patch attached.  Tested on Linux (SuSE 6.3, gcc), HP-UX
10.20 (cc -Ae), and AIX 4 (native cc).

jenglish added on 2002-06-07 22:40:08:
Logged In: YES 
user_id=68433

Other changes:

In r1.8 of tcl.h, the definition of STRINGIFY:

#define STRINGIFY(x) STRINGIFY1(x)
#define STRINGIFY1(x) #x

was replaced with a messy #ifdef chain.  The current version  uses the above (correct) definition when _MSC_VER or RESOURCE_INCLUDED is defined, an incorrect version if __STDC__ is defined, and a fourth version (which may or may not work on older compilers -- this wasn't possible to do portably pre-ANSI).  It also added a JOIN() macro, which is not used anywhere in the core. STRINGIFY() appears in two places (win/tclWinPipe.c, win/tcl.rc).

I plan to revert to the older definition. (On the tcl'ers chat, Jeff said this would be OK.)

I also plan to remove references to <sys/type.h>: this was added as part of the TIP 72 implementation, but it turns out not to be needed (confirmed by DKF [private email], who added it initially), and causes problems compiling on non-POSIX systems.  (<sys/types.h> is a POSIX header file that defines various typedefs like dev_t, pid_t, ino_t, etc., none of which are used elsewhere).

jenglish added on 2002-06-07 21:56:00:
Logged In: YES 
user_id=68433

> [...] please avoid any macro like "ANCIENT_COMPILER".

Naturally :-)

Currently I'm using the following CPP symbols:
NO_PROTOTYPES
NO_CONST
NO_VOID
NO_STDARG

All of which are undefined by default.  This should allow the current build system to work unchanged on any modern compiler.  As far as I can tell, all of the platforms mentioned in tcl.m4/configure.in, as well as Windows (MSVC, Borland C, GCC+CYGWIN, GCC+MINGW) and the Mac satisfy this criteria but please someone correct me if I'm wrong.  I'm unable to test this patch on a pre-ANSI compiler, since I no longer have one available.

dgp added on 2002-06-07 21:33:43:
Logged In: YES 
user_id=80530

The basic idea seems fine, but please avoid any macro
like "ANCIENT_COMPILER".  By the time 2010 gets here,
every compiler we're using now will be an "ancient compiler",
but that's not what we mean.  Use macro names that say
precisely what they mean.

dkf added on 2002-06-07 16:44:21:
Logged In: YES 
user_id=79902

David: No.  It increases the maintenance cost too much, and
I am not convinced the benefits are worth it.  If the new
compilers cope with the source as it is now, there's no good
reason to change it.  Especially as I don't fancy typing all
that stuff in every time I create a new function!

And I think old style function defns are more readable
anyway.  It is one of the few places where ANSI, by tailing
C++,  did not improve things IMHO...

davygrvy added on 2002-06-07 08:07:48:
Logged In: YES 
user_id=7549

Bravo!  How about we hit the source, too?

int
#if OLD_CRUFTY_PRE_ANSIC89_COMPILER
Tcl_Stat(path, oldStyleBuf)
    CONST char *path;/* Path of file to stat (in 
current CP). */
    struct stat *oldStyleBuf;/* Filled with results of 
stat call. */
#else
Tcl_Stat(
    CONST char *path,/* Path of file to stat (in 
current CP). */
    struct stat *oldStyleBuf)/* Filled with results of 
stat call. */
#endif
{
    ....

Attachments: