[UNIX] gccで定義されるマクロ

gccでコンパイラが定義してくれるマクロ(predefined macro)を一覧する方法のメモ。
これは、gccのオンラインマニュアルに記載されている。

-dCHARS
CHARS is a sequence of one or more of the following characters, and
must not be preceded by a space.  Other characters are interpreted by
the compiler proper, or reserved for future versions of GCC, and so
are silently ignored.  If you specify characters whose behavior
conflicts, the result is undefined.
M   Instead of the normal output, generate a list of #define
directives for all the macros defined during the execution of the
preprocessor, including predefined macros.  This gives you a way
of finding out what is predefined in your version of the
preprocessor.  Assuming you have no file foo.h, the command
touch foo.h; cpp -dM foo.h
will show all the predefined macros.
If you use -dM without the -E option, -dM is interpreted as a
synonym for -fdump-rtl-mach.

あるLinuxでpthread関連のマクロがコンパイルできなかったことがあり、defineを追跡してみた。
Linuxでは/usr/include/features.hがdefine文をまとめて持っている。これをそれぞれのheaderファイルがincludeすることで動きを変えている。

$ gcc -E -dM features.h

でfeatures.hで生きているdefineを確認する。
結果を見ると、

#define __USE_XOPEN2K 1
#define __USE_XOPEN2K8 1

コンパイルできなかったdefineは
/usr/incluide/pthread.hにある。
これを見てみると

/* Mutex types.  */
enum
{
PTHREAD_MUTEX_TIMED_NP,
PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK_NP,
PTHREAD_MUTEX_ADAPTIVE_NP
#if defined __USE_UNIX98 || defined __USE_XOPEN2K8
,
PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP,
PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
#endif
#ifdef __USE_GNU
/* For compatibility.  */
, PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_TIMED_NP
#endif
};

となっている。
PTHREAD_MUTEX_RECURSIVEが定義されるのは

defined __USE_UNIX98 || defined __USE_XOPEN2K8

が成立したとき。
まず、features.hの中では以下の記述がある。

/* This is to enable the ISO C90 Amendment 1:1995 extension.  */
#if (defined _ISOC99_SOURCE || defined _ISOC9X_SOURCE \
|| (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199409L))
# define __USE_ISOC95   1
#endif
/* If none of the ANSI/POSIX macros are defined, use POSIX.1 and POSIX.2
(and IEEE Std 1003.1b-1993 unless _XOPEN_SOURCE is defined).  */
#if ((!defined __STRICT_ANSI__ || (_XOPEN_SOURCE - 0) >= 500) && \
!defined _POSIX_SOURCE && !defined _POSIX_C_SOURCE)
# define _POSIX_SOURCE  1
# if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) < 500
#  define _POSIX_C_SOURCE       2
# elif defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) < 600
#  define _POSIX_C_SOURCE       199506L
# elif defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) < 700
#  define _POSIX_C_SOURCE       200112L
# else
#  define _POSIX_C_SOURCE       200809L
# endif
# define __USE_POSIX_IMPLICITLY 1
#endif

ここでPOXIX_C_SOURCEが定義され、それが以下の記述に使われている。

#if (_POSIX_C_SOURCE - 0) >= 200809L
# define __USE_XOPEN2K8         1
# undef  _ATFILE_SOURCE
# define _ATFILE_SOURCE 1
#endif

このようにして__USE_XOPEN2K8が定義される。
POSIX_C_SOURCEを定義するif分岐の部分は古いLinuxでは異なっている場合があり、そのときはPOSIX_C_SOURCEが200809Lよりも小さい。
そのため、同じソースコードが同じヘッダファイルを使用していてもコンパイルエラーが発生することがある。

広告
%d人のブロガーが「いいね」をつけました。