* Format enums annotated with fmt::as_identifiers (requires C++26 reflection)
Format an enum as the identifier of the matching enumerator if the enum is
annotated with fmt::as_identifiers:
enum class [[=fmt::as_identifiers]] color { red, green, blue };
fmt::format("{}", color::green); // "green"
Values that don't match any enumerator are represented as their underlying
value in decimal before applying string formatting.
Identifiers are retrieved via C++26 reflection (P2996) and the annotation
via P3394. FMT_USE_REFLECTION is autodetected and can be overridden by the
user; without reflection the header is empty.
The header is also part of the fmt module, but, unlike with headers, whether
it provides anything is decided when the module is compiled, so the module
build detects reflection and enables it if the configured standard allows.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Look up enum identifiers by index when the values are dense
The formatter for enums annotated with fmt::as_identifiers did a linear
search over all enumerators. Build a table indexed by the distance from
the smallest enumerator value instead, with empty string views in the
holes, which reduces the lookup to a bounds check and one load.
The table is only used if at least 70% of its elements are identifiers,
limiting its size to 10/7 of the number of enumerators. Sparser enums
keep using the linear search. Distances are computed in uint64_t so that
enums with negative values and values spanning the whole range of the
underlying type are handled without overflow.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Suppress -Wsfinae-incomplete in format-test on GCC 16
GCC 16 warns when a type is completed after it failed to be complete in a
SFINAE context. format-test does this deliberately to check that formatting
of incomplete types works, so the warning is a false positive there and
breaks the build with -Werror.
* Test GCC 16 on CI
GCC 16 is the first compiler with C++26 reflection support, which is needed
by fmt/enum.h, so add a job that builds with it in C++26 mode. It comes from
the ubuntu-toolchain-r/test PPA since Ubuntu 24.04 only ships GCC 14.
Also report when reflection is not detected to make it visible that
enum-test was skipped.
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rename INSTALL_TARGETS to FMT_TARGETS since the list is now used for both
installation and the build-tree export, and move INSTALL_FILE_SET into the
FMT_INSTALL block as only install(TARGETS) uses it.
Replace the export-test static library and export-lib.cc with an INTERFACE
library, which reproduces the same CMake export dependency check (#4806).
export() was scoped inside if (FMT_INSTALL), so projects that pull in
fmt via add_subdirectory()/FetchContent without installing it had no
way to get the exported fmt::* targets. If such a project tries to
export its own targets that depend on fmt, CMake fails with "target
... requires target fmt that is not in any export set".
Hoist the target list/export name and the export() call itself out of
the FMT_INSTALL guard so the build-tree export file is always
generated; the install()-only pieces (config/version files, pkgconfig,
install(EXPORT ...)) stay behind the guard and installed behavior is
unchanged.
Fixes#4806
Co-authored-by: flink <w741069229@gmail.com>
The .gitignore-derived `build/` pattern does not actually prune the build
directory or its contents from the CPack source package, so an empty build/
(and, once docs were built in CI, build/doc-html) leaked into the zip. Ignore
the whole build tree in CPACK_SOURCE_IGNORE_FILES.
- We need to confirm compiler support for module scanning before
creating the CXX_MODULE FILE_SET using the `target_sources` command
- This is especially relevant for compilers that have module support but
do not support the module scanning such as g++13, clang15. For these
we can use the older way of creating the fmt-module target
Co-authored-by: Mathew Benson <mathew@benson.co.ke>
* Add Separate CMake Target for C++20 Modules
In the same vein as there is the `fmt::fmt-header-only`, `fmt::fmt` and
`fmt::fmt_c` targets, I propose the addition of a new target
`fmt::fmt-module` which will be for the compilation of the FMT_MODULE
library option.
The new target will have the properties requried for Compiling,
Installing and using the C++20 functionality in CMake
The `add_module_library` function is marked as deprecated as its
functionality is superseded.
Updated the logic for setting the FMT_USE_CMAKE_MODULE flag to check the
versions for Ninja and MSVC according the CMAKE Documents and setting
the FMT_MODULE flag based on this
* Add Separate CMake Target for C++20 Modules
In the same vein as there is the `fmt::fmt-header-only`, `fmt::fmt` and
`fmt::fmt_c` targets, I propose the addition of a new target
`fmt::fmt-module` which will be for the compilation of the FMT_MODULE
library option.
The new target will have the properties requried for Compiling,
Installing and using the C++20 functionality in CMake
Updated the logic for setting the FMT_USE_CMAKE_MODULE flag to check the
versions for Ninja and MSVC according the CMAKE Documents and setting
the FMT_MODULE flag based on this
Fixed the test/CMakeLists.txt file which used the FMT_MODULE flag to
separate the module and non-module library testing, in particular
disableing the module version.
The module testing still needs to be fixed, but the expected behavior of
testing the non-modular version is working.
---------
Co-authored-by: Mathew Benson <mathew@benson.co.ke>
Co-authored-by: ClausKlein <claus.klein@arcormail.de>
SOURCE vs CURRENT_SOURCE is unreliable. `DEFINED PROJECT_NAME` is a much more portable way of determination.
Also, installation shouldn't default to on if it is a subproject.
Suppresses error:
CMake Error (dev) at build/coverage/_deps/fmt-src/CMakeLists.txt:208 (set):
uninitialized variable 'CMAKE_MODULE_PATH'
This error is for project developers. Use -Wno-error=dev to suppress it.
Define two components, core and doc, which can be installed separately.
This facilitates packagers who want to package docs in a separate
package.
After this change it's possible to install only core files with:
cmake --install build --component core
And only install documentation with:
cmake --install build --component doc
When no component is specified, the behaviour is unchanged, i.e. if
documentation was built, it will be installed.