portability: speed and modernize autoconf; compiler.h improvements

- Add some features to autoconf that makes it cleaner and faster
- Modernize some of the autoconf macros
- Update compiler.h with some C23 features

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin 2025-09-16 13:25:39 -07:00
parent 95cf51c306
commit 55dd65cddc
12 changed files with 173 additions and 57 deletions

View file

@ -1895,7 +1895,7 @@ static const char no_file_name[] = "nasm"; /* What to print if no file name */
/*
* For fatal/critical/panic errors, kill this process.
*/
static fatal_func die_hard(errflags true_type, errflags severity)
static_fatal_func die_hard(errflags true_type, errflags severity)
{
fflush(NULL);

View file

@ -1,5 +1,5 @@
dnl --------------------------------------------------------------------------
dnl PA_ADD_CFLAGS(variable, flag [,actual_flag [,success [,failure]]]])
dnl PA_ADD_CFLAGS(flag [,actual_flag [,success [,failure]]]])
dnl
dnl Attempt to add the given option to xFLAGS, if it doesn't break
dnl compilation. If the option to be tested is different than the

View file

@ -1,5 +1,5 @@
dnl --------------------------------------------------------------------------
dnl PA_ADD_FLAGS(flagvar, flags)
dnl PA_ADD_FLAGS(variable, flag [,actual_flag [,success [,failure]]]])
dnl
dnl Add [flags] to the variable [flagvar] if and only if it is accepted
dnl by all languages affected by [flagvar], if those languages have

View file

@ -1,10 +1,12 @@
dnl --------------------------------------------------------------------------
dnl PA_ADD_HEADERS(headers...)
dnl
dnl Call AC_CHECK_HEADERS(), and add to ac_includes_default if found
dnl Call AC_CHECK_HEADERS_ONCE(), and add to ac_includes_default if found
dnl --------------------------------------------------------------------------
AC_DEFUN([_PA_ADD_HEADER],
[AC_CHECK_HEADERS([$1],[ac_includes_default="$ac_includes_default
[AC_CHECK_HEADERS_ONCE([$1])
AS_IF([test x$ac_ac_header_$1 = xyes],
[ac_includes_default="$ac_includes_default
#include <$1>"
])
])

View file

@ -13,7 +13,10 @@ AC_DEFUN([PA_COMMON_ATTRIBUTES],
PA_FUNC_ATTRIBUTE(sentinel,,,[const char *, ...],["a","b",NULL],end_with_null)
PA_FUNC_ATTRIBUTE(format,[printf,1,2],int,[const char *, ...],["%d",1])
PA_FUNC_ATTRIBUTE(const)
PA_FUNC_ATTRIBUTE(unsequenced)
PA_FUNC_ATTRIBUTE(reproducible)
PA_FUNC_ATTRIBUTE(pure)
PA_FUNC_ATTRIBUTE(cold,,,,,unlikely_func)
PA_FUNC_ATTRIBUTE(maybe_unused)
PA_FUNC_ATTRIBUTE(unused)
PA_FUNC_ATTRIBUTE_ERROR])

View file

@ -0,0 +1,13 @@
dnl --------------------------------------------------------------------------
dnl PA_FIND_FLAGS(flagvar, flags_list)
dnl
dnl Add the first set of flags in flags_list that is accepted by
dnl by all languages affected by [flagvar], if those languages have
dnl been previously seen in the script.
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_FIND_FLAGS],
[_pa_find_flags_done=no
m4_foreach([_pa_find_flags_flag],[$2],
[
AS_IF([test x$_pa_find_flags_done != xyes],
[PA_ADD_FLAGS([$1],_pa_find_flags_flag,,[_pa_find_flags_done=yes])])])])

View file

@ -10,8 +10,7 @@ AC_DEFUN([PA_FUNC_SNPRINTF],
for pa_try_func_snprintf in snprintf _snprintf
do
AS_IF([test $pa_cv_func_snprintf = no],
[AC_LINK_IFELSE([AC_LANG_SOURCE([
AC_INCLUDES_DEFAULT
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[
const char *snprintf_test(int x);
const char *snprintf_test(int x)
{
@ -20,12 +19,9 @@ const char *snprintf_test(int x)
sz = $pa_try_func_snprintf(buf, sizeof buf, "Hello = %d", x);
return (sz < sizeof buf) ? buf : NULL;
}
int main(void) {
]],[[
puts(snprintf_test(33));
return 0;
}
])],
]])],
[pa_cv_func_snprintf=$pa_try_func_snprintf])])
done
])

View file

