Check if `_GNU_SOURCE` or `_BSD_SOURCE` is supported by the libc? - c

I am curious if asprintf is available. Some libc implementations provide it under specific Feature Test Macros. Namely if you #define _GNU_SOURCE or #define _BSD_SOURCE you can get asprintf and a few other nice nonstandard extensions when you #include <stdio.h>.
There are a decent number of libc implementation. glibc obviously has asprintf; but so do a number of others.
How do I test if the libc implementation supports _BSD_SOURCE or _GNU_SOURCE?
My current test is bad, as it's just a kernel check not a compiler + libc + version check:
#if defined(__linux) || defined(__linux__) || defined(linux)
#define _GNU_SOURCE
#elif defined(BSD) || defined(__FreeBSD__) || defined(__FreeBSD__) || \
defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || \
defined(__DragonFly__)
#define _BSD_SOURCE
#endif
#include <stdio.h>
PS: I'm also using CMake and considered a check_symbol_exists(asprintf "stdio.h" HAVE_ASPRINTF) but not sure that'd suffice.

Related

After importing unistd.h, compiler states that sbrk() is an implicit declaration. Why is this?

I'm trying to implement malloc on CentOS, but I keep getting the error:
malloc.c: In function ‘malloc’:
malloc.c:11:5: error: implicit declaration of function ‘sbrk’ [-Werror=implicit-function-declaration]
mem_ptr = sbrk(SIXTY_FOUR_K); /* Allocate 64 kB of memory */
Here is the code that the compiler warning is referencing:
#include "malloc.h"
#include <unistd.h>
void * malloc(size_t bytes) {
uintptr_t mem_ptr;
if (bytes <= 0) { /* If user passes in bad value, return NULL */
return NULL;
}
mem_ptr = sbrk(SIXTY_FOUR_K); /* Allocate 64 kB of memory */
if (mem_ptr == -1) { /* sbrk() failed */
return NULL;
}
return (void *)mem_ptr;
}
According to the documentation on sbrk, you should just have to import unistd.h, which I do. Is there something I'm doing wrong?
Did you take a look at the Feature Test Macro requirements?
Feature Test Macro Requirements for glibc (see
feature_test_macros(7)):
brk(), sbrk():
Since glibc 2.12:
_BSD_SOURCE || _SVID_SOURCE ||
(_XOPEN_SOURCE >= 500 ||
_XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) &&
!(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
Before glibc 2.12:
_BSD_SOURCE || _SVID_SOURCE || _XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
See if compiling with something like -D_SVID_SOURCE will work (though it looks like there are a number of options based on that macro list)
As of glibc 2.19, a new feature test macro was added, _DEFAULT_SOURCE which is meant to replace _BSD_SOURCE and _SVID_SOURCE. For more information on _DEFAULT_SOURCE, see this question: What does -D_DEFAULT_SOURCE do?

How to convert between a dev_t and major/minor device numbers?

I'm trying to write a portable program that deals with ustar archives. For device files, these archives store the major and minor device numbers. However, the struct stat as laid out in POSIX only contains a single st_rdev member of type dev_t described with “Device ID (if file is character or block special).”
How can I convert between a pair of major and minor device numbers and a single st_rdev member as returned by stat() in a portable manner?
While all POSIX programming interfaces use the device number (of type dev_t) as is, FUZxxl pointed out in a comment to this answer that the common UStar file format -- most common tar archive format -- does split the device number into major and minor. (They are typically encoded as seven octal digits each, so for compatibility reasons one should limit to 21-bit unsigned major and 21-bit unsigned minor. This also means that mapping the device number to just the major or just the minor is not a reliable approach.)
The following include file expanding on Jonathon Reinhart's answer, after digging on the web for the various systems man pages and documentation (for makedev(), major(), and minor()), plus comments to this question.
#if defined(custom_makedev) && defined(custom_major) && defined(custom_minor)
/* Already defined */
#else
#undef custom_makedev
#undef custom_major
#undef custom_minor
#if defined(__linux__) || defined(__GLIBC__)
/* Linux, Android, and other systems using GNU C library */
#ifndef _BSD_SOURCE
#define _BSD_SOURCE 1
#endif
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(_WIN32)
/* 32- and 64-bit Windows. VERIFY: These are just a guess! */
#define custom_makedev(dmajor, dminor) ((((unsigned int)dmajor << 8) & 0xFF00U) | ((unsigned int)dminor & 0xFFFF00FFU))
#define custom_major(devnum) (((unsigned int)devnum & 0xFF00U) >> 8)
#define custom_minor(devnum) ((unsigned int)devnum & 0xFFFF00FFU)
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
/* FreeBSD, OpenBSD, NetBSD, and DragonFlyBSD */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(__APPLE__) && defined(__MACH__)
/* Mac OS X */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(_AIX) || defined (__osf__)
/* AIX, OSF/1, Tru64 Unix */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(hpux)
/* HP-UX */
#include <sys/sysmacros.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#elif defined(sun)
/* Solaris */
#include <sys/types.h>
#include <sys/mkdev.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#else
/* Unknown OS. Try a the BSD approach. */
#ifndef _BSD_SOURCE
#define _BSD_SOURCE 1
#endif
#include <sys/types.h>
#if defined(makedev) && defined(major) && defined(minor)
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum) major(devnum)
#define custom_minor(devnum) minor(devnum)
#endif
#endif
#if !defined(custom_makedev) || !defined(custom_major) || !defined(custom_minor)
#error Unknown OS: please add definitions for custom_makedev(), custom_major(), and custom_minor(), for device number major/minor handling.
#endif
#endif
One could glean additional definitions from existing UStar-format -capable archivers. Compatibility with existing implementations on each OS/architecture is, in my opinion, the most important thing here.
The above should cover all systems using GNU C library, Linux (including Android), FreeBSD, OpenBSD, NetBSD, DragonFlyBSD, Mac OS X, AIX, Tru64, HP-UX, and Solaris, plus any that define the macros when <sys/types.h> is included. Of the Windows part, I'm not sure.
As I understand it, Windows uses device 0 for all normal files, and a HANDLE (a void pointer type) for devices. I am not at all sure whether the above logic is sane on Windows, but many older systems put the 8 least significant bits of the device number into minor, and the next 8 bits into major, and the convention seems to be that any leftover bits would be put (without shifting) into minor, too. Examining existing UStar-format tar archives with references to devices would be useful, but I personally do not use Windows at all.
If a system is not detected, and the system does not use the BSD-style inclusion for defining the macros, the above will error out stopping the compilation. (I would personally add compile-time machinery that could help finding the correct header definitions, using e.g. find, xargs, and grep, in case that happens, with a suggestion to send the addition upstream, too. touch empty.h ; cpp -dM empty.h ; rm -f empty.h should show all predefined macros, to help with identifying the OS and/or C library.)
Originally, POSIX stated that dev_t must be an arithmetic type (thus, theoretically, it might have been some variant of float or double on some systems), but IEEE Std 1003.1, 2013 Edition says it must be an integer type. I would wager that means no known POSIX-y system ever used a floating-point dev_t type. It would seem that Windows uses a void pointer, or HANDLE type, but Windows is not POSIX-compliant anyway.
Use the major() and minor() macros after defining BSD_SOURCE.
The makedev(), major(), and minor() functions are not specified in
POSIX.1, but are present on many other systems.
http://man7.org/linux/man-pages/man3/major.3.html
I have a program based on an antique version of ls for Minix, but much mangled modified by me since then. It has the following code to detect the major and minor macros — and some comments about (now) antique systems where it has worked in the past. It assumes a sufficiently recent version of GCC is available to support #pragma GCC diagnostic ignored etc. You have to be trying pretty hard (e.g. clang -Weverything) to get the -Wunused-macros option in effect unless you include it explicitly.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
/* Defines to ensure major and minor macros are available */
#define _DARWIN_C_SOURCE /* In <sys/types.h> on MacOS X */
#define _BSD_SOURCE /* In <sys/sysmacros.h> via <sys/types.h> on Linux (Ubuntu 12.0.4) */
#define __EXTENSIONS__ /* Maybe beneficial on Solaris */
#pragma GCC diagnostic pop
/* From Solaris 2.6 sys/sysmacros.h
**
** WARNING: The device number macros defined here should not be used by
** device drivers or user software. [...] Application software should make
** use of the library routines available in makedev(3). [...] Macro
** routines bmajor(), major(), minor(), emajor(), eminor(), and makedev()
** will be removed or their definitions changed at the next major release
** following SVR4.
**
** #define O_BITSMAJOR 7 -- # of SVR3 major device bits
** #define O_BITSMINOR 8 -- # of SVR3 minor device bits
** #define O_MAXMAJ 0x7f -- SVR3 max major value
** #define O_MAXMIN 0xff -- SVR3 max major value
**
** #define L_BITSMAJOR 14 -- # of SVR4 major device bits
** #define L_BITSMINOR 18 -- # of SVR4 minor device bits
** #define L_MAXMAJ 0x3fff -- SVR4 max major value
** #define L_MAXMIN 0x3ffff -- MAX minor for 3b2 software drivers.
** -- For 3b2 hardware devices the minor is restricted to 256 (0-255)
*/
/* AC_HEADER_MAJOR:
** - defines MAJOR_IN_MKDEV if found in sys/mkdev.h
** - defines MAJOR_IN_SYSMACROS if found in sys/macros.h
** - otherwise, hope they are in sys/types.h
*/
#if defined MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#elif defined MAJOR_IN_SYSMACROS
#include <sys/sysmacros.h>
#elif defined(MAJOR_MINOR_MACROS_IN_SYS_TYPES_H)
/* MacOS X 10.2 - for example */
/* MacOS X 10.5 requires -D_DARWIN_C_SOURCE or -U_POSIX_C_SOURCE - see above */
#elif defined(USE_CLASSIC_MAJOR_MINOR_MACROS)
#define major(x) ((x>>8) & 0x7F)
#define minor(x) (x & 0xFF)
#else
/* Hope the macros are in <sys/types.h> or otherwise magically visible */
#endif
#define MAJOR(x) ((long)major(x))
#define MINOR(x) ((long)minor(x))
You will justifiably not be all that keen on the 'hope the macros are … magically visible' part of the code.
The reference to AC_HEADER_MAJOR is to the macro in the autoconf that deduces this information. It would be relevant if you have a config.h file generated by autoconf.
POSIX
Note that the POSIX pax command defines the ustar format and specifies that it includes devmajor and devminor in the information, but adds:
… Represent character special files and block special files respectively. In this case the devmajor and devminor fields shall contain information defining the device, the format of which is unspecified by this volume of POSIX.1-2008. Implementations may map the device specifications to their own local specification or may ignore the entry.
This means that there isn't a fully portable way to represent the numbers. This is not wholly unreasonable (but it is a nuisance); the meanings of the major and minor device numbers varies across platforms and is unspecified too. Any attempt to create block or character devices via ustar format will only work reasonably reliably if the source and target machines are running the same (version of the same) operating system — though usually they're portable across versions of the same operating system.

