SDL_stdinc.h inlines problematic when application not compiled in exact same feature environment

This is “interesting” behavior (and breaks my build, but then, I’m doing
something a bit weird):

I’m building SDL 2.0.0 on my main development box, which runs Debian sid AMD64
with GCC 4.7.3 (Debian 4.7.3-4). The autoconf-based configure for it detects
functions like strdup and setenv being available, which they are, provided
the correct feature test macros are active. However, trying to build a test
application results in:

SDL_stdinc.h: In function ?SDL_setenv_inline?:
SDL_stdinc.h:282:1: error: implicit declaration of function ?setenv? [-Werror=implicit-function-declaration]
SDL_stdinc.h: In function ?SDL_strdup_inline?:
SDL_stdinc.h:485:1: error: implicit declaration of function ?strdup? [-Werror=implicit-function-declaration]
SDL_stdinc.h:485:61: error: return makes pointer from integer without a cast [-Werror]

I’m guessing this is because I’m compiling my application with -std=c99. If I
use -std=gnu99, for instance, the errors go away, but don’t I lose my more
explicit portability control that way. I’d just as soon not have so much
transitive header cruft anyway (cf. SDL_syswm.h not being included by default),
but a lot of the public headers depend on SDL_stdinc.h; a cursory glance
suggests that they mainly depend on it for types, so I’m not sure why all the
inlines are stuffed in there too.

My current intended workaround is to just strip all the inline functions from
that file manually, but this seems fragile as well and might wind up requiring
me to keep a local fork if I juggle build environments enough.

Any recommendation on how best to handle this?

—> Drake Wilson

It seems that the pkg-config file for SDL2 forgets to include
"-D_GNU_SOURCE=1" in its CFLAGS, like SDL1 does. This is probably a bug.

So try adding “-D_GNU_SOURCE=1” to your CFLAGS and see if that works.
Alternatively, check the man pages of those functions to see which
feature test macros they depend on. strdup(3) for example says:

strdup():
_SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500
|| _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
|| /* Since glibc 2.12: */ _POSIX_C_SOURCE >= 200809L

But usually “-D_GNU_SOURCE=1” is all you need.On 11/06/13 06:39, Drake Wilson wrote:

[…]
I’m building SDL 2.0.0 on my main development box, which runs Debian sid AMD64
with GCC 4.7.3 (Debian 4.7.3-4). The autoconf-based configure for it detects
functions like strdup and setenv being available, which they are, provided
the correct feature test macros are active. However, trying to build a test
application results in:

SDL_stdinc.h: In function ?SDL_setenv_inline?:
SDL_stdinc.h:282:1: error: implicit declaration of function ?setenv? [-Werror=implicit-function-declaration]
SDL_stdinc.h: In function ?SDL_strdup_inline?:
SDL_stdinc.h:485:1: error: implicit declaration of function ?strdup? [-Werror=implicit-function-declaration]
SDL_stdinc.h:485:61: error: return makes pointer from integer without a cast [-Werror]

I’m guessing this is because I’m compiling my application with -std=c99. […]

My current intended workaround is to just strip all the inline functions from
that file manually, but this seems fragile as well and might wind up requiring
me to keep a local fork if I juggle build environments enough.

Any recommendation on how best to handle this?

Quoth Nikos Chantziaras , on 2013-06-11 07:41:45 +0300:

It seems that the pkg-config file for SDL2 forgets to include
"-D_GNU_SOURCE=1" in its CFLAGS, like SDL1 does. This is probably a
bug.

That’s bad to begin with. Compiling with a library shouldn’t transitively
force me to compile against a particular set of system features without a
lot of justification (note that this doesn’t prevent the library itself from
linking against those features, since it sets its own CFLAGS).

I hadn’t noticed SDL 1 doing this, and now that I see it I’m a bit shocked.
Forcibly manipulating the behavior of other header files that I might include
is rude; it’s not always avoidable, and there’s some justification for it in
the case of hairy, less frequent, and more inherently platform-specific bits
like SDL_syswm, but the standard C headers, really? So now that I see it I
consider the SDL 1 approach a misbehavior.