@ -10,12 +10,11 @@ AC_DEFUN([PA_FUNC_VSNPRINTF],
for pa_try_func_vsnprintf in vsnprintf _vsnprintf
do
AS_IF([test $pa_cv_func_vsnprintf = no],
[AC_LINK_IFELSE([AC_LANG_SOURCE([
AC_INCLUDES_DEFAULT
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[
const char *vsnprintf_test(const char *fmt, va_list va);
const char *vsnprintf_test(const char *fmt, va_list va)
{
static char buf[[256]];
static char buf[256];
size_t sz;
sz = $pa_try_func_vsnprintf(buf, sizeof buf, fmt, va);
return (sz < sizeof buf) ? buf : NULL;
@ -30,13 +29,10 @@ const char *vsnprintf_caller(const char *fmt, ...)
what = vsnprintf_test(fmt, va);
va_end(va);
return what;
}
int main(void) {
}]], [[
puts(vsnprintf_caller("Hello = %d", 33));
return 0;
}
])],
]])],
[pa_cv_func_vsnprintf=$pa_try_func_vsnprintf])])
done
])

View file

@ -3,11 +3,20 @@ dnl PA_PROG_CC()
dnl
dnl Similar to AC_PROG_CC, but add a prototype for main() to
dnl AC_INCLUDES_DEFAULT to avoid -Werror from breaking compilation.
dnl (Very odd!)
dnl
dnl It can optionally take lists of CFLAGS to be added. For each argument,
dnl only the *first* flag accepted is added.
dnl
dnl BUG: this expands AC_CHECK_HEADERS_ONCE() before the flags get
dnl probed. Don't know yet how to fix that.
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_PROG_CC],
[AC_PROG_CC
AS_IF([test x$ac_cv_prog != xno],
[ac_includes_default="$ac_includes_default
AC_DEFUN_ONCE([PA_PROG_CC],
[AC_REQUIRE([AC_PROG_CC])
AC_USE_SYSTEM_EXTENSIONS
ac_includes_default="$ac_includes_default
#ifndef __cplusplus
extern int main(void);
#endif"])])
#endif"
PA_FIND_FLAGS(CFLAGS,[$1])
])

View file

@ -67,6 +67,46 @@
# endif
#endif
#ifndef unsequenced_func
# ifdef HAVE_FUNC_ATTRIBUTE_UNSEQUENCED
# define unsequenced_func ATTRIBUTE(unsequenced)
# else
# define unsequenced_func
# endif
#endif
#ifndef unsequenced_func_ptr
# ifdef HAVE_FUNC_PTR_ATTRIBUTE_UNSEQUENCED
# define unsequenced_func_ptr ATTRIBUTE(unsequenced)
# else
# define unsequenced_func_ptr
# endif
#endif
#ifndef noreturn_func
# ifdef HAVE_FUNC_ATTRIBUTE_NORETURN
# define noreturn_func ATTRIBUTE(noreturn)
# else
# define noreturn_func
# endif
#endif
#ifndef reproducible_func
# ifdef HAVE_FUNC_ATTRIBUTE_REPRODUCIBLE
# define reproducible_func ATTRIBUTE(reproducible)
# else
# define reproducible_func
# endif
#endif
#ifndef reproducible_func_ptr
# ifdef HAVE_FUNC_PTR_ATTRIBUTE_REPRODUCIBLE
# define reproducible_func_ptr ATTRIBUTE(reproducible)
# else
# define reproducible_func_ptr
# endif
#endif
#ifndef pure_func
# ifdef HAVE_FUNC_ATTRIBUTE_PURE
# define pure_func ATTRIBUTE(pure)
@ -83,14 +123,6 @@
# endif
#endif
#ifndef noreturn_func
# ifdef HAVE_FUNC_ATTRIBUTE_NORETURN
# define noreturn_func ATTRIBUTE(noreturn)
# else
# define noreturn_func
# endif
#endif
#ifndef unlikely_func
# ifdef HAVE_FUNC_ATTRIBUTE_COLD
# define unlikely_func ATTRIBUTE(cold)
@ -107,6 +139,22 @@
# endif
#endif
#ifndef maybe_unused_func
# ifdef HAVE_FUNC_ATTRIBUTE_MAYBE_UNUSED
# define maybe_unused_func ATTRIBUTE(maybe_unused)
# else
# define maybe_unused_func
# endif
#endif
#ifndef maybe_unused_func_ptr
# ifdef HAVE_FUNC_PTR_ATTRIBUTE_MAYBE_UNUSED
# define maybe_unused_func_ptr ATTRIBUTE(maybe_unused)
# else
# define maybe_unused_func_ptr
# endif
#endif
#ifndef unused_func
# ifdef HAVE_FUNC_ATTRIBUTE_UNUSED
# define unused_func ATTRIBUTE(unused)

View file

@ -18,12 +18,11 @@ dnl the best very slow and doesn't buy us a single thing at all.
PA_CROSS_COMPILE
dnl Enable any available C extensions
PA_PROG_CC
PA_PROG_CC([[-std=c23],[-std=c17],[-std=c11],[-std=c99]])
AC_USE_SYSTEM_EXTENSIONS
PA_ADD_CPPFLAGS([-std=c23], [], [],
[PA_ADD_CPPFLAGS([-std=c17], [], [],
[PA_ADD_CPPFLAGS([-std=c11], [], [],
[PA_ADD_CPPFLAGS([-std=c99])])])])
dnl Some environments abuse __STRICT_ANSI__ to disable some
dnl function declarations
PA_ADD_CFLAGS([-U__STRICT_ANSI__])
dnl Options for debugging and profiling
PA_OPTION_DEBUG
@ -77,10 +76,6 @@ dnl Force clang to behave in a predictable manner, in order to make bugs
dnl possible to track down. gcc appears to have this behavior by default.
PA_ADD_CFLAGS([-ftrivial-auto-var-init=zero])
dnl Some environments abuse __STRICT_ANSI__ to disable some
dnl function declarations
PA_ADD_CFLAGS([-U__STRICT_ANSI__])
dnl Don't put things in common if we can avoid it. We don't want to
dnl assume all compilers support common, and this will help find those
dnl problems. This also works around an OSX linker problem.

View file

@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2007-2024 The NASM Authors - All Rights Reserved
* Copyright 2007-2025 The NASM Authors - All Rights Reserved
* See the file AUTHORS included with the NASM distribution for
* the specific copyright holders.
*
@ -187,18 +187,34 @@ size_t strlcpy(char *, const char *, size_t);
char * pure_func strrchrnul(const char *, int);
#endif
#ifndef __cplusplus /* C++ has false, true, bool as keywords */
#if !defined(__cplusplus) || (__STDC_VERSION >= 202311L)
/* C++ and C23 have bool, false, and true as proper keywords */
# ifdef HAVE_STDBOOL_H
/* If <stdbool.h> exists, include it explicitly to prevent it from
begin included later, causing the "bool" macro to be defined. */
# include <stdbool.h>
# elif defined(HAVE__BOOL)
# ifdef bool
/* Force bool to be a typedef instead of a macro. What a "clever" hack
this is... */
typedef bool /* The macro definition of bool */
# undef bool
bool; /* No longer the macro definition */
# endif
# elif defined(HAVE___BOOL)
typedef _Bool bool;
# define false 0
# define true 1
# else
/* This is sort of dangerous, since casts will behave different than
casting to the standard boolean type. Always use !!, not (bool). */
/* This is a bit dangerous, because casting to this ersatz bool
will not produce the same result as the standard (bool) cast.
Instead, use the bool() constructor-style macro defined below. */
typedef enum bool { false, true } bool;
# endif
/* This amounts to a C++-style conversion cast to bool. This works
because C ignores an argument-taking macro when used without an
argument and because bool was redefined as a typedef if it previously
was defined as a macro (see above.) */
# define bool(x) ((bool)!!(x))
#endif
/* Create a NULL pointer of the same type as the address of
@ -311,13 +327,26 @@ static inline void *mempset(void *dst, int c, size_t n)
* less likely to be taken.
*/
#if HAVE___BUILTIN_EXPECT
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
# define likely(x) __builtin_expect(bool(x), true)
# define unlikely(x) __builtin_expect(bool(x), false)
#else
# define likely(x) (!!(x))
# define unlikely(x) (!!(x))
# define likely(x) bool(x)
# define unlikely(x) bool(x)
#endif
/*
* Attributes
*/
/* Standard [[...]] attribute testing macros */
#if !defined(__has_c_attribute)
# define __has_c_attribute(x) 0
#endif
#if !defined(__has_cpp_attribute)
# define __has_cpp_attribute(x) 0
#endif
#define has_attribute(x) (__has_c_attribute(x) || __has_cpp_attribute(x))
#define safe_alloc never_null malloc_func
#define safe_alloc_ptr never_null_ptr malloc_func_ptr
@ -331,20 +360,45 @@ static inline void *mempset(void *dst, int c, size_t n)
/*
* How to tell the compiler that a function doesn't return
*/
#ifdef HAVE_STDNORETURN_H
#if has_attribute(noreturn)
# define no_return [[noreturn]]
#elif defined(HAVE_STDNORETURN_H)
# include <stdnoreturn.h>
# define no_return noreturn void
# define no_return noreturn
#elif defined(_MSC_VER)
# define no_return __declspec(noreturn) void
# define no_return __declspec(noreturn)
#else
# define no_return void noreturn_func
# define no_return noreturn_func
#endif
/* Function priority: pure < reproducible < unsequenced < const */
#ifndef HAVE_FUNC_ATTRIBUTE_REPRODUCIBLE
# undef reproducible_func
# define reproducible_func pure_func
# undef reproducible_func_ptr
# define reproducible_func_ptr pure_func_ptr
#endif
#ifndef HAVE_FUNC_ATTRIBUTE_UNSEQUENCED
# undef unsequenced_func
# define unsequenced_func reproducible_func
# undef unsequenced_func_ptr
# define unsequenced_func_ptr reproducible_func_ptr
#endif
#ifndef HAVE_FUNC_ATTRIBUTE_CONST
# undef const_func
# define const_func reproducible_func
# undef const_func_ptr
# define const_func_ptr reproducible_func_ptr
#endif
/*
* A fatal function is both unlikely and no_return
*/
#define fatal_func no_return unlikely_func
#define fatal_func_ptr no_return unlikely_func_ptr
#define fatal_func no_return unlikely_func void
#define static_fatal_func no_return unlikely_func static void
/*
* How to tell the compiler that a function takes a printf-like string