C - How do you ignore certain code depending on the OS (so one source code to fit all)

I want to make the source of my program cross-platform, and so far so good. I have a couple of functions that only really differ in syntax, so I am checking some defines at the start to see if its windows or linux and setting a variable to 1 or 0 depending on which one it is. My thinking was that I could do an if statement check on that variable to skip the incorrect syntax usage. I have realised now that it won't compile because the compiler still 'sees' the offending code. Can you you
#ifdef
to compartmentalize certain functions and call them within the code? Any suggestions?
You have to enclose the entire non cross-platform section between #ifdefs.
For instance:
int gettimeofday(struct timeval *tp, void *tzp)
{
#ifdef WIN32
struct _timeb timebuffer;
_ftime(&timebuffer);
tp->tv_sec = timebuffer.time;
tp->tv_usec = timebuffer.millitm * 1000;
return 0;
#else
tp->tv_sec = time(NULL);
tp->tv_usec = 0;
return 0;
#endif
}
Like this the compiler won't see the offending code since it is removed at the preprocessing step.
Of course you can, that's pretty much the standard way of doing that, at least for small parts of code. For bigger chunks, you might want to use the buildsystem instead, and have platform-specific code in separated files (foo_win.c, foo_unix.c); then, depending on the OS, you compile and link in the application only the right ones.
There are a lot of preprocessor defines that will tell you OS, compiler, architecture and other things; take a look at how Qt detects the OS or the compiler.
cpp -d M < /dev/null > somefile will show the default feature test macro settings (#define values) you can expect from a compiler - for the macros (#ifdef) stuff you want to test for. You have to run this on every system, plus some compilers add macros by default e.g. gcc.
#ifdef _SUN_OS
// put all Sun OS code here
#endif
You will have to find the macros to identify all of your platforms.
Yes, in the simplest case and assuming for example a function called foo() you can do something like that...
/* Are we on a Windows platform ? */
#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) || defined(__TOS_WIN__)
void foo( ... ) {
/* windows implementation */
}
/* Are we on a Linux platform ? */
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
void foo( ... ) {
/* linux implementation */
}
/* Are we on a Unix platform ? */
#elif defined(__unix__) || defined(__unix) || defined(unix) \
|| defined(__CYGWIN__) || ( defined(__APPLE__) && defined(__MACH) )
void foo( ... ) {
/* unix implementation */
}
/* Are we on Unsupported platform? */
#else
void foo( ... ) {
/* generic implementation */
}
#endif
Another option is to have different header files for each OS that implement the different versions of the function(s), and then conditionally #include the appropriate one.
Assuming some header files called: myproj_win32.h, myproj_linux.h, myproj_unix.h, myproj_generic.h you could do something like this...
/* Are we on a Windows platform ? */
#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) || defined(__TOS_WIN__)
#include "myproj_win32.h"
/* Are we on a Linux platform ? */
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
#include "myproj_linux.h"
/* Are we on a Unix platform ? */
#elif defined(__unix__) || defined(__unix) || defined(unix) \
|| defined(__CYGWIN__) || ( defined(__APPLE__) && defined(__MACH) )
#include "myproj_unix.h"
}
/* Are we on Unsupported platform? */
#else
#include "myproj_generic.h"
#endif
Only the correct version of the implementation will be compiled. There are more options, but those should be fine to get you started.
EDIT
Here is a useful link with pre-defined macros for common C/C++ compilers.