—> Drake Wilson

Better question, why would GNU’s feature set allow implicit function
declarations while the standard counterpart doesn’t? Implicit
declarations date back from the pre-standard era, they shouldn’t be
allowed anymore, and they will trigger warnings always unless you
disable warnings in the first place.

…also wait a second. I build my game with -std=c99, why don’t I get
any warnings then? Maybe because I’m building on a platform that comes
with setenv and strdup? If so, that looks more like an oversight to
me.

2013/6/11, Drake Wilson :> Quoth Nikos Chantziaras , on 2013-06-11 07:41:45 +0300:

It seems that the pkg-config file for SDL2 forgets to include
"-D_GNU_SOURCE=1" in its CFLAGS, like SDL1 does. This is probably a
bug.

That’s bad to begin with. Compiling with a library shouldn’t transitively
force me to compile against a particular set of system features without
a
lot of justification (note that this doesn’t prevent the library itself
from
linking against those features, since it sets its own CFLAGS).

I hadn’t noticed SDL 1 doing this, and now that I see it I’m a bit shocked.
Forcibly manipulating the behavior of other header files that I might
include
is rude; it’s not always avoidable, and there’s some justification for it
in
the case of hairy, less frequent, and more inherently platform-specific
bits
like SDL_syswm, but the standard C headers, really? So now that I see it I
consider the SDL 1 approach a misbehavior.

—> Drake Wilson


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Quoth Sik the hedgehog <sik.the.hedgehog at gmail.com>, on 2013-06-11 05:07:36 -0300:

Better question, why would GNU’s feature set allow implicit function
declarations while the standard counterpart doesn’t? Implicit
declarations date back from the pre-standard era, they shouldn’t be
allowed anymore, and they will trigger warnings always unless you
disable warnings in the first place.

I’d guess -std=gnu99 also uses different default feature test macros
for the C library and causes the pile of transitive inclusions from
SDL_stdinc.h to pull in non-ISO-C setenv, strdup, etc., but I’ve never
actively used it in a new program, so…

…also wait a second. I build my game with -std=c99, why don’t I get
any warnings then? Maybe because I’m building on a platform that comes
with setenv and strdup? If so, that looks more like an oversight to
me.

Are you sure you don’t get any? What compiler/platform are you using,
and what other feature test macros are you defining in your configure
and build process? And is this with SDL 2? (SDL 1, as mentioned
upthread, apparently forces full Gnarly GNU Gadzooks mode for you.)

Now that I think of it, I suppose an argument can be made that one is
asked to write to SDL as the “language” rather than to C with SDL as
a library (especially considering things like the main-mangling on
some platforms). This still seems hazardous and surprising since it
isn’t able to actually mediate all the other interactions. If the
point is to help one make a portable application, interfering with eir
own efforts to that effect can be counterproductive.

—> Drake Wilson

Quoth Sik the hedgehog <sik.the.hedgehog at gmail.com>, on 2013-06-11 05:07:36 -0300:

Better question, why would GNU’s feature set allow implicit function
declarations while the standard counterpart doesn’t? Implicit
declarations date back from the pre-standard era, they shouldn’t be
allowed anymore, and they will trigger warnings always unless you
disable warnings in the first place.

I’d guess -std=gnu99 also uses different default feature test macros
for the C library and causes the pile of transitive inclusions from
SDL_stdinc.h to pull in non-ISO-C setenv, strdup, etc., but I’ve never
actively used it in a new program, so…

Sounds weird. I compile my programs with C++, using
both gcc 4.2 --std=c++98 and clang 3.3 --std=c++11,
don’t seem to have many problems except for heaps of stupid
warnings about style.

The one serious one I ran into was the conflict between
GNU and Posix on strerror_r. [Nan etc is also a mess]

Generally C++ resolves most of these issues and doesn’t
require nearly as much crap to get working as C,
even if you’re only using C like code.

[My code is written in Felix which is mechanically translated into C++.
Thats even better because I can control the translation]On 11/06/2013, at 6:27 PM, Drake Wilson wrote:


