cmacostimeposixsolaris

Compilation failing on MacOS with weird errors when _POSIX_C_SOURCE is defined


With the follow compiler flags:

-std=c11 -Werror -Wpedantic

Oracle Solaris 14.6 requires _POSIX_C_SOURCE/_XOPEN_SOURCE to be defined for the declaration of clock_gettime(), a function that's used by the this testing library I am including in the translation unit below.

The code compiles fine after defining it, but fails when compiled under Apple MacOS with these errors:

cc -std=c11 -fPIC -Wall -Wextra -Werror -Wwrite-strings -Wno-unused-variable -Wno-parentheses -Wpedantic -Warray-bounds -Wno-unused-function -Wstrict-prototypes -Wdeprecated -DDEBUG    tests.c   -o tests
In file included from tests.c:19:
In file included from ./acutest.h:377:
In file included from /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/sysctl.h:83:
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/ucred.h:101:2: error: unknown type name 'u_int'
        u_int   cr_version;             /* structure layout version */
        ^
In file included from tests.c:19:
In file included from ./acutest.h:377:
In file included from /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/sysctl.h:85:
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/proc.h:116:2: error: unknown type name 'u_int'
        u_int   p_estcpu;        /* Time averaged value of p_cpticks. */
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/proc.h:121:2: error: unknown type name 'u_int'
        u_int   p_swtime;        /* Time swapped in or out. */
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/proc.h:122:2: error: unknown type name 'u_int'
        u_int   p_slptime;       /* Time since last blocked. */
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/proc.h:136:2: error: unknown type name 'u_char'; did you mean 'char'?
        u_char  p_priority;     /* Process priority. */
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/proc.h:137:2: error: unknown type name 'u_char'; did you mean 'char'?
        u_char  p_usrpri;       /* User-priority based on p_cpu and p_nice. */
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/proc.h:142:2: error: unknown type name 'u_short'; did you mean 'short'?
        u_short p_xstat;        /* Exit status for wait; also stop signal. */
        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/proc.h:143:2: error: unknown type name 'u_short'; did you mean 'short'?
        u_short p_acflag;       /* Accounting flags. */
        ^
8 errors generated.
make[1]: *** [tests] Error 1
make: *** [test] Error 2
Error: Process completed with exit code 2.

What are these unknown types, and why do these errors disappear if I remove the macros?

Currently, I am avoiding these by only defining _POSIX_C_SOURCE/_XOPEN_SOURCE for Solaris:

#if defined(__sun) && defined(__SVR4)
    #define _POSIX_C_SOURCE 200819L
    #define _XOPEN_SOURCE 700
#endif

And here's the translation unit:

#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
    #define HAVE_STDALIGN_H
    #include <stdalign.h>
#endif

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>


#define _POSIX_C_SOURCE 200819L
#define _XOPEN_SOURCE 700

#include "acutest.h"

#include "arena.c"

/* *INDENT-OFF* */
/* In C2X/C23 or later, nullptr is a keyword. */
/* Patch up C18 (__STDC_VERSION__ == 201710L) and earlier versions.  */
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ <= 201710L
    #define nullptr ((void *)0)
#endif
/* *INDENT-ON* */

static inline bool is_aligned(const void *ptr, size_t byte_count)
{
    return (uintptr_t) ptr % byte_count == 0;
}

static void test_arena_new(void)
{
    TEST_CHECK(arena_new(stderr, 0) == nullptr);

    Arena *const arena = arena_new(nullptr, 100);

    TEST_CHECK(arena);
    arena_destroy(arena);

    uint8_t *const backing_storage1 = malloc(100 * (size_t) 1024);

    TEST_ASSERT(backing_storage1);

    Arena *const heap_arena = arena_new(backing_storage1, 100 * (size_t) 1024);

    TEST_CHECK(heap_arena);
    arena_destroy(heap_arena);
    free(backing_storage1);

#ifdef HAVE_STDALIGN_H
    static uint8_t alignas (max_align_t) backing_storage2[BUFSIZ];
    Arena *const static_arena =
        arena_new(backing_storage2, sizeof backing_storage2);
    TEST_CHECK(static_arena);
    arena_destroy(static_arena);

    uint8_t alignas (max_align_t) backing_storage3[BUFSIZ];
    Arena *const thread_local_arena =
        arena_new(backing_storage3, sizeof backing_storage3);
    TEST_CHECK(thread_local_arena);
    arena_destroy(thread_local_arena);
#endif
}

static void test_arena_destroy(void)
{
    Arena *const arena = arena_new(nullptr, 100);

    TEST_ASSERT(arena);
    arena_destroy(arena);
}

static void test_arena_reset(void)
{
    Arena *const arena = arena_new(nullptr, 100);

    TEST_ASSERT(arena);
    arena_reset(arena);

    for (size_t i = 0; i < arena->count; ++i) {
        TEST_CHECK(arena->pools[i]->offset == 0);
    }

    TEST_CHECK(arena->current == 1);
    arena_destroy(arena);
}

