microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
compat.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 Jarosław Pelczar <jarek@jpelczar.com>
2//
3// SPDX-License-Identifier: BSD-2-Clause
4
5#pragma once
6
16#include "../microfmt_config.hpp"
17
18#include <reloco/detail/compat.hpp>
19
20#if RELOCO_CXX20 && RELOCO_HAS_INCLUDE(<source_location>)
21#include <source_location>
22#endif
23
24#if RELOCO_CXX20 && defined(__cpp_lib_source_location) && (__cpp_lib_source_location >= 201907L)
25#define MICROFMT_HAS_STD_SOURCE_LOCATION 1
26#else
27#define MICROFMT_HAS_STD_SOURCE_LOCATION 0
28#endif
29
30#if RELOCO_CXX23 && RELOCO_HAS_INCLUDE(<expected>)
31#include <expected>
32#endif
33
34#if RELOCO_CXX23 && defined(__cpp_lib_expected) && (__cpp_lib_expected >= 202202L)
35#define MICROFMT_HAS_STD_EXPECTED 1
36#else
37#define MICROFMT_HAS_STD_EXPECTED 0
38#endif
39
40#if defined(MICROFMT_ENABLE_BOOST_SOURCE_LOCATION)
41// clang-format off
42#if RELOCO_HAS_INCLUDE(<boost/assert/source_location.hpp>)
43#include <boost/assert/source_location.hpp>
44// clang-format on
45#define MICROFMT_HAS_BOOST_SOURCE_LOCATION 1
46#else
47#error "MICROFMT_ENABLE_BOOST_SOURCE_LOCATION requires <boost/assert/source_location.hpp>"
48#endif
49#else
50#define MICROFMT_HAS_BOOST_SOURCE_LOCATION 0
51#endif
52
53#if MICROFMT_HAS_STD_SOURCE_LOCATION || MICROFMT_HAS_BOOST_SOURCE_LOCATION
54#define MICROFMT_HAS_SOURCE_LOCATION 1
55#else
56#define MICROFMT_HAS_SOURCE_LOCATION 0
57#endif
58
59#if defined(MICROFMT_ENABLE_BOOST_UUID) || defined(BOOST_UUID_UUID_HPP) || defined(BOOST_UUID_HPP)
60#if !defined(BOOST_UUID_UUID_HPP) && !defined(BOOST_UUID_HPP)
61// clang-format off
62#if RELOCO_HAS_INCLUDE(<boost/uuid/uuid.hpp>)
63#include <boost/uuid/uuid.hpp>
64// clang-format on
65#else
66#error "MICROFMT_ENABLE_BOOST_UUID requires <boost/uuid/uuid.hpp>"
67#endif
68#endif
69#define MICROFMT_HAS_BOOST_UUID 1
70#else
71#define MICROFMT_HAS_BOOST_UUID 0
72#endif
73
74#if defined(__unix__) || defined(__APPLE__) || defined(__posix)
75#define MICROFMT_HAS_POSIX_FD 1
76#else
77#define MICROFMT_HAS_POSIX_FD 0
78#endif
79
80#if defined(__ANDROID__)
81#define MICROFMT_HAS_ANDROID_LOG 1
82#else
83#define MICROFMT_HAS_ANDROID_LOG 0
84#endif
85
86// ============================================================================
87// Shared-library build/consume support (MICROFMT_SHARED)
88// ============================================================================
89//
90// microfmt is header-only by default: even the "heavy", non-templated
91// definitions factored out into a `*.ipp` file (see e.g. `microfmt.ipp`,
92// included from `microfmt.hpp`) are plain `inline` and live directly in the
93// header, so -- like every other microfmt entity -- each independently
94// compiled translation unit gets its own copy of them, and the linker only
95// merges duplicate copies within a single link step, never across separate
96// shared-object boundaries. For an application built as one executable
97// plus several plugin `.so`'s that each `#include` microfmt, this means
98// every plugin pays for its own copy of the same handful of routines (see
99// `tools/codesize/testbed/README.md` for measured numbers).
100//
101// Define MICROFMT_SHARED (to any value, before including any microfmt
102// header, e.g. via `detail/porting/microfmt_user_config.hpp` or a
103// compiler `-D` flag applied consistently to every translation unit in the
104// program) to switch every `*.ipp`-hosted definition to a plain
105// declaration instead: ordinary consumers then link against one shared
106// definition rather than each instantiating their own copy.
107//
108// Exactly one translation unit in the whole program -- the one building
109// the actual shared library that is meant to host these definitions --
110// must additionally define MICROFMT_SHARED_BUILD (to any value) before
111// including any microfmt header. That TU alone re-imports the `*.ipp`
112// bodies as exported, out-of-line definitions; every other TU (which
113// defines MICROFMT_SHARED but not MICROFMT_SHARED_BUILD) only sees
114// declarations and must be linked against that library.
115//
116// `MICROFMT_API` decorates every entity affected by this split:
117// - MICROFMT_SHARED not defined (default):
118// `MICROFMT_API` -> `inline`; current, unchanged header-only behavior.
119// - MICROFMT_SHARED defined, MICROFMT_SHARED_BUILD not defined (consume):
120// `MICROFMT_API` -> plain declaration, no body
121// (+ `__declspec(dllimport)` on MSVC).
122// - MICROFMT_SHARED and MICROFMT_SHARED_BUILD both defined (build):
123// `MICROFMT_API` -> exported, out-of-line definition
124// (`__declspec(dllexport)` on MSVC, default visibility elsewhere).
125//
126// `MICROFMT_SHARED_PROVIDE_DEFINITIONS` is 1 exactly when the current TU
127// should pull in `*.ipp` bodies at all (default header-only mode, or the
128// MICROFMT_SHARED_BUILD library-build TU) and 0 when it should only see
129// declarations (ordinary MICROFMT_SHARED consumer).
130//
131// This is opt-in and off by default: a plain header-only build (the
132// overwhelming common case, and every existing consumer) is entirely
133// unaffected.
134#if !defined(MICROFMT_SHARED)
135#define MICROFMT_API inline
136#define MICROFMT_SHARED_PROVIDE_DEFINITIONS 1
137#elif defined(MICROFMT_SHARED_BUILD)
138#if defined(_MSC_VER)
139#define MICROFMT_API __declspec(dllexport)
140#elif RELOCO_HAS_ATTRIBUTE(visibility)
141#define MICROFMT_API __attribute__((visibility("default")))
142#else
143#define MICROFMT_API
144#endif
145#define MICROFMT_SHARED_PROVIDE_DEFINITIONS 1
146#else
147#if defined(_MSC_VER)
148#define MICROFMT_API __declspec(dllimport)
149#else
150#define MICROFMT_API
151#endif
152#define MICROFMT_SHARED_PROVIDE_DEFINITIONS 0
153#endif
154
155// MICROFMT_API_CONSTEXPR is MICROFMT_API for an entity that is `constexpr`
156// in the default header-only build (where MICROFMT_API is plain `inline`,
157// so adding `constexpr` costs nothing and preserves compile-time
158// callability exactly as before) but must drop `constexpr` under
159// MICROFMT_SHARED: a `constexpr` function is implicitly `inline`, which
160// would force every MICROFMT_SHARED_BUILD-declared-only consumer to still
161// carry a definition, defeating the whole build/consume split.
162#if !defined(MICROFMT_SHARED)
163#define MICROFMT_API_CONSTEXPR constexpr MICROFMT_API
164#else
165#define MICROFMT_API_CONSTEXPR MICROFMT_API
166#endif
167
168// MICROFMT_API_CLASS decorates a whole class/struct (as opposed to
169// MICROFMT_API, which decorates individual members/free functions) so its
170// vtable and any members implicitly emitted per-TU (typeinfo, defaulted
171// special members, ...) are deduplicated across a MICROFMT_SHARED_BUILD
172// library's shared-object boundary, exactly like MICROFMT_API does for
173// out-of-line function definitions.
174//
175// A plain `class`/`struct` head cannot be decorated `inline` (unlike a
176// function or variable), so MICROFMT_API_CLASS -- unlike MICROFMT_API --
177// expands to nothing in the default header-only build: there is no
178// separate shared object to deduplicate against, and every member stays
179// implicitly inline the same way it already does today.
180#if !defined(MICROFMT_SHARED)
181#define MICROFMT_API_CLASS
182#elif defined(MICROFMT_SHARED_BUILD)
183#if defined(_MSC_VER)
184#define MICROFMT_API_CLASS __declspec(dllexport)
185#elif RELOCO_HAS_ATTRIBUTE(visibility)
186#define MICROFMT_API_CLASS __attribute__((visibility("default")))
187#else
188#define MICROFMT_API_CLASS
189#endif
190#else
191#if defined(_MSC_VER)
192#define MICROFMT_API_CLASS __declspec(dllimport)
193#else
194#define MICROFMT_API_CLASS
195#endif
196#endif
197
198// dlog availability cannot be reliably inferred from a compiler-predefined
199// macro (unlike MICROFMT_HAS_ANDROID_LOG's __ANDROID__ check); headers
200// assume the real Tizen SDK is available unless the includer opts out via
201// MICROFMT_COMPILE_WITHOUT_TIZEN_DLOG (see CMakeLists.txt).
202#if defined(MICROFMT_COMPILE_WITHOUT_TIZEN_DLOG)
203#define MICROFMT_HAS_DLOG 0
204#else
205#define MICROFMT_HAS_DLOG 1
206#endif