john skaller
@john_skaller
http://felix-lang.org

2013/6/11, Drake Wilson :

Are you sure you don’t get any? What compiler/platform are you using,
and what other feature test macros are you defining in your configure
and build process? And is this with SDL 2? (SDL 1, as mentioned
upthread, apparently forces full Gnarly GNU Gadzooks mode for you.)

Platform: 64-bit Ubuntu
Compiler options: -O3 -s -std=c99 -Wall -Wextra
Linker options: -lvorbisfile -lvorbis -logg -lSDL2 -lphysfs -lpng15 -lz

To build:

./configure
make
sudo make install
sudo ldconfig <-- because I don’t want to reboot

Note I’m using -l directly, I’m not using pkg-config (I’m using
Code::Blocks though). Also note I’m using SDL standalone, without any
of the satellite libraries. And as you can see I do have warnings
enabled :stuck_out_tongue:

Maybe pkg-config is setting some other option it shouldn’t?

Quoth john skaller , on 2013-06-11 19:11:11 +1000:

Generally C++ resolves most of these issues and doesn’t
require nearly as much crap to get working as C,
even if you’re only using C like code.

I use C99. I depend on C ABI by default, designated initializers and
inline compounds, variable-length autos, flexible arrays in structs,
and sometimes offsetof. I use “static” inside the brackets of
fixed-length array parameters in function prototypes. I use “new” and
"class" as variable names! So… sort of, maybe, but in practice no.
(Yes, I’m aware this makes it harder to construct a viable Windows
toolchain.)

If I were to go that route I’d be tempted to go straight for D…

Anyway, that’s getting off-topic, but basically “problem with C
library, therefore use C++” may be viable a lot of the time but not in
general.

—> Drake Wilson

Quoth Sik the hedgehog <sik.the.hedgehog at gmail.com>, on 2013-06-11 06:49:06 -0300:

Platform: 64-bit Ubuntu
Compiler options: -O3 -s -std=c99 -Wall -Wextra
Linker options: -lvorbisfile -lvorbis -logg -lSDL2 -lphysfs -lpng15 -lz

Which C compiler and version? Which SDL version? (My tarball has SHA256
cdc8f1fc7e564a56440df71f8fcafc55ae53f36ad4d530af15f56f24cd154b19, which
I’d intended to mention but forgot about.)

Are you willing to show a full set of compiler and linker invocations,
the source of a test program, and/or the contents of your SDL.h and
SDL_stdinc.h? I don’t want to overburden you since you’re not the one
running into problems, but I’d sort of like to get to the bottom of
this.

—> Drake Wilson

…I think I know from where the problem comes. I looked at
SDL_stdinc.h, it decides whether to use those functions or not based
on #defines. Problem: setenv is declared in stdlib.h, strdup is
declared in string.h (despite neither of those being part of the
standard library officially - they’re defined by POSIX instead).

In other words, it means that for some reason SDL is being told those
functions exist, but the system headers say otherwise. Maybe that’s
the issue? Note that on some platforms the system headers will declare
functions depending on the standards mode in use. This means that e.g.
-std=c99 will get rid of anything not explicitly defined in the
standard, while -std=gnu99 will be more lenient and allow non-standard
functions to be declared.

Is there another way to get those two functions? :confused: (there’s always
the option to define the prototypes of the functions directly, but
that’s rather risky)

…I think I know from where the problem comes. I looked at
SDL_stdinc.h, it decides whether to use those functions or not based
on #defines. Problem: setenv is declared in stdlib.h, strdup is
declared in string.h (despite neither of those being part of the
standard library officially - they’re defined by POSIX instead).

In other words, it means that for some reason SDL is being told those
functions exist, but the system headers say otherwise. Maybe that’s
the issue? Note that on some platforms the system headers will declare
functions depending on the standards mode in use. This means that e.g.
-std=c99 will get rid of anything not explicitly defined in the
standard, while -std=gnu99 will be more lenient and allow non-standard
functions to be declared.