static void test_arena_alloc(void)
{
    Arena *const arena = arena_new(nullptr, 100);

    TEST_ASSERT(arena);

    TEST_CHECK(arena_alloc(arena, 1, 112) == nullptr);
    TEST_CHECK(arena_alloc(arena, 0, 1) == nullptr);
    TEST_CHECK(arena_alloc(arena, 1, 0) == nullptr);
    TEST_CHECK(arena_alloc(arena, 2, 5) == nullptr);
    TEST_CHECK(arena_alloc(arena, 3, 5) == nullptr);

    TEST_CHECK(arena_alloc(arena, 1, 95));
    uint8_t *const curr_pool = arena->pools[0]->buf;

    TEST_CHECK(curr_pool[96] == 0xA5 && curr_pool[97] == 0xA5
        && curr_pool[98] == 0xA5 && curr_pool[99] == 0xA5);

    arena_reset(arena);

#ifdef HAVE_STDALIGN_H
    const int *const a = arena_alloc(arena, alignof (int), 5 * sizeof *a);
    const double *const b = arena_alloc(arena, alignof (double), 2 * sizeof *b);
    const char *const c = arena_alloc(arena, 1, 10);
    const short *const d = arena_alloc(arena, alignof (short), 5 * sizeof *d);

    TEST_CHECK(a && is_aligned(a, alignof (int)));
    TEST_CHECK(b && is_aligned(b, alignof (double)));
    TEST_CHECK(c && is_aligned(c, 1));
    TEST_CHECK(d && is_aligned(d, alignof (short)));
#endif
    arena_destroy(arena);
}

static void test_arena_resize(void)
{
    Arena *arena = arena_new(nullptr, 1000);

    TEST_ASSERT(arena);

    TEST_CHECK(arena_resize(arena, stderr, 0) == nullptr);

    arena = arena_resize(arena, nullptr, 10000);
    TEST_CHECK(arena);
    TEST_CHECK(arena->current == 2 && arena->count == 2);

    const char *c = arena_alloc(arena, 1, 10000);

    TEST_ASSERT(c);

    arena_reset(arena);
    TEST_CHECK(arena->current == 1 && arena->count == 2);
    arena_destroy(arena);
}

static void test_arena_allocarray(void)
{
    Arena *const arena = arena_new(nullptr, 100);

    TEST_ASSERT(arena);

#ifdef HAVE_STDALIGN_H
    const int *const nums =
        arena_allocarray(arena, alignof (int), 10, sizeof *nums);
    TEST_CHECK(nums);
#endif

    TEST_CHECK(arena_allocarray(arena, 0, 10, 20) == nullptr);
    TEST_CHECK(arena_allocarray(arena, 10, 0, 20) == nullptr);
    TEST_CHECK(arena_allocarray(arena, 10, 20, 0) == nullptr);
    TEST_CHECK(arena_allocarray(arena, 2, 10, SIZE_MAX) == nullptr);

    arena_destroy(arena);
}

static void test_arena_realloc(void)
{
    Arena *const arena = arena_new(nullptr, 100);

    TEST_ASSERT(arena);

    TEST_ASSERT(arena_alloc(arena, 1, 10));
    TEST_CHECK(arena->pools[0]->offset == 10 && arena->last_alloc_size == 10);

    /* Test expansion. */
    TEST_CHECK(arena_realloc(arena, 20));
    TEST_CHECK(arena->pools[0]->offset == 20 && arena->last_alloc_size == 20);

    /* Test shrinking. */
    TEST_CHECK(arena_realloc(arena, 15));
    TEST_CHECK(arena->pools[0]->offset == 15 && arena->last_alloc_size == 15);

    /* Test deletion. */
    TEST_CHECK(arena_realloc(arena, 0));
    TEST_CHECK(arena->pools[0]->offset == 0 && arena->last_alloc_size == 0);
    arena_destroy(arena);
}

static void test_arena_pool_capacity(void)
{
    Arena *const arena = arena_new(nullptr, 100);

    TEST_ASSERT(arena);
    TEST_ASSERT(arena_alloc(arena, 1, 40));
    TEST_CHECK(arena_pool_capacity(arena) == 60);

    TEST_ASSERT(arena_alloc(arena, 1, 49));
    TEST_CHECK(arena_pool_capacity(arena) == 11);

    TEST_ASSERT(arena_alloc(arena, 1, 11));
    TEST_CHECK(arena_pool_capacity(arena) == 0);
    arena_destroy(arena);
}

static void test_arena_allocated_bytes(void)
{
    Arena *arena = arena_new(nullptr, 100);

    TEST_ASSERT(arena);
    arena = arena_resize(arena, nullptr, 10002);
    TEST_ASSERT(arena);
    TEST_CHECK(arena_allocated_bytes(arena) == 10102);
    arena_destroy(arena);
}

static void test_arena_allocated_bytes_including_metadata(void)
{
    Arena *arena = arena_new(nullptr, 100);

    TEST_ASSERT(arena);
    arena = arena_resize(arena, nullptr, 10002);
    TEST_CHECK(arena_allocated_bytes_including_metadata(arena) == 10102
        + offsetof(Arena, pools)
        + sizeof arena->pools[0] * arena->capacity);
    arena_destroy(arena);
}

/* *INDENT-OFF* */
TEST_LIST = {
    { "arena_new", test_arena_new },
    { "arena_destroy", test_arena_destroy },
    { "arena_reset", test_arena_reset },
    { "arena_alloc", test_arena_alloc },
    { "arena_resize", test_arena_resize },
    { "arena_allocarray", test_arena_allocarray },
    { "arena_realloc", test_arena_realloc },
    { "arena_pool_capacity", test_arena_pool_capacity},
    { "arena_allocated_bytes", test_arena_allocated_bytes },
    { "arena_allocated_bytes_including_metadata", test_arena_allocated_bytes_including_metadata },
    { nullptr, nullptr }
};
/* *INDENT-ON* */

Solution

  • Including <sys/types.h> in tests.c before any other include or define directive fixes all errors for missing types. As @Eric says in the comments, that is not a correction, just a kludge for the moment.