This is supposed to resolve #1095 and help with restricted settings such as embedded systems or WASM.
The approach is to detect the availability of <stdio.h>
and <stdio.h>
, both when building the library or building against the API. The effects depend on the case:
When building the library:
- If
<stdio.h>
is not available, disablefprintf(stderr, ...)
in callbacks and emit a note during compilation (#pragma message
) - If
<stdlib.h>
is not available and external default callbacks are not used, then we don’t haveabort
. Raise an error in compilation and tell the user to use external callbacks - If
<stdlib.h>
is not available, we don’t havemalloc
(andfree
). Disable all API functions that need it.
When building against our API:
- If
<stdlib.h>
is not available, make an educated guess that it wasn’t available when the library was built, and tell the user that certain API functions are not available.
We use different methods of detecting the presence of the headers, see the code. The user can always override our detection mechanism as a last resort.
The other kind of standard library functionality we use is memset
and memcpy
from <string.h>
(but not memcmp
because it’s a policy to use `secp256k1_memcmp_var). There’s not much we can do for these two, unless we want to provide our own implementations, but in practice these functions are pretty common. C23 has adopted a proposal to make these mandatory even for freestanding implementations (i.e., embedded systems in standard-speak).
A good way to test this is to change the filename in _has_include
to simulate the case when headers are unavailable.
I went through a lot of back and forth when working on this. Here are some alternatives and why I didn’t choose them for now:
- Detecting
<stdlib.h>
for bothabort
andmalloc
and is rather crude. I’m sure there are embedded platforms out there which havemalloc
and noabort
, or the other way around. However, dealing with this will probably need more machinery (e.g., special non-standard headers), and compilers don’t have automatic mechanism to detect the availability of functions. Moreover, I don’t want to overshoot in the dark with my limited experience in embedded system and given the fact that noone has complained so far. After this PR, if you have a nonstandard<stdlib.h>
withmalloc
but withoutabort
, you can get away with providing external callbacks. If you have a nonstandard<stdlib.h>
withabort
but withoutmalloc
, you can get away with overriding the detection of<stdlib.h>
to “no” while at the same time providing external callbacks (that may still callabort
then.) For a different, much more flexible approach, see for example Mbed TLS, which has a focus on embedded system. - I’m not entirely convinced that it’s a good idea to warn the user when building against our API. We could be wrong and headers were available when building the library and just not now. But in that case, the user can still override, so I think it’s better to loud here.
- I’m also not sure that it’s a good idea to let the compiler issue a “note” message when we disable features when compiling the library, also taking into account that it’s apparently difficult to disable this kind of messages in GCC. But again, I felt it’s a bit better to be loud here.
@tcharding This is supposed to improve the situation for rust-secp256k1 wasm significantly. Perhaps except for the aforementioned string.h, but if you’re using wasi, then I think you should just use the wabi sysroot and not your own sysroot then. Searching the web also tells me that clang may need some compiler option. I don’t know, I haven’t tried this.