As you note … you will not be so lucky. This is because Posix BREAKS
the C Standard(s – all of them). C headers are not permitted to contain
anything more or less than specified, but posix makes them do so.

So the compilers with --std=blah switches are all wrong. They actually
need

--std=c99
--std=c99-posix-xx

[i.e. --std=c99 should ensure headers do NOT contain any posix functions.]

Now, there is a simple fix for strdup.
DONT USE IT. It’s that simple. Its trivial to
define this function as say sdl_strdup and just use
that if you really have to.

setenv is tricker. I don’t know any reason you would want this
function. It never modifies the calling context. It is never
necessary when calling out to another process. Its only use
is modifying the environment of the current program, and is
only useful if the program contains code not under your control,
eg a third party library.

In your own code you can create your own “environment” initialised
from the environment at startup. Then you can modify it without
setenv and query it as you please. Of course this will not work if
you’re using foreign code that uses genenv. So my question is:
where does this happen?On 13/06/2013, at 6:54 PM, Sik the hedgehog wrote:


john skaller
@john_skaller
http://felix-lang.org

2013/6/13, john skaller :

Now, there is a simple fix for strdup.
DONT USE IT. It’s that simple. Its trivial to
define this function as say sdl_strdup and just use
that if you really have to.

Assuming I didn’t do anything stupid, strdup could be easily defined as:

char *strdup (const char *str) {
char *temp = malloc(strlen(str) + 1);
if (temp == NULL) return NULL;
strcpy(temp, str);
return temp;
}

That should be small enough to still get inlined on modern systems.
It’s probably possible to use this code in the inlined function
directly.

setenv is tricker. I don’t know any reason you would want this
function. It never modifies the calling context. It is never
necessary when calling out to another process. Its only use
is modifying the environment of the current program, and is
only useful if the program contains code not under your control,
eg a third party library.

In your own code you can create your own “environment” initialised
from the environment at startup. Then you can modify it without
setenv and query it as you please. Of course this will not work if
you’re using foreign code that uses genenv. So my question is:
where does this happen?

No idea, maybe the game controller API uses it but I’m not really
sure. It’s possible it’s there just for the sake of convenience
(setenv isn’t standard so SDL providing it is more portable for
programs using it).

…also add a casting to that malloc in the example strdup code I
showed or you’ll have serious trouble in C++ >.>’ Still, you get the
idea.

2013/6/13, Sik the hedgehog <@Sik_the_hedgehog>:> 2013/6/13, john skaller :

Now, there is a simple fix for strdup.
DONT USE IT. It’s that simple. Its trivial to
define this function as say sdl_strdup and just use
that if you really have to.

Assuming I didn’t do anything stupid, strdup could be easily defined as:

char *strdup (const char *str) {
char *temp = malloc(strlen(str) + 1);
if (temp == NULL) return NULL;
strcpy(temp, str);
return temp;
}

That should be small enough to still get inlined on modern systems.
It’s probably possible to use this code in the inlined function
directly.

setenv is tricker. I don’t know any reason you would want this
function. It never modifies the calling context. It is never
necessary when calling out to another process. Its only use
is modifying the environment of the current program, and is
only useful if the program contains code not under your control,
eg a third party library.

In your own code you can create your own “environment” initialised
from the environment at startup. Then you can modify it without
setenv and query it as you please. Of course this will not work if
you’re using foreign code that uses genenv. So my question is:
where does this happen?

No idea, maybe the game controller API uses it but I’m not really
sure. It’s possible it’s there just for the sake of convenience
(setenv isn’t standard so SDL providing it is more portable for
programs using it).

Reference, please.On 13/06/13 12:44, john skaller wrote:

As you note … you will not be so lucky. This is because Posix BREAKS
the C Standard(s – all of them). C headers are not permitted to contain
anything more or less than specified, but posix makes them do so.

2013/6/13, john skaller <@john_skaller>:

Now, there is a simple fix for strdup.
DONT USE IT. It’s that simple. Its trivial to
define this function as say sdl_strdup and just use
that if you really have to.

Assuming I didn’t do anything stupid, strdup could be easily defined as:

