mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-26 01:20:05 +01:00
gmacros: Define G_CXX_STD_VERSION and check macros
Sadly, in C++ there's not an universal way to get what language standard is used to compile GLib-based programs, in fact while most compilers relies on `__cplusplus`, MSVC is defining that, but it does not use it to expose such information (unless `/Zc:__cplusplus` arg is used). On the other side, MSVC reports the language standard via _MSVC_LANG [1]. This complication makes us defining some macros in a very complex way (such as glib_typeof()), because we need to perform many checks just to understand if a C++ compiler is used and what standard is expecting. To avoid this, define multiple macros that can be used to figure out what C++ standard is being used. [1] https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-170
This commit is contained in:
parent
054b96fd09
commit
f9845abe39
@ -410,6 +410,10 @@ G_HAVE_GNUC_VISIBILITY
|
||||
G_GNUC_INTERNAL
|
||||
G_GNUC_MAY_ALIAS
|
||||
|
||||
<SUBSECTION>
|
||||
G_CXX_STD_VERSION
|
||||
G_CXX_STD_CHECK_VERSION
|
||||
|
||||
<SUBSECTION>
|
||||
G_DEPRECATED
|
||||
G_DEPRECATED_FOR
|
||||
|
38
glib/docs.c
38
glib/docs.c
@ -2527,6 +2527,44 @@
|
||||
* Since: 2.6
|
||||
*/
|
||||
|
||||
/**
|
||||
* G_CXX_STD_VERSION:
|
||||
*
|
||||
* The C++ standard version the code is compiling against, it's defined
|
||||
* with the same value of `__cplusplus` for C++ standard compatible
|
||||
* compilers, while it uses `_MSVC_LANG` in MSVC, given that the
|
||||
* standard definition depends on a compilation flag in such compiler.
|
||||
*
|
||||
* This is granted to be undefined when not compiling with a C++ compiler.
|
||||
*
|
||||
* See also: %G_CXX_STD_CHECK_VERSION
|
||||
*
|
||||
* Since: 2.76
|
||||
*/
|
||||
|
||||
/**
|
||||
* G_CXX_STD_CHECK_VERSION:
|
||||
* @version: The C++ version to be checked for compatibility
|
||||
*
|
||||
* Macro to check if the current compiler supports a specified @version
|
||||
* of the C++ standard. Such value must be numeric and can be provided both
|
||||
* in the short form for the well-known versions (e.g. `11`, `17`...) or in
|
||||
* the complete form otherwise (e.g. `201103L`, `201703L`, `205503L`...).
|
||||
*
|
||||
* When a C compiler is used, the macro is defined and returns always %FALSE.
|
||||
*
|
||||
* This value is compared against %G_CXX_STD_VERSION.
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* #if G_CXX_STD_CHECK_VERSION(20)
|
||||
* #endif
|
||||
* ]|
|
||||
*
|
||||
* Returns: %TRUE if @version is supported by the compiler, %FALSE otherwise
|
||||
*
|
||||
* Since: 2.76
|
||||
*/
|
||||
|
||||
/**
|
||||
* G_LIKELY:
|
||||
* @expr: the expression
|
||||
|
@ -64,6 +64,31 @@
|
||||
#define G_GNUC_EXTENSION
|
||||
#endif
|
||||
|
||||
#if !defined (__cplusplus)
|
||||
|
||||
# undef G_CXX_STD_VERSION
|
||||
# define G_CXX_STD_CHECK_VERSION(version) (0)
|
||||
|
||||
#else /* defined (__cplusplus) */
|
||||
|
||||
# if defined (_MSVC_LANG)
|
||||
# define G_CXX_STD_VERSION (_MSVC_LANG > __cplusplus ? _MSVC_LANG : __cplusplus)
|
||||
# else
|
||||
# define G_CXX_STD_VERSION __cplusplus
|
||||
# endif /* defined(_MSVC_LANG) */
|
||||
|
||||
# define G_CXX_STD_CHECK_VERSION(version) ( \
|
||||
((version) >= 199711L && (version) <= G_CXX_STD_VERSION) || \
|
||||
((version) == 98 && G_CXX_STD_VERSION >= 199711L) || \
|
||||
((version) == 03 && G_CXX_STD_VERSION >= 199711L) || \
|
||||
((version) == 11 && G_CXX_STD_VERSION >= 201103L) || \
|
||||
((version) == 14 && G_CXX_STD_VERSION >= 201402L) || \
|
||||
((version) == 17 && G_CXX_STD_VERSION >= 201703L) || \
|
||||
((version) == 20 && G_CXX_STD_VERSION >= 202002L) || \
|
||||
0)
|
||||
|
||||
#endif /* !defined (__cplusplus) */
|
||||
|
||||
/* Every compiler that we target supports inlining, but some of them may
|
||||
* complain about it if we don't say "__inline". If we have C99, or if
|
||||
* we are using C++, then we can use "inline" directly. Unfortunately
|
||||
|
@ -19,6 +19,115 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#if !defined (G_CXX_STD_VERSION) || !defined (G_CXX_STD_CHECK_VERSION)
|
||||
#error G_CXX_STD_VERSION is not defined
|
||||
#endif
|
||||
|
||||
G_STATIC_ASSERT (G_CXX_STD_VERSION);
|
||||
|
||||
#if G_CXX_STD_VERSION >= 199711L
|
||||
G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (98));
|
||||
G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (199711L));
|
||||
G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (03));
|
||||
#endif
|
||||
|
||||
#if G_CXX_STD_VERSION == 199711L
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (11));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (201103L));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (14));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (201402L));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (17));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (201703L));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (20));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (202002L));
|
||||
#endif
|
||||
|
||||
#if G_CXX_STD_VERSION >= 201103L
|
||||
G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (98));
|
||||
G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (199711L));
|
||||
G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (03));
|
||||
G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (11));
|
||||
G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (201103L));
|
||||
#endif
|
||||
|
||||
#if G_CXX_STD_VERSION == 201103L
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (14));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (201402L));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (17));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (201703L));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (20));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (202002L));
|
||||
#endif
|
||||
|
||||
#if G_CXX_STD_VERSION >= 201402L
|
||||
G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (14));
|
||||
G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (201402L));
|
||||
#endif
|
||||
|
||||
#if G_CXX_STD_VERSION == 201402L
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (17));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (201703L));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (20));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (202002L));
|
||||
#endif
|
||||
|
||||
#if G_CXX_STD_VERSION >= 201703L
|
||||
G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (17));
|
||||
G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (201703L));
|
||||
#endif
|
||||
|
||||
#if G_CXX_STD_VERSION == 201703L
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (20));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (202002L));
|
||||
#endif
|
||||
|
||||
#if G_CXX_STD_VERSION >= 202002L
|
||||
G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (20));
|
||||
G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (202002L));
|
||||
#endif
|
||||
|
||||
#if G_CXX_STD_VERSION == 202002L
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (23));
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (202300L));
|
||||
#endif
|
||||
|
||||
#ifdef _G_EXPECTED_CXX_STANDARD
|
||||
static void
|
||||
test_cpp_standard (void)
|
||||
{
|
||||
guint64 std_version = 0;
|
||||
|
||||
if (!g_ascii_string_to_unsigned (_G_EXPECTED_CXX_STANDARD, 10, 0, G_MAXUINT64,
|
||||
&std_version, NULL))
|
||||
{
|
||||
g_test_skip ("Expected standard value is non-numeric: "
|
||||
_G_EXPECTED_CXX_STANDARD);
|
||||
return;
|
||||
}
|
||||
|
||||
#if !G_GNUC_CHECK_VERSION (11, 0)
|
||||
if (std_version >= 20)
|
||||
{
|
||||
// See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93821
|
||||
g_test_skip ("Expected standard version is not properly supported by compiler");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
g_test_message ("Checking if '" G_STRINGIFY (G_CXX_STD_VERSION) "' respects "
|
||||
"the expected standard version '" _G_EXPECTED_CXX_STANDARD "'");
|
||||
g_assert_true (G_CXX_STD_CHECK_VERSION (std_version));
|
||||
|
||||
if (std_version < 10 || std_version > 90)
|
||||
std_version = 97;
|
||||
|
||||
if (std_version >= 90)
|
||||
g_assert_cmpuint (G_CXX_STD_VERSION, >=, (std_version + 1900) * 100);
|
||||
else
|
||||
g_assert_cmpuint (G_CXX_STD_VERSION, >=, (std_version + 2000) * 100);
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int dummy;
|
||||
@ -186,12 +295,15 @@ test_steal_pointer (void)
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
#if __cplusplus >= 201103L
|
||||
#if G_CXX_STD_CHECK_VERSION (11)
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
#else
|
||||
g_test_init (&argc, &argv, static_cast<void *>(NULL));
|
||||
#endif
|
||||
|
||||
#ifdef _G_EXPECTED_CXX_STANDARD
|
||||
g_test_add_func ("/C++/check-standard-" _G_EXPECTED_CXX_STANDARD, test_cpp_standard);
|
||||
#endif
|
||||
g_test_add_func ("/C++/typeof", test_typeof);
|
||||
g_test_add_func ("/C++/atomic-pointer-compare-and-exchange", test_atomic_pointer_compare_and_exchange);
|
||||
g_test_add_func ("/C++/atomic-pointer-compare-and-exchange-full", test_atomic_pointer_compare_and_exchange_full);
|
||||
|
@ -22,6 +22,12 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#ifdef G_CXX_STD_VERSION
|
||||
#error G_CXX_STD_VERSION should be undefined in C programs
|
||||
#endif
|
||||
|
||||
G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (98));
|
||||
|
||||
/* Test that G_STATIC_ASSERT_EXPR can be used as an expression */
|
||||
static void
|
||||
test_assert_static (void)
|
||||
|
@ -187,7 +187,7 @@ if have_cxx
|
||||
'cxx-@0@'.format(std) : {
|
||||
'source' : ['cxx.cpp'],
|
||||
'suite' : ['cpp'],
|
||||
'cpp_args' : [arg],
|
||||
'cpp_args' : [arg, '-D_G_EXPECTED_CXX_STANDARD="@0@"'.format(std)],
|
||||
},
|
||||
}
|
||||
endforeach
|
||||
|
Loading…
x
Reference in New Issue
Block a user