fileno() not available?

I am trying to use the posix function isatty() in my C code, to tell if the output is being redirected. However, to do this I need a file descriptor, and from my research it looks like fileno() is no longer included with stdio.h. Are there any alternative methods of getting a file descriptor?
It's still there, but you may have to explicitly turn on POSIX features. In particular, under Linux, fileno is only available if POSIX or XOPEN features are enabled. From the fileno(3) manpage:
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
fileno(): _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE
So, compile with -D_POSIX_SOURCE.
If you just want to know if output is being redirected, you can use:
#include <unistd.h>
...
if (isatty(STDOUT_FILENO))
error("redirect output.");
STDOUT_FILENO is generally 1.
fileno() is still the POSIX-standard way of getting the file descriptor associated with a file stream.
What compilation options are you using, on which platform(s)? Are you enabling the POSIX extensions?
gcc -std=gnu99 ...
This should make fileno() visible. (Using gcc -std=c99 -pedantic may make them invisible.)
Alternatively, add a variation on this stanza to your code, or put it in a header and include that at the start of your code:
#ifndef JLSS_ID_POSIXVER_H
#define JLSS_ID_POSIXVER_H
/*
** Include this file before including system headers. By default, with
** C99 support from the compiler, it requests POSIX 2001 support. With
** C89 support only, it requests POSIX 1997 support. Override the
** default behaviour by setting either _XOPEN_SOURCE or _POSIX_C_SOURCE.
*/
/* _XOPEN_SOURCE 700 is loosely equivalent to _POSIX_C_SOURCE 200809L */
/* _XOPEN_SOURCE 600 is loosely equivalent to _POSIX_C_SOURCE 200112L */
/* _XOPEN_SOURCE 500 is loosely equivalent to _POSIX_C_SOURCE 199506L */
#if !defined(_XOPEN_SOURCE) && !defined(_POSIX_C_SOURCE)
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600 /* SUS v3, POSIX 1003.1 2004 (POSIX 2001 + Corrigenda) */
#else
#define _XOPEN_SOURCE 500 /* SUS v2, POSIX 1003.1 1997 */
#endif /* __STDC_VERSION__ */
#endif /* !_XOPEN_SOURCE && !_POSIX_C_SOURCE */
#endif /* JLSS_ID_POSIXVER_H */
For my purposes, _XOPEN_SOURCE set to 600 is better than 700; it works out of the box on more machine types. You may be able to use 700. I keep this in a file posixver.h and my code starts
#include "posixver.h"
before any of the system headers. This allows me to change the rules (600 to 700, for example) centrally and I only need to recompile, not edit every source file.