char *strdup (const char *str) {
char *temp = malloc(strlen(str) + 1);
if (temp == NULL) return NULL;
strcpy(temp, str);
return temp;
}

That should be small enough to still get inlined on modern systems.
It’s probably possible to use this code in the inlined function
directly.

Well it would be useful to write:

inline char *strdup …

to hint it should be inlined :slight_smile:

Actually, there “different switches” problem is much worse than I thought.

The original problem is trying to compile with

gcc -std=c99

But its worse. On my box I have

gcc4.2
clang 3.3

and I use both. Someone else may have intel or EDG or other
compilers. Or use C++. More cans of worms. Or have Cygwin
and use MSys compilers AND several of the MS compilers
(at least in the old days the 32 and 64 bit compilers were distinct).

And its gets worse. Someone in an enterprise level organisation
may install shared headers to be used by people on multiple platforms
(of course the libraries might be distinct). Indeed on OSX you can make
PPC and Intel binaries in one shot.

The only realistic solution is standards conformance.

[Personally I’d pick C++, there’s no good reason to write
a game or game library in C these days, even if you only
write “C style code” in C++ its still better than C]

Of course SDL specifically uses non-standardised features
(access to game controllers etc). So configuration is necessary
to get at platform specific stuff (after all the whole point of
SDL is to establish a standard for game writing).

I just think it would good if SDL avoided trying to "fix"
broken compilers and used a modern standard
to solve some of the problems. After all SDL supports
touch screens, mobile devices and such like and the
hardware postdates the compiler technology SDL tries
to accommodate by decades.

No idea, maybe the game controller API uses it but I’m not really
sure. It’s possible it’s there just for the sake of convenience
(setenv isn’t standard so SDL providing it is more portable for
programs using it).

But you can’t. Its not possible to write setenv in terms of other
functions (unless they’re just renamed variants of setenv).On 13/06/2013, at 7:57 PM, Sik the hedgehog wrote:


john skaller
@john_skaller
http://felix-lang.org

As you note … you will not be so lucky. This is because Posix BREAKS
the C Standard(s – all of them). C headers are not permitted to contain
anything more or less than specified, but posix makes them do so.

Reference, please.

Read the fore-matter in the ISO C Standard (any version),
especially the parts related to conformance.

I don’t have a link handy, Google will find one. You can
also get online copies of the draft C++ standards (but not
the final one).

Or just apply simple logic. If standardised headers could
have ANY symbols defined in them the vendor wanted,
then the user would not be able to write ANY program
reliably, because there might be a clash.

So in fact certain symbols starting with _ and __ are reserved
for the vendor (and can be put in headers freely) but no
symbols starting with a letter my be added unless explicitly
specified in the Standard. Nor may any symbols be omitted
unless specified.

There are some optional symbols of course, and some symbols
are allowed to occur “extraneously” in additional headers
(because it isn’t possible to define the contents of some headers
without types defined in others).

Given that – Posix adds certain types and functions to
certain standardised C headers. And therefore it
breaks the C standard.On 13/06/2013, at 10:36 PM, Nikos Chantziaras wrote:

On 13/06/13 12:44, john skaller wrote:


john skaller
@john_skaller
http://felix-lang.org

2013/6/13, john skaller :

Well it would be useful to write:

inline char *strdup …

to hint it should be inlined :slight_smile:

That was just to show how strdup works ^^; My actual suggestion was to
include the code directly inside SDL’s function, then strdup wouldn’t
be touched at all for starters.

No idea, maybe the game controller API uses it but I’m not really
sure. It’s possible it’s there just for the sake of convenience
(setenv isn’t standard so SDL providing it is more portable for
programs using it).

But you can’t. Its not possible to write setenv in terms of other
functions (unless they’re just renamed variants of setenv).

OS-specific functions? :stuck_out_tongue:

As you note … you will not be so lucky. This is because Posix BREAKS
the C Standard(s – all of them). C headers are not permitted to contain
anything more or less than specified, but posix makes them do so.

Reference, please.

Read the fore-matter in the ISO C Standard (any version),
especially the parts related to conformance.

