This is a set of commits, each one trivial, that reorganizes code so that all C files are mostly self-contained.
These changes are merely fixes that make the files adhere to our current implicit style, which I'd describe as:
- Every C file (library, tests.c, ...) is a single translation unit ("unit build"), except that the libsepc256k1_precomputed is separate to speed up compilation.
- Internal "modules" are organized in headers (
.h) and implementation files (_impl.h). Symbols not present in the header are private to that module. - Internal "modules" should include the headers of all other modules they use.
secp256k1.cincludes all_impl.hfiles. Other C files include simplysecp256k1.c, or, if that isn't possible for some reason (e.g., in theprecompute_*.cfiles), the individual necessary_impl.hfiles.
So, none of these changes here should be controversial. In particular, I refrain from changing the above rules (e.g., by renaming the _impl.h to .c as suggested in #1039).
Why "mostly" self-contained?
After this PR, some errors remain when I run clang src/*.c and clang src/*.h on my machine. But all of them are special cases:
ctime_tests.crefuses to be compiled without valgrind or msan enabled.src/field_10x26_impl.h,src/int128_struct_impl.h, andsrc/scalar_low_impl.hare confused because the autodetection logic in the preprocessor picks field_5x64, native int 128, and scalar_4x64 on my machine.
<details> <summary>Full output of "clang src/*.c" and "clang src/*.h` </summary>
> clang src/*.c
src/ctime_tests.c:16:4: error: "This tool cannot be compiled without memory-checking interface (valgrind or msan)"
16 | # error "This tool cannot be compiled without memory-checking interface (valgrind or msan)"
| ^
1 error generated.
> clang src/*.h -ferror-limit=100
src/field_10x26_impl.h:265:21: warning: incompatible pointer types initializing 'const uint32_t *' (aka 'const unsigned int *') with an expression of type 'const uint64_t[5]' (aka 'const unsigned long[5]') [-Wincompatible-pointer-types]
265 | const uint32_t *t = a->n;
| ^ ~~~~
src/field_10x26_impl.h:1007:28: warning: incompatible pointer types passing 'uint64_t[5]' (aka 'unsigned long[5]') to parameter of type 'uint32_t *' (aka 'unsigned int *') [-Wincompatible-pointer-types]
1007 | secp256k1_fe_mul_inner(r->n, a->n, b->n);
| ^~~~
src/field_10x26_impl.h:401:63: note: passing argument to parameter 'r' here
401 | SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) {
| ^
src/field_10x26_impl.h:1007:34: warning: incompatible pointer types passing 'const uint64_t[5]' (aka 'const unsigned long[5]') to parameter of type 'const uint32_t *' (aka 'const unsigned int *') [-Wincompatible-pointer-types]
1007 | secp256k1_fe_mul_inner(r->n, a->n, b->n);
| ^~~~
src/field_10x26_impl.h:401:82: note: passing argument to parameter 'a' here
401 | SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) {
| ^
src/field_10x26_impl.h:1007:40: warning: incompatible pointer types passing 'const uint64_t[5]' (aka 'const unsigned long[5]') to parameter of type 'const uint32_t *' (aka 'const unsigned int *') [-Wincompatible-pointer-types]
1007 | secp256k1_fe_mul_inner(r->n, a->n, b->n);
| ^~~~
src/field_10x26_impl.h:401:121: note: passing argument to parameter 'b' here
401 | SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) {
| ^
src/field_10x26_impl.h:1011:28: warning: incompatible pointer types passing 'uint64_t[5]' (aka 'unsigned long[5]') to parameter of type 'uint32_t *' (aka 'unsigned int *') [-Wincompatible-pointer-types]
1011 | secp256k1_fe_sqr_inner(r->n, a->n);
| ^~~~
src/field_10x26_impl.h:731:63: note: passing argument to parameter 'r' here
731 | SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a) {
| ^
src/field_10x26_impl.h:1011:34: warning: incompatible pointer types passing 'const uint64_t[5]' (aka 'const unsigned long[5]') to parameter of type 'const uint32_t *' (aka 'const unsigned int *') [-Wincompatible-pointer-types]
1011 | secp256k1_fe_sqr_inner(r->n, a->n);
| ^~~~
src/field_10x26_impl.h:731:82: note: passing argument to parameter 'a' here
731 | SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a) {
| ^
6 warnings generated.
src/int128_struct_impl.h:54:6: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
54 | r->hi = hi;
| ~^ ~~
src/int128_struct_impl.h:55:6: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
55 | r->lo = lo;
| ~^ ~~
src/int128_struct_impl.h:59:5: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
59 | r->lo = secp256k1_umul128(a, b, &r->hi);
| ~^ ~~
src/int128_struct_impl.h:59:38: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
59 | r->lo = secp256k1_umul128(a, b, &r->hi);
| ~^ ~~
src/int128_struct_impl.h:65:5: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
65 | r->lo += lo;
| ~^ ~~
src/int128_struct_impl.h:66:5: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
66 | r->hi += hi + (r->lo < lo);
| ~^ ~~
src/int128_struct_impl.h:66:20: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
66 | r->hi += hi + (r->lo < lo);
| ~^ ~~
src/int128_struct_impl.h:70:5: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
70 | r->lo += a;
| ~^ ~~
src/int128_struct_impl.h:71:5: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
71 | r->hi += r->lo < a;
| ~^ ~~
src/int128_struct_impl.h:71:14: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
71 | r->hi += r->lo < a;
| ~^ ~~
src/int128_struct_impl.h:80:7: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
80 | r->lo = r->hi >> (n-64);
| ~^ ~~
src/int128_struct_impl.h:80:15: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
80 | r->lo = r->hi >> (n-64);
| ~^ ~~
src/int128_struct_impl.h:81:7: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
81 | r->hi = 0;
| ~^ ~~
src/int128_struct_impl.h:87:7: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
87 | r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
| ~^ ~~
src/int128_struct_impl.h:87:22: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
87 | r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
| ~^ ~~
src/int128_struct_impl.h:87:42: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
87 | r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
| ~^ ~~
src/int128_struct_impl.h:89:7: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
89 | r->hi >>= n;
| ~^ ~~
src/int128_struct_impl.h:94:12: error: member reference base type 'const secp256k1_uint128' (aka 'const unsigned __int128') is not a structure or union
94 | return a->lo;
| ~^ ~~
src/int128_struct_impl.h:98:12: error: member reference base type 'const secp256k1_uint128' (aka 'const unsigned __int128') is not a structure or union
98 | return a->hi;
| ~^ ~~
src/int128_struct_impl.h:102:5: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
102 | r->hi = 0;
| ~^ ~~
src/int128_struct_impl.h:103:5: error: member reference base type 'secp256k1_uint128' (aka 'unsigned __int128') is not a structure or union
103 | r->lo = a;
| ~^ ~~
src/int128_struct_impl.h:108:22: error: member reference base type 'const secp256k1_uint128' (aka 'const unsigned __int128') is not a structure or union
108 | return n >= 64 ? r->hi >> (n - 64) == 0
| ~^ ~~
src/int128_struct_impl.h:109:22: error: member reference base type 'const secp256k1_uint128' (aka 'const unsigned __int128') is not a structure or union
109 | : r->hi == 0 && r->lo >> n == 0;
| ~^ ~~
src/int128_struct_impl.h:109:36: error: member reference base type 'const secp256k1_uint128' (aka 'const unsigned __int128') is not a structure or union
109 | : r->hi == 0 && r->lo >> n == 0;
| ~^ ~~
src/int128_struct_impl.h:113:6: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
113 | r->hi = hi;
| ~^ ~~
src/int128_struct_impl.h:114:6: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
114 | r->lo = lo;
| ~^ ~~
src/int128_struct_impl.h:119:5: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
119 | r->lo = (uint64_t)secp256k1_mul128(a, b, &hi);
| ~^ ~~
src/int128_struct_impl.h:120:5: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
120 | r->hi = (uint64_t)hi;
| ~^ ~~
src/int128_struct_impl.h:126:5: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
126 | r->lo += lo;
| ~^ ~~
src/int128_struct_impl.h:127:11: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
127 | hi += r->lo < lo;
| ~^ ~~
src/int128_struct_impl.h:139:5: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
139 | r->hi += hi;
| ~^ ~~
src/int128_struct_impl.h:145:11: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
145 | hi += r->lo < lo;
| ~^ ~~
src/int128_struct_impl.h:156:5: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
156 | r->hi -= hi;
| ~^ ~~
src/int128_struct_impl.h:157:5: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
157 | r->lo -= lo;
| ~^ ~~
src/int128_struct_impl.h:171:7: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
171 | r->lo = (uint64_t)((int64_t)(r->hi) >> (n-64));
| ~^ ~~
src/int128_struct_impl.h:171:36: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
171 | r->lo = (uint64_t)((int64_t)(r->hi) >> (n-64));
| ~^ ~~
src/int128_struct_impl.h:172:7: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
172 | r->hi = (uint64_t)((int64_t)(r->hi) >> 63);
| ~^ ~~
src/int128_struct_impl.h:172:36: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
172 | r->hi = (uint64_t)((int64_t)(r->hi) >> 63);
| ~^ ~~
src/int128_struct_impl.h:174:7: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
174 | r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
| ~^ ~~
src/int128_struct_impl.h:174:22: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
174 | r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
| ~^ ~~
src/int128_struct_impl.h:174:42: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
174 | r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
| ~^ ~~
src/int128_struct_impl.h:175:7: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
175 | r->hi = (uint64_t)((int64_t)(r->hi) >> n);
| ~^ ~~
src/int128_struct_impl.h:175:36: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
175 | r->hi = (uint64_t)((int64_t)(r->hi) >> n);
| ~^ ~~
src/int128_struct_impl.h:180:12: error: member reference base type 'const secp256k1_int128' (aka 'const __int128') is not a structure or union
180 | return a->lo;
| ~^ ~~
src/int128_struct_impl.h:190:5: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
190 | r->hi = (uint64_t)(a >> 63);
| ~^ ~~
src/int128_struct_impl.h:191:5: error: member reference base type 'secp256k1_int128' (aka '__int128') is not a structure or union
191 | r->lo = (uint64_t)a;
| ~^ ~~
src/int128_struct_impl.h:195:12: error: member reference base type 'const secp256k1_int128' (aka 'const __int128') is not a structure or union
195 | return a->hi == b->hi && a->lo == b->lo;
| ~^ ~~
src/int128_struct_impl.h:195:21: error: member reference base type 'const secp256k1_int128' (aka 'const __int128') is not a structure or union
195 | return a->hi == b->hi && a->lo == b->lo;
| ~^ ~~
src/int128_struct_impl.h:195:30: error: member reference base type 'const secp256k1_int128' (aka 'const __int128') is not a structure or union
195 | return a->hi == b->hi && a->lo == b->lo;
| ~^ ~~
src/int128_struct_impl.h:195:39: error: member reference base type 'const secp256k1_int128' (aka 'const __int128') is not a structure or union
195 | return a->hi == b->hi && a->lo == b->lo;
| ~^ ~~
src/int128_struct_impl.h:201:23: error: member reference base type 'const secp256k1_int128' (aka 'const __int128') is not a structure or union
201 | return n >= 64 ? r->hi == (uint64_t)sign << (n - 64) && r->lo == 0
| ~^ ~~
src/int128_struct_impl.h:201:62: error: member reference base type 'const secp256k1_int128' (aka 'const __int128') is not a structure or union
201 | return n >= 64 ? r->hi == (uint64_t)sign << (n - 64) && r->lo == 0
| ~^ ~~
src/int128_struct_impl.h:202:23: error: member reference base type 'const secp256k1_int128' (aka 'const __int128') is not a structure or union
202 | : r->hi == (uint64_t)(sign >> 1) && r->lo == (uint64_t)sign << n;
| ~^ ~~
src/int128_struct_impl.h:202:57: error: member reference base type 'const secp256k1_int128' (aka 'const __int128') is not a structure or union
202 | : r->hi == (uint64_t)(sign >> 1) && r->lo == (uint64_t)sign << n;
| ~^ ~~
54 errors generated.
src/scalar_low_impl.h:19:17: error: invalid operands to binary expression ('const secp256k1_scalar' and 'int')
19 | return !(*a & 1);
| ~~ ^ ~
src/scalar_low_impl.h:23:14: error: use of undeclared identifier 'EXHAUSTIVE_TEST_ORDER'
23 | *r = v % EXHAUSTIVE_TEST_ORDER;
| ^
src/scalar_low_impl.h:33:20: error: invalid operands to binary expression ('const secp256k1_scalar' and 'unsigned int')
33 | return (*a >> offset) & (0xFFFFFFFF >> (32 - count));
| ~~ ^ ~~~~~~
src/scalar_low_impl.h:45:103: error: use of undeclared identifier 'EXHAUSTIVE_TEST_ORDER'
45 | SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; }
| ^
src/scalar_low_impl.h:51:14: error: invalid operands to binary expression ('const secp256k1_scalar' and 'const secp256k1_scalar')
51 | *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER;
| ~~ ^ ~~
src/scalar_low_impl.h:51:22: error: use of undeclared identifier 'EXHAUSTIVE_TEST_ORDER'
51 | *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER;
| ^
src/scalar_low_impl.h:54:15: error: invalid operands to binary expression ('secp256k1_scalar' and 'const secp256k1_scalar')
54 | return *r < *b;
| ~~ ^ ~~
src/scalar_low_impl.h:61:12: error: invalid operands to binary expression ('secp256k1_scalar' and 'uint32_t' (aka 'unsigned int'))
61 | *r += ((uint32_t)1 << bit);
| ~~ ^ ~~~~~~~~~~~~~~~~~~~~
src/scalar_low_impl.h:72:8: error: assigning to 'secp256k1_scalar' from incompatible type 'int'
72 | *r = 0;
| ^ ~
src/scalar_low_impl.h:74:18: error: invalid operands to binary expression ('secp256k1_scalar' and 'int')
74 | *r = (*r * 0x100) + b32[i];
| ~~ ^ ~~~~~
src/scalar_low_impl.h:75:19: error: use of undeclared identifier 'EXHAUSTIVE_TEST_ORDER'
75 | if (*r >= EXHAUSTIVE_TEST_ORDER) {
| ^
src/scalar_low_impl.h:77:19: error: use of undeclared identifier 'EXHAUSTIVE_TEST_ORDER'
77 | *r %= EXHAUSTIVE_TEST_ORDER;
| ^
src/scalar_low_impl.h:89:18: error: invalid operands to binary expression ('const secp256k1_scalar' and 'int')
89 | bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a;
| ~~ ^ ~~
src/scalar_low_impl.h:89:38: error: invalid operands to binary expression ('const secp256k1_scalar' and 'int')
89 | bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a;
| ~~ ^ ~~
src/scalar_low_impl.h:89:58: error: invalid operands to binary expression ('const secp256k1_scalar' and 'int')
89 | bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a;
| ~~ ^ ~
src/scalar_low_impl.h:89:72: error: assigning to 'unsigned char' from incompatible type 'const secp256k1_scalar'
89 | bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a;
| ^ ~~
src/scalar_low_impl.h:95:15: error: invalid operands to binary expression ('const secp256k1_scalar' and 'int')
95 | return *a == 0;
| ~~ ^ ~
src/scalar_low_impl.h:101:12: error: invalid operands to binary expression ('const secp256k1_scalar' and 'int')
101 | if (*a == 0) {
| ~~ ^ ~
src/scalar_low_impl.h:102:12: error: assigning to 'secp256k1_scalar' from incompatible type 'int'
102 | *r = 0;
| ^ ~
src/scalar_low_impl.h:104:14: error: use of undeclared identifier 'EXHAUSTIVE_TEST_ORDER'
104 | *r = EXHAUSTIVE_TEST_ORDER - *a;
| ^
src/scalar_low_impl.h:113:15: error: invalid operands to binary expression ('const secp256k1_scalar' and 'int')
113 | return *a == 1;
| ~~ ^ ~
src/scalar_low_impl.h:119:17: error: use of undeclared identifier 'EXHAUSTIVE_TEST_ORDER'
119 | return *a > EXHAUSTIVE_TEST_ORDER / 2;
| ^
src/scalar_low_impl.h:135:14: error: invalid operands to binary expression ('const secp256k1_scalar' and 'const secp256k1_scalar')
135 | *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER;
| ~~ ^ ~~
src/scalar_low_impl.h:135:22: error: use of undeclared identifier 'EXHAUSTIVE_TEST_ORDER'
135 | *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER;
| ^
src/scalar_low_impl.h:144:9: error: assigning to 'secp256k1_scalar' from incompatible type 'int'
144 | *r2 = 0;
| ^ ~
src/scalar_low_impl.h:154:15: error: invalid operands to binary expression ('const secp256k1_scalar' and 'const secp256k1_scalar')
154 | return *a == *b;
| ~~ ^ ~~
src/scalar_low_impl.h:165:14: error: invalid operands to binary expression ('secp256k1_scalar' and 'uint32_t' (aka 'unsigned int'))
165 | *r = (*r & mask0) | (*a & mask1);
| ~~ ^ ~~~~~
src/scalar_low_impl.h:165:29: error: invalid operands to binary expression ('const secp256k1_scalar' and 'uint32_t' (aka 'unsigned int'))
165 | *r = (*r & mask0) | (*a & mask1);
| ~~ ^ ~~~~~
src/scalar_low_impl.h:175:21: error: use of undeclared identifier 'EXHAUSTIVE_TEST_ORDER'
175 | for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) {
| ^
src/scalar_low_impl.h:176:16: error: invalid operands to binary expression ('int' and 'const secp256k1_scalar')
176 | if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) {
| ~ ^ ~~
src/scalar_low_impl.h:176:24: error: use of undeclared identifier 'EXHAUSTIVE_TEST_ORDER'
176 | if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) {
| ^
src/scalar_low_impl.h:185:8: error: assigning to 'secp256k1_scalar' from incompatible type 'uint32_t' (aka 'unsigned int')
185 | *r = res;
| ^ ~~~
src/scalar_low_impl.h:201:33: error: invalid operands to binary expression ('const secp256k1_scalar' and 'int')
201 | *r = (*a + ((-(uint32_t)(*a & 1)) & EXHAUSTIVE_TEST_ORDER)) >> 1;
| ~~ ^ ~
src/scalar_low_impl.h:201:41: error: use of undeclared identifier 'EXHAUSTIVE_TEST_ORDER'
201 | *r = (*a + ((-(uint32_t)(*a & 1)) & EXHAUSTIVE_TEST_ORDER)) >> 1;
| ^
34 errors generated.
</details>
Perhaps some of these cases can be improved further, but these improvements should go to a separate PR.
What is the motivation for these changes?
Self-contained files work much better with tooling. For example, the [clangd](https://clangd.llvm.org/installation) language server works great in my editor after this PR (ignoring the four files mentioned above) and gives me much better completion, symbol lookup, etc. In fact, what made me create this PR is that I got annoyed by not being able to jump to symbols when trying to review silent payments.
Here's my ~/.config/clangd/config.yaml if you're interested:
# libsecp256k1
If:
PathMatch: .*/secp256k1/.*
CompileFlags:
# clangd compiles even _impl.h files individually, so it won't
# find definitions of static functions in other files.
Add: [-Wno-undefined-internal]
Diagnostics:
# Disable hints about unused and missing includes. The assumptions that clangd
# make about inclusion style are too far off from what libsecp256k1 does.
UnusedIncludes: None
MissingIncludes: None
You'll also need to run make clean and bear -- make once to create a compile_commands.json file in the repo root that contains the compiler flags so that clangd knows the configured -D flags etc. Get bear first.
edit: CMake can also generate the json file:
$ mkdir build
$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -B build
$ cmake --build build
Then the file will be stored in the build subdirectory, whose name is special-cased in clangd so that it the file will be found automatically.
Or the flags can be added above in CompileFlags manually.