implicit declaration using -std=c99

I'm getting this warning: (-std=c99 -pedantic)
warning: implicit declaration of function ‘strndup’ [-Wimplicit-function-declaration]
but I'm importing these libs:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
So what?! :(
// file.c:
#include "file.h"
strndup(...)
// file.h:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
The issue is your usage of the -std=c99 option. Since strndup() isn't part of C99, and you're asking the compiler to go into standards compliant mode, it won't provide the prototype for it. It still links of course, because your C library has it.
While you may be able to coax gcc into providing it by specifying feature macros yourself, I'd say it doesn't make much sense to be in C99 compliance mode and ask for GNU extensions for example. gcc already provides a mode for this, which will solve your warning: -std=gnu99.
My man strndup says
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
strdup():
_SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 ||
_XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED
|| /* Since glibc 2.12: */ _POSIX_C_SOURCE >= 200809L
strndup():
Since glibc 2.10:
_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700
Before glibc 2.10:
_GNU_SOURCE
strdupa(), strndupa(): _GNU_SOURCE
So I'd need to, eg, #define _POSIX_C_SOURCE 200809L before the first #include in your file.
see man 7 feature_test_macros
strndup is a GNU extension, so you need to compile with -D_GNU_SOURCE on the command line, or stick a #define _GNU_SOURCE 1 in your source files before the #include lines
This happened to me, and I added #define _XOPEN_SOURCE 500 and the warning went away.

Resources