I don’t have a link handy, Google will find one. You can
also get online copies of the draft C++ standards (but not
the final one).

Sorry, but the burden of proof is the responsibility of the accuser :wink:

But seriously, with that logic, one can also claim that the ISO C
standard is the one that breaks the POSIX one. So, meh.On 13/06/13 22:22, john skaller wrote:

On 13/06/2013, at 10:36 PM, Nikos Chantziaras wrote:

On 13/06/13 12:44, john skaller wrote:

It probably does… POSIX predates C89. Actually it seems both
standards were being developed at the same time, with *nix sticking to
POSIX and everything else to C89 (whenever the system decided to
follow any standard, that is). So from this viewpoint there isn’t even
a proper concept of standard library… sigh

Although at this point it’s unlikely the two standards will clash
(heavily at least), where POSIX overrides the C library is to turn
some of the undefined behavior into defined behavior. It’s more of a
problem of whether a system is POSIX compliant or not.

…is this going off-topic?

2013/6/13, Nikos Chantziaras :> On 13/06/13 22:22, john skaller wrote:

On 13/06/2013, at 10:36 PM, Nikos Chantziaras wrote:

On 13/06/13 12:44, john skaller wrote:

As you note … you will not be so lucky. This is because Posix BREAKS
the C Standard(s – all of them). C headers are not permitted to
contain
anything more or less than specified, but posix makes them do so.

Reference, please.

Read the fore-matter in the ISO C Standard (any version),
especially the parts related to conformance.

I don’t have a link handy, Google will find one. You can
also get online copies of the draft C++ standards (but not
the final one).

Sorry, but the burden of proof is the responsibility of the accuser :wink:

But seriously, with that logic, one can also claim that the ISO C
standard is the one that breaks the POSIX one. So, meh.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Quoth Sik the hedgehog <sik.the.hedgehog at gmail.com>, on 2013-06-13 05:54:39 -0300:

In other words, it means that for some reason SDL is being told those
functions exist, but the system headers say otherwise. Maybe that’s
the issue? Note that on some platforms the system headers will declare
functions depending on the standards mode in use.

This is pretty much what I said upthread regarding different
compilation environments for the SDL library and its consumer. Sorry
if I was unclear.

My main question for upstream is in what ways consumers of SDL rely on
the SDL_-prefixed versions of these functions (either in the explicit
API or /de facto/). I’d prefer to be able to drop them from my
compilation environment completely, either by default or with a macro
setting. My current feeling from looking at SDL_stdinc.h is that that
whole pile is mainly intended for use within SDL and therefore
exposing all this transitive dependency to consumers is unintentional.

To restate specifically for my own build process, taking SDL_strdup as
an example without loss of generality:

  • I don’t mind SDL_strdup being defined as an extern that points
    into the SDL library. It can be harmlessly ignored (or if SDL is
    guaranteed to provide it, I might decide to use it under that
    name).

  • I don’t want to have strdup defined by system headers while
    compiling my own source code, and that’s why I don’t just compile
    with _GNU_SOURCE as Nikos Chantziaras suggested. Defining
    SDL_strdup as inline implies this, so that doesn’t work for me.

  • If SDL links against strdup from (say) glibc, making the
    resultant binary depend on it, that’s mostly okay, since the
    binary is allowed to be more platform-specific than the source in
    that way.

Incidentally, the SDL 1.2 SDL_stdinc.h on my system seems less likely
to run into this problem because it uses macros rather than inline
functions and therefore does not require the target to exist at
compile time unless the macro is actually expanded. (This is aside
from sdl-config --cflags containing -D_GNU_SOURCE, which I consider
bogus as I described upthread.)

I am not at all interested in being told by john skaller et al. that
my problem is irrelevant because I should be using C++ instead. Nor
am I interested in screwing with the feature test macro rules of one
of my main target platforms. If the API is going to really state “you
have to compile under the same conditions as SDL itself and we won’t
bother minimizing it”, I don’t like that, but I’ll accept it and use
a minor local fork if that’s the authoritative answer.

—> Drake Wilson