mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-11-01 00:42:16 +01:00 
			
		
		
		
	macros: Add a generic way to get and check the supported C standard
Try to get the value of __STDC_VERSION__ if supported, if not just fallback to the oldest standard that any compiler should handle.
This commit is contained in:
		| @@ -411,6 +411,8 @@ G_GNUC_INTERNAL | ||||
| G_GNUC_MAY_ALIAS | ||||
|  | ||||
| <SUBSECTION> | ||||
| G_C_STD_VERSION | ||||
| G_C_STD_CHECK_VERSION | ||||
| G_CXX_STD_VERSION | ||||
| G_CXX_STD_CHECK_VERSION | ||||
|  | ||||
|   | ||||
							
								
								
									
										45
									
								
								glib/docs.c
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								glib/docs.c
									
									
									
									
									
								
							| @@ -2527,6 +2527,47 @@ | ||||
|  * Since: 2.6 | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * G_C_STD_VERSION: | ||||
|  * | ||||
|  * The C standard version the code is compiling against, it's normally | ||||
|  * defined with the same value of `__STDC_VERSION__` for C standard | ||||
|  * compatible compilers, while it uses the lowest standard version | ||||
|  * in pure MSVC, given that in such compiler the definition depends on | ||||
|  * a compilation flag. | ||||
|  * | ||||
|  * This is granted to be undefined when compiling with a C++ compiler. | ||||
|  * | ||||
|  * See also: %G_C_STD_CHECK_VERSION and %G_CXX_STD_VERSION | ||||
|  * | ||||
|  * Since: 2.76 | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * G_C_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. `90`, `99`...) or in | ||||
|  * the complete form otherwise (e.g. `199000L`, `199901L`, `205503L`...). | ||||
|  * | ||||
|  * When a C++ compiler is used, the macro is defined and returns always %FALSE. | ||||
|  * | ||||
|  * This value is compared against %G_C_STD_VERSION. | ||||
|  * | ||||
|  * |[<!-- language="C" --> | ||||
|  * #if G_C_STD_CHECK_VERSION(17) | ||||
|  * #endif | ||||
|  * ]| | ||||
|  * | ||||
|  * See also: %G_CXX_STD_CHECK_VERSION | ||||
|  * | ||||
|  * Returns: %TRUE if @version is supported by the compiler, %FALSE otherwise | ||||
|  * | ||||
|  * Since: 2.76 | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * G_CXX_STD_VERSION: | ||||
|  * | ||||
| @@ -2537,7 +2578,7 @@ | ||||
|  * | ||||
|  * This is granted to be undefined when not compiling with a C++ compiler. | ||||
|  * | ||||
|  * See also: %G_CXX_STD_CHECK_VERSION | ||||
|  * See also: %G_CXX_STD_CHECK_VERSION and %G_C_STD_VERSION | ||||
|  * | ||||
|  * Since: 2.76 | ||||
|  */ | ||||
| @@ -2560,6 +2601,8 @@ | ||||
|  * #endif | ||||
|  * ]| | ||||
|  * | ||||
|  * See also: %G_C_STD_CHECK_VERSION | ||||
|  * | ||||
|  * Returns: %TRUE if @version is supported by the compiler, %FALSE otherwise | ||||
|  * | ||||
|  * Since: 2.76 | ||||
|   | ||||
| @@ -69,8 +69,26 @@ | ||||
| # undef G_CXX_STD_VERSION | ||||
| # define G_CXX_STD_CHECK_VERSION(version) (0) | ||||
|  | ||||
| # if defined (__STDC_VERSION__) | ||||
| #  define G_C_STD_VERSION __STDC_VERSION__ | ||||
| # else | ||||
| #  define G_C_STD_VERSION 199000L | ||||
| # endif /* defined (__STDC_VERSION__) */ | ||||
|  | ||||
| # define G_C_STD_CHECK_VERSION(version) ( \ | ||||
|   ((version) >= 199000L && (version) <= G_C_STD_VERSION) || \ | ||||
|   ((version) == 89 && G_C_STD_VERSION >= 199000L) || \ | ||||
|   ((version) == 90 && G_C_STD_VERSION >= 199000L) || \ | ||||
|   ((version) == 99 && G_C_STD_VERSION >= 199901L) || \ | ||||
|   ((version) == 11 && G_C_STD_VERSION >= 201112L) || \ | ||||
|   ((version) == 17 && G_C_STD_VERSION >= 201710L) || \ | ||||
|   0) | ||||
|  | ||||
| #else /* defined (__cplusplus) */ | ||||
|  | ||||
| # undef G_C_STD_VERSION | ||||
| # define G_C_STD_CHECK_VERSION(version) (0) | ||||
|  | ||||
| # if defined (_MSVC_LANG) | ||||
| #  define G_CXX_STD_VERSION (_MSVC_LANG > __cplusplus ? _MSVC_LANG : __cplusplus) | ||||
| # else | ||||
|   | ||||
| @@ -23,7 +23,12 @@ | ||||
| #error G_CXX_STD_VERSION is not defined | ||||
| #endif | ||||
|  | ||||
| #ifdef G_C_STD_VERSION | ||||
| #error G_C_STD_VERSION should be undefined in C programs | ||||
| #endif | ||||
|  | ||||
| G_STATIC_ASSERT (G_CXX_STD_VERSION); | ||||
| G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (99)); | ||||
|  | ||||
| #if G_CXX_STD_VERSION >= 199711L | ||||
|   G_STATIC_ASSERT (G_CXX_STD_CHECK_VERSION (98)); | ||||
|   | ||||
| @@ -27,6 +27,81 @@ | ||||
| #endif | ||||
|  | ||||
| G_STATIC_ASSERT (!G_CXX_STD_CHECK_VERSION (98)); | ||||
| G_STATIC_ASSERT (G_C_STD_CHECK_VERSION (89)); | ||||
| G_STATIC_ASSERT (G_C_STD_CHECK_VERSION (90)); | ||||
|  | ||||
| #if G_C_STD_VERSION >= 199000L | ||||
|   G_STATIC_ASSERT (G_C_STD_CHECK_VERSION (89)); | ||||
|   G_STATIC_ASSERT (G_C_STD_CHECK_VERSION (90)); | ||||
|   G_STATIC_ASSERT (G_C_STD_CHECK_VERSION (199000L)); | ||||
| #endif | ||||
|  | ||||
| #if G_C_STD_VERSION == 198900L | ||||
|   G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (99)); | ||||
|   G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (199901L)); | ||||
|   G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (11)); | ||||
|   G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (201112L)); | ||||
|   G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (17)); | ||||
|   G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (201710L)); | ||||
| #endif | ||||
|  | ||||
| #if G_C_STD_VERSION >= 199901L | ||||
|   G_STATIC_ASSERT (G_C_STD_CHECK_VERSION (99)); | ||||
|   G_STATIC_ASSERT (G_C_STD_CHECK_VERSION (199901L)); | ||||
| #endif | ||||
|  | ||||
| #if G_C_STD_VERSION == 199901L | ||||
|   G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (11)); | ||||
|   G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (201112L)); | ||||
|   G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (17)); | ||||
|   G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (201710L)); | ||||
| #endif | ||||
|  | ||||
| #if G_C_STD_VERSION >= 201112L | ||||
|   G_STATIC_ASSERT (G_C_STD_CHECK_VERSION (11)); | ||||
|   G_STATIC_ASSERT (G_C_STD_CHECK_VERSION (201112L)); | ||||
| #endif | ||||
|  | ||||
| #if G_C_STD_VERSION == 201112L | ||||
|   G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (17)); | ||||
|   G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (201710L)); | ||||
| #endif | ||||
|  | ||||
| #if G_C_STD_VERSION >= 201710L | ||||
|   G_STATIC_ASSERT (G_C_STD_CHECK_VERSION (17)); | ||||
|   G_STATIC_ASSERT (G_C_STD_CHECK_VERSION (201710L)); | ||||
| #endif | ||||
|  | ||||
| #if G_C_STD_VERSION == 201710L | ||||
|   G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (23)); | ||||
|   G_STATIC_ASSERT (!G_C_STD_CHECK_VERSION (202300L)); | ||||
| #endif | ||||
|  | ||||
| #ifdef _G_EXPECTED_C_STANDARD | ||||
| static void | ||||
| test_c_standard (void) | ||||
| { | ||||
|   guint64 std_version = 0; | ||||
|  | ||||
|   if (!g_ascii_string_to_unsigned (_G_EXPECTED_C_STANDARD, 10, 0, G_MAXUINT64, | ||||
|                                    &std_version, NULL)) | ||||
|     { | ||||
|       g_test_skip ("Expected standard value is non-numeric: " | ||||
|                    _G_EXPECTED_C_STANDARD); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|   g_assert_true (G_C_STD_CHECK_VERSION (std_version)); | ||||
|  | ||||
|   if (std_version > 80 && std_version < 99) | ||||
|     std_version = 90; | ||||
|  | ||||
|   if (std_version >= 90) | ||||
|     g_assert_cmpuint (G_C_STD_VERSION, >=, (std_version + 1900) * 100); | ||||
|   else | ||||
|     g_assert_cmpuint (G_C_STD_VERSION, >=, (std_version + 2000) * 100); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| /* Test that G_STATIC_ASSERT_EXPR can be used as an expression */ | ||||
| static void | ||||
| @@ -71,6 +146,10 @@ main (int   argc, | ||||
| { | ||||
|   g_test_init (&argc, &argv, NULL); | ||||
|  | ||||
| #ifdef _G_EXPECTED_C_STANDARD | ||||
|   g_test_add_func ("/C/standard-" _G_EXPECTED_C_STANDARD, test_c_standard); | ||||
| #endif | ||||
|  | ||||
|   g_test_add_func ("/alignof/fallback", test_alignof_fallback); | ||||
|   g_test_add_func ("/assert/static", test_assert_static); | ||||
|   g_test_add_func ("/struct/sizeof_member", test_struct_sizeof_member); | ||||
|   | ||||
| @@ -306,7 +306,10 @@ foreach test_name, extra_args : glib_tests | ||||
|         '@0@-c-@1@'.format(test_name, std) : extra_args + { | ||||
|           'source' : extra_args.get('source', test_name + '.c'), | ||||
|           'suite' : ['cc'] + extra_args.get('suite', []), | ||||
|           'c_args' : [c_standards.get(std)] + extra_args.get('c_args', []), | ||||
|           'c_args' : [ | ||||
|             c_standards.get(std), | ||||
|             '-D_G_EXPECTED_C_STANDARD="@0@"'.format(std) | ||||
|           ] + extra_args.get('c_args', []), | ||||
|         } | ||||
|       } | ||||
|     endif | ||||
|   | ||||
		Reference in New Issue
	
	Block a user