From 8450156e98ee49484f3fadad791d5684f9576f8b Mon Sep 17 00:00:00 2001 From: eunhhu Date: Thu, 1 Oct 2026 18:19:14 +0100 Subject: Build with clang, and the core and store on macOS, again Apple clang 21 (an M3) and clang 19 refused what gcc let pass (research 029): - PURE_FIELD_REST was an enum of UINT32_MAX, past an int (C17): a macro. - a store's publish copied an entry rebuild left unset when the record was not found (the copy was never used): copied when it was made. - the log's image writer kept a count only Linux's sync_file_range uses. - ",{" + (row == from) read as adding an int to a string: said plainly. - the tests: mkdtemp, hidden by _POSIX_C_SOURCE on macOS, needs _DARWIN_C_SOURCE; a string split so that \x80 and a stay apart is bracketed; a count left over and a malloc measure only glibc has. The core's and the store's tests pass on the Mac. --- core/module.h | 2 +- core/test-module.c | 13 +++++++++---- serve/serve.c | 2 +- store/store-log.c | 5 ++++- store/store-tree.c | 2 +- store/test-log.c | 3 +++ store/test-tree-store.c | 3 +++ 7 files changed, 22 insertions(+), 8 deletions(-) diff --git a/core/module.h b/core/module.h index 2cc3109..162a8b1 100644 --- a/core/module.h +++ b/core/module.h @@ -113,7 +113,7 @@ enum { PURE_TIMER_LONGEST = 86400000, PURE_SOURCE = 64 }; * they are not whole. */ typedef enum { PURE_FIELD_U32 = 1, PURE_FIELD_BYTES = 2, PURE_FIELD_NUMBER = 3, PURE_FIELD_TEXT = 4, PURE_FIELD_ROWS = 5, PURE_FIELD_BOOL = 6, PURE_FIELD_I64 = 7 } PureFieldType; -enum { PURE_FIELD_REST = UINT32_MAX }; +#define PURE_FIELD_REST UINT32_MAX /* a macro: an enum's values are ints (C17) */ /* A field held in its payload's prefix (a u32, a number, a bool, an i64), and the bytes it takes there. */ static inline bool pure_field_fixed(uint8_t type) { return type == PURE_FIELD_U32 || type == PURE_FIELD_NUMBER || type == PURE_FIELD_BOOL || type == PURE_FIELD_I64; diff --git a/core/test-module.c b/core/test-module.c index 46da5f1..c91bd2c 100644 --- a/core/test-module.c +++ b/core/test-module.c @@ -1,4 +1,7 @@ #define _POSIX_C_SOURCE 200809L +#ifdef __APPLE__ +#define _DARWIN_C_SOURCE /* mkdtemp, which _POSIX_C_SOURCE hides there */ +#endif #include "module.h" #include "module-save.h" #include "module-store.h" @@ -781,7 +784,8 @@ enum { CUL = PURE_OP_CUR_LOAD, CS = PURE_OP_CUR_STORE, CM = PURE_OP_CUR_MOVE, TI static void texts(void) { static const S nums[] = {{"edits", 0}}; static const T textual[] = {{"note", 1, 0}, {"at", 2, 1}, {"title", 1, 1}}; - static const char *const constants[] = {"\xea\xb0\x80" "a\nbc", "\xeb\xa9\x94\xeb\xaa\xa8", "XYZ", + static const char *const constants[] = {("\xea\xb0\x80" "a\nbc"), /* apart: \x80a would be one escape */ + "\xeb\xa9\x94\xeb\xaa\xa8", "XYZ", " \xc2\xb7 ", "\xec\x9e\x90"}; static const I inputs[] = { {"typed", NULL, PURE_KIND_TEXT, false, NULL, 0}, KEY("left", "ArrowLeft"), KEY("right", "ArrowRight"), @@ -1113,7 +1117,7 @@ static void list_trees(void) { PureList *copies[SHARES]; Model shared[SHARES] = {{0}}; PureRetired retired[SHARES + 1] = {{0}}; - unsigned first = 0, held = 0, splits_seen = 0; + unsigned first = 0, held = 0; uint64_t epoch = 0; /* the copies', one after another */ size_t largest = 0, events = 0, undone = 0; for (unsigned event = 0; event < 6000; ++event) { @@ -1159,7 +1163,6 @@ static void list_trees(void) { pure_undo_commit(&undo); ++events; largest = model.count > largest ? model.count : largest; - splits_seen += model.count > 32; if (event % 7 == 0) CHECK(same_items(list, &model)); /* A save every few events: its records after the stored ones, or now * and then the items stored whole with none after them. */ @@ -1488,7 +1491,7 @@ static void list_mutations(void) { for (size_t at = 0; at < pure_list_count(app.lists[s]); ++at) for (unsigned f = 0; f < record->count; ++f) { PureCell cell = pure_list_get(app.lists[s], at, f); - if ((module_b.record_field_type[record->first + f] == PURE_RECORD_TEXT)) + if (module_b.record_field_type[record->first + f] == PURE_RECORD_TEXT) CHECK(pure_utf8_valid((PureSpan){cell.text, cell.size})); else CHECK(isfinite(cell.num)); } @@ -3823,7 +3826,9 @@ static void snapshot_held(Spec spec, void (*event)(PureApp *, uint32_t *)) { CHECK(held); Shown before = {was, 0, sizeof(was)}, shown = {shown_text, 0, sizeof(shown_text)}; describe(&app, &before); +#ifdef __GLIBC__ size_t used[3] = {0, 0, 0}; +#endif for (unsigned half = 0; half < 2; ++half) { #ifdef __GLIBC__ used[half] = mallinfo2().uordblks; diff --git a/serve/serve.c b/serve/serve.c index 81a338d..65a5c0b 100644 --- a/serve/serve.c +++ b/serve/serve.c @@ -1429,7 +1429,7 @@ static PureResult show_given(PureApp *app, const Route *route, size_t available, char head[80]; put_bytes(&o, head, (size_t)snprintf(head, sizeof(head), "{\"rows\":%zu,\"from\":%zu,\"items\":[", rows, from)); for (size_t row = from; row < end && !o.failed; ++row) { - put_bytes(&o, ",{" + (row == from), 2 - (row == from)); + put_bytes(&o, row == from ? "{" : ",{", row == from ? 1 : 2); for (unsigned k = 0; k < count; ++k) { put_bytes(&o, columns[k].key + !k, columns[k].length - !k); uint8_t kind = m->view_type[columns[k].view]; diff --git a/store/store-log.c b/store/store-log.c index f73d2bc..7b6f00c 100644 --- a/store/store-log.c +++ b/store/store-log.c @@ -493,7 +493,10 @@ PureResult pure_image_write(const char *directory, const char *name, bool (*next put64(head + 8, 0); /* its length, once known */ Digest digest = {0}; bool ok = write_all(fd, head, sizeof(head), 0), produced = true; - uint64_t at = sizeof(head), started = 0; + uint64_t at = sizeof(head); +#if defined(__linux__) + uint64_t started = 0; /* the bytes handed to the device */ +#endif for (PureSpan chunk; ok && (produced = next(context, &chunk)) && chunk.size;) for (size_t done = 0; ok && done < chunk.size;) { size_t take = chunk.size - done < STEP ? chunk.size - done : STEP; diff --git a/store/store-tree.c b/store/store-tree.c index ecdced6..3404edd 100644 --- a/store/store-tree.c +++ b/store/store-tree.c @@ -1202,7 +1202,7 @@ static PureResult publish(Session *session, Writer *writer, size_t count, const written = find(&session->tree, catalog, keys[i], &index, &found, ¤t, &stored) && rebuild(&session->tree, catalog, index * RECORD, found ? RECORD : 0, (PureSpan){record, RECORD}, &updated); - catalog = updated; + if (written) catalog = updated; } written = written && write_root(&session->tree, writer, &catalog, false) && flush(writer); /* Unpublished bytes stay in the tail; the next commit overwrites them. */ diff --git a/store/test-log.c b/store/test-log.c index 451f354..6e81c4c 100644 --- a/store/test-log.c +++ b/store/test-log.c @@ -5,6 +5,9 @@ * model kept, and its files stay as many as the unreleased entries need. * Then list images: written whole, read back, refused when damaged. */ #define _POSIX_C_SOURCE 200809L +#ifdef __APPLE__ +#define _DARWIN_C_SOURCE /* mkdtemp, which _POSIX_C_SOURCE hides there */ +#endif #include "log.h" #include "store.h" #include diff --git a/store/test-tree-store.c b/store/test-tree-store.c index 2ef9d22..2ffbc39 100644 --- a/store/test-tree-store.c +++ b/store/test-tree-store.c @@ -1,4 +1,7 @@ #define _POSIX_C_SOURCE 200809L +#ifdef __APPLE__ +#define _DARWIN_C_SOURCE /* mkdtemp, which _POSIX_C_SOURCE hides there */ +#endif #include "store.h" #include "state.h" #include -- cgit v1.2.3