Conversation
Just a dry-run at a possible implementation pending clarification on details. Fixes fmtlib#4646
|
@vitaut, If it helps, here is a (Click to expand `Dockerfile` source)# syntax=docker/dockerfile:1
FROM ubuntu:noble
# Lastest release of official "Arm Toolchain for Embedded"
ADD --unpack=true https://github.com/arm/arm-toolchain/releases/download/release-22.1.0-ATfE/ATfE-22.1.0-Linux-x86_64.tar.xz /usr/local
ENV TOOLCHAIN_DIR="/usr/local/ATfE-22.1.0-Linux-x86_64"
ENV TOOLCHAIN_BIN_DIR="${TOOLCHAIN_DIR}/bin"
ENV PATH="${TOOLCHAIN_BIN_DIR}:$PATH"
ENV SRC_DIR=/src
RUN mkdir -p "${SRC_DIR}"
ADD --chmod=0755 <<EOF "${SRC_DIR}/build-and-run.sh"
#!/bin/bash
set -euo pipefail
CFLAGS=(
--std=c23
--target=armv7-unknown-none-eabi -mfpu=none # generic defaults so the compiler can pick a set of runtime libraries
--config=\${TOOLCHAIN_BIN_DIR}/llvmlibc.cfg -Wl,-Tllvmlibc.ld # use llvm libc\'s runtime libraries and linker script
-static # no dynamic linking available because no dynamic linker present (nor fs to load shared libs from) on bare-metal
-nostartfiles # by default, the llvm linker looks for (the non-existent) crt0.o; we need to specify our own because the real file is named like libcrt0.a
-lcrt0-semihost -lsemihost # choose the libcrt0.a for semihosting, which provides support for stdin/out
)
set -x
cd "\${SRC_DIR}"
! test -f "test" || rm -f test
"${TOOLCHAIN_BIN_DIR}/clang" "\${CFLAGS[@]}" -o test test.c
exec ./test
EOF
ADD <<EOF "${SRC_DIR}/test.c"
#include <stdio.h>
#if __has_include(<newlib.h>)
# include <newlib.h> // include __NEWLIB__ macro, if it exists
#endif
#if __NEWLIB__
# warning "using newlib"
#endif
#if __LLVM_LIBC__
# warning "using llvm libc"
#endif
int main() {
flockfile(stdout);
funlockfile(stdout);
printf("Test complete!\n");
return 0;
}
EOF
WORKDIR "${SRC_DIR}"
CMD ["./build-and-run.sh"]To use, write the contents above to a file named docker build -t mvastola/fmt-test-flockfile-poc-llvm-libc . && docker run --rm mvastola/fmt-test-flockfile-poc-llvm-libcExpected output is: |
|
So, I think I was able to come up with the beginnings of a headers-only way to do this, if you feel strongly about approaching it that way. Let me know if you prefer this approach. While this wouldn't be my preference, I wanted to put it out there as an alternative approach if you're not comfortable with the one in this PR. (If that's not an issue, no need to bother with this as it's a more complex and slightly more fraught solution.) Basically this alternate approach turns There are some downsides/implications, that I'll list here for your consideration:
|
@vitaut,
Wanted to continue the discussion from #4646 since that's a closed issue..
@vitaut thanks for your understanding on this. I truly appreciate what you're saying, and it makes sense, but from what I've seen (and from the logistics I anticipate would be involved in not doing so), separating the declarations and implementations of low-level standard library functions in such a way that the former can't depend on the latter is SOP for bare-metal targets. (If you have any resources that suggest otherwise, I'm very open.)
A few clarifications:
How strongly wedded are you to using the presence of newlib specifically as the deciding factor in setting
FMT_USE_FLOCKFILE?IMHO, the ideal solution would be to do something along the lines of what I've done in this PR, which directly tests if
flockfilecan be linked, especially if you're now okay making a small addition to the CMake script. This involves as little fuss as possible and is 100% accurate, baring a mismatch in compile options between the compilation of this library and the software it is included in.I'm realizing, however, that while your stated condition was that it be "easy to detect" and this implementation is certainly simple, it's possible you wanted me to just do this via a macro. I wanted to double check since you expressed reticence about doing this in CMake previously.
Unfortunately, if we restrict ourselves to macros and/or detecting newlib, the accuracy of testing if
flockfileworks/links drops significantly:It seems there is an official macro to test the presence of newlib (aptly named
__NEWLIB__), but as I mentioned previously, the use of newlib isn't dispositive offlockfilebeing unimplemented. Newlib is just onelibcimplementation popular with bare-metal targets (others includepicolibcandLLVM libc). Further, some bare-metal platforms do, in fact, support filesystems (and, thus,flockfile).If you're not convinced about using CMake to do the check, I'd be happy to address any concerns you have and figure out how to obviate them.
For sake of completeness, I've also included several macro-only solutions I've investigated here, with my assessment of each. As mentioned, they unfortunately all have (often major) downsides.
#if __STDC_HOSTED__ == 0.Downside: This depends on the user or platform toolchain passing
-ffreestandingto the compiler, which isn't always done.#if !defined(_WIN32) && !defined(__linux__) && !defined(__APPLE__) && !defined(__unix__) ...Downside: this is brittle and would requires an exhaustive list of OSes with filesystems. Additionally, there are quite a few RTOS OSes where filesystem support is an optional feature.
#if (defined(__ELF__) && !defined(__linux__) && !defined(__unix__)) || defined(__ARM_EABI__)Downside: While this would likely be more accurate than the previous two at identifying bare-metal targets, it still can't tell if its being used on a bare-metal target with a filesystem, and is likely to miss many bare-metal targets anyway.
#include <dirent.h>works. While newlib doesn't have any macros to indicate filesystem support, one thing it does have is a defaultsys/dirent.hcontaining#errordirective. If<dirent.h>is included andsys/dirent.his not masked by a file of the same name in the platform's headers containing a real implementation, a compile-time error occurs.Downside: this only works on newlib, plus there's no way to use this indicator without using CMake to assist, because the compiler will only know if it has an
#errordirective by#includeing it, at which point you've broken compilation.