Re: 1.5.8 build failure on Solaris 8
Brendan Cully writes:
> I don't suppose you could dig a little further into exactly what's
> causing 'open' to get rewritten?
(Sorry for the late response -- I've been rather ill recently.)
This is actually entirely in accordance with the relevant standards.
The rule is that any function described in the library clause of the C
standard (clause 7 in ISO C89) must exist as a function (so that you can
take a pointer to it), but the implementation is entirely free to shadow
the declaration of the function with a macro that has exactly the same
effect. Now, C itself doesn't actually have a function called 'open',
but POSIX and Single Unix (which do) adopt the same rule that
implementations are free to define an equivalent macro. (See
http://www.opengroup.org/onlinepubs/007908799/xsh/interfaces.html, for
example.)
This sort of situation (a struct containing a function pointer named
after a standard function) tends to bite people fairly often. Defining
the struct doesn't cause a problem:
typedef int (*Function)(const char *, int);
struct s {
Function open;
int (*close)(int);
};
Why not? Because the rule is that function-like macros only get
expanded when the name is followed immediately by (optional whitespace
and) an open paren. Regardless of whether you use an extra typedef name
for the function-pointer type, you don't get that in the struct
definition.
The problem only crops up when you try to use the function:
struct s *p = ...;
int fd = p->open(name, mode); /* ??? */
p->close(fd); /* ??? */
Now we do have a form which permits function-like macros to be expanded,
and thus the problem.
Fixes? Renaming the members of the struct is probably the best option.
There's no point trying to find a compilation mode on some particular
combination of OS and compiler which doesn't trigger this behaviour,
because any other implementation could do the same thing.
Another possibility is to
#undef open
(and so on for other such names) when defining the struct. This leads
to nasty behaviour, though; a file that does
#include <unistd.h>
#include "mutt_socket.h"
will work, though one that does
#include "mutt_socket.h"
#include <unistd.h>
will fail.
The only other option is unpleasant: change all calls to look like this:
struct s *p = ...;
int fd = (p->open)(name, mode);
(p->close)(fd);
This has the simple syntactic effect of preventing the calls from
looking like calls to function-like macros -- but at the high cost of
obscuring every single call made through such a struct, not to mention
the difficulty of remembering to do this.
--
Aaron Crane