feat: 💥 API-related Conan, CMake, and preprocessor options redesigned

This commit is contained in:
Mateusz Pusz
2024-04-16 21:48:36 +01:00
parent 7b57ce5ab1
commit 8e0a26b933
26 changed files with 490 additions and 207 deletions

View File

@ -221,13 +221,13 @@ jobs:
sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.cppstd=.*/compiler.cppstd=${{ matrix.std }}/' ~/.conan2/profiles/default
sed -i.backup '/^\[settings\]$/,/^\[/ s/^build_type=.*/build_type=${{ matrix.build_type }}/' ~/.conan2/profiles/default
conan profile show -pr default
- run: echo "use_fmtlib=$([ "${{ matrix.formatting }}" == "fmtlib" ] && echo "True" || echo "False")" >> $GITHUB_ENV
- run: echo "std_format=$([ "${{ matrix.formatting }}" == "std::format" ] && echo "True" || echo "False")" >> $GITHUB_ENV
- name: Create Conan package
shell: bash
run: |
conan create . --user mpusz --channel ${CHANNEL} --lockfile-out=package.lock \
-b mp-units/* -b missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" \
-c user.mp-units.build:all=True -o cxx_modules=${{ matrix.config.cxx_modules }} -o use_fmtlib=${{ env.use_fmtlib }} ${{ matrix.config.conan-config }}
-c user.mp-units.build:all=True -o cxx_modules=${{ matrix.config.cxx_modules }} -o std_format=${{ env.std_format }} ${{ matrix.config.conan-config }}
- name: Obtain package reference
id: get-package-ref
shell: bash

View File

@ -215,12 +215,12 @@ jobs:
sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.cppstd=.*/compiler.cppstd=${{ matrix.std }}/' ~/.conan2/profiles/default
sed -i.backup '/^\[settings\]$/,/^\[/ s/^build_type=.*/build_type=${{ matrix.build_type }}/' ~/.conan2/profiles/default
conan profile show -pr default
- run: echo "use_fmtlib=$([ "${{ matrix.formatting }}" == "fmtlib" ] && echo "True" || echo "False")" >> $GITHUB_ENV
- run: echo "std_format=$([ "${{ matrix.formatting }}" == "std::format" ] && echo "True" || echo "False")" >> $GITHUB_ENV
- name: Install Conan dependencies
shell: bash
run: |
conan install . -b missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -c user.mp-units.build:all=False \
-o cxx_modules=${{ matrix.config.cxx_modules }} -o use_fmtlib=${{ env.use_fmtlib }}
-o cxx_modules=${{ matrix.config.cxx_modules }} -o std_format=${{ env.std_format }}
mv CMakeUserPresets.json src
- name: Configure mp-units CMake
if: matrix.config.compiler.type == 'VISUAL' || matrix.config.compiler.type == 'MSVC'

View File

@ -105,7 +105,7 @@ jobs:
conan profile detect --force
conan remote add artifactory https://mpusz.jfrog.io/artifactory/api/conan/conan-oss
mkdir _lgtm_build_dir && cd _lgtm_build_dir
conan build .. -s compiler.cppstd=20 -c user.mp-units.build:all=True -o use_fmtlib=True -b missing
conan build .. -s compiler.cppstd=20 -c user.mp-units.build:all=True -o std_format=False -b missing
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

View File

@ -70,17 +70,17 @@ tasks:
gp sync-await python-init
conan profile detect
conan config install $PWD/.gitpod/conan
conan install . -pr gcc12 -o use_fmtlib=True -b missing
conan install . -pr gcc12 -o use_fmtlib=True -b missing -s build_type=Debug
conan install . -pr gcc12 -o std_format=False -b missing
conan install . -pr gcc12 -o std_format=False -b missing -s build_type=Debug
gp sync-done conan-gcc12-20
conan install . -pr gcc13 -b missing
conan install . -pr gcc13 -b missing -s build_type=Debug
conan install . -pr gcc13 -o std_format=True -b missing
conan install . -pr gcc13 -o std_format=True -b missing -s build_type=Debug
gp sync-done conan-gcc13-20
conan install . -pr clang16 -o use_fmtlib=True -b missing
conan install . -pr clang16 -o use_fmtlib=True -b missing -s build_type=Debug
conan install . -pr clang16 -o std_format=False -b missing
conan install . -pr clang16 -o std_format=False -b missing -s build_type=Debug
gp sync-done conan-clang16-20
conan install . -pr clang17 -o cxx_modules=True -b missing
conan install . -pr clang17 -o cxx_modules=True -b missing -s build_type=Debug
conan install . -pr clang17 -o std_format=True -o cxx_modules=True -b missing
conan install . -pr clang17 -o std_format=True -o cxx_modules=True -b missing -s build_type=Debug
gp sync-done conan-clang17-20
conan remote login -p $ARTIFACTORY_TOKEN conan-gitpod-mp-units $ARTIFACTORY_USER
conan upload "*" -r conan-gitpod-mp-units -c
@ -88,29 +88,29 @@ tasks:
init: |
gp sync-await conan-gcc12-20
source ${PYTHON_VENV}/bin/activate
conan build . -pr gcc12 -o use_fmtlib=True
conan build . -pr gcc12 -o use_fmtlib=True -s build_type=Debug
conan build . -pr gcc12 -o std_format=False
conan build . -pr gcc12 -o std_format=False -s build_type=Debug
echo "🛠️ gcc-12 pre-build done for C++20, header files, and libfmt! You can close this terminal and use 'Build' button in the VSCode status bar for incremental builds. 🛠️"
- name: gcc-13-20
init: |
gp sync-await conan-gcc13-20
source ${PYTHON_VENV}/bin/activate
conan build . -pr gcc13
conan build . -pr gcc13 -s build_type=Debug
conan build . -pr gcc13 -o std_format=True
conan build . -pr gcc13 -o std_format=True -s build_type=Debug
echo "🛠️ gcc-13 pre-build done for C++20 and header files! You can close this terminal and use 'Build' button in the VSCode status bar for incremental builds. 🛠️"
- name: clang-16-20
init: |
gp sync-await conan-clang16-20
source ${PYTHON_VENV}/bin/activate
conan build . -pr clang16 -o use_fmtlib=True
conan build . -pr clang16 -o use_fmtlib=True -s build_type=Debug
conan build . -pr clang16 -o std_format=False
conan build . -pr clang16 -o std_format=False -s build_type=Debug
echo "🛠️ clang-16 pre-build done for C++20, header files, and libfmt! You can close this terminal and use 'Build' button in the VSCode status bar for incremental builds. 🛠️"
- name: clang-17-20
init: |
gp sync-await conan-clang17-20
source ${PYTHON_VENV}/bin/activate
conan build . -pr clang17 -o cxx_modules=True
conan build . -pr clang17 -o cxx_modules=True -s build_type=Debug
conan build . -pr clang17 -o std_format=True -o cxx_modules=True
conan build . -pr clang17 -o std_format=True -o cxx_modules=True -s build_type=Debug
echo "🛠️ clang-17 pre-build done for C++20! You can close this terminal and use 'Build' button in the VSCode status bar for incremental builds. 🛠️"
- name: documentation
init: |

View File

@ -77,7 +77,7 @@ Before submission, please remember to check if the code compiles fine on the sup
The CI will check it anyway but it is good to check at least some of the configurations before pushing changes.
Especially older compilers can be tricky as those do not support all the C++20 features well enough. The official
list of supported compilers can be always found in the
[Installation And Usage](https://mpusz.github.io/mp-units/latest/getting_started/installation_and_usage/#cpp-compiler-support)
[Installation And Usage](https://mpusz.github.io/mp-units/latest/getting_started/cpp_compiler_support)
chapter of our documentation.

View File

@ -25,13 +25,20 @@ import re
from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.build import can_run, check_min_cppstd
from conan.tools.build import can_run, default_cppstd, valid_min_cppstd
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
from conan.tools.files import copy, load, rmdir
required_conan_version = ">=2.0.0"
def loose_lt_semver(v1, v2):
lv1 = [int(v) for v in v1.split(".")]
lv2 = [int(v) for v in v2.split(".")]
min_length = min(len(lv1), len(lv2))
return lv1[:min_length] < lv2[:min_length]
class MPUnitsConan(ConanFile):
name = "mp-units"
homepage = "https://github.com/mpusz/mp-units"
@ -54,14 +61,18 @@ class MPUnitsConan(ConanFile):
url = "https://github.com/mpusz/mp-units"
settings = "os", "arch", "compiler", "build_type"
options = {
"cxx_modules": [True, False],
"use_fmtlib": [True, False],
"cxx_modules": ["auto", True, False],
"std_format": ["auto", True, False],
"string_view_ret": ["auto", True, False],
"no_crtp": ["auto", True, False],
}
default_options = {
"cxx_modules": False,
"use_fmtlib": False,
"cxx_modules": "auto",
"std_format": "auto",
"string_view_ret": "auto",
"no_crtp": "auto",
}
tool_requires = "cmake/[>=3.28.1]"
tool_requires = "cmake/[>=3.29]"
exports = "LICENSE.md"
exports_sources = (
"docs/*",
@ -75,27 +86,106 @@ class MPUnitsConan(ConanFile):
no_copy_source = True
@property
def _minimum_compilers_version(self):
def _feature_compatibility(self):
return {
"gcc": "12",
"clang": "16",
"apple-clang": "15",
# , "msvc": "192"
"minimum_support": {
"std": "20",
"compiler": {
"gcc": "12",
"clang": "16",
"apple-clang": "15",
"msvc": "",
},
},
"std_format": {
"std": "20",
"compiler": {
"gcc": "13",
"clang": "17",
"apple-clang": "",
"msvc": "",
},
},
"cxx_modules": {
"std": "20",
"compiler": {"gcc": "14", "clang": "17", "apple-clang": "", "msvc": ""},
},
"static_constexpr_vars_in_constexpr_func": {
"std": "23",
"compiler": {"gcc": "13", "clang": "17", "apple-clang": "", "msvc": ""},
},
"explicit_this": {
"std": "23",
"compiler": {
"gcc": "14",
"clang": "18",
"apple-clang": "",
"msvc": "",
},
},
}
@property
def _std_format_minimum_compilers_version(self):
def _option_feature_map(self):
return {
"gcc": "13",
"clang": "17",
# , "apple-clang": "15"
# , "msvc": "192"
"std_format": "std_format",
"cxx_modules": "cxx_modules",
"string_view_ret": "static_constexpr_vars_in_constexpr_func",
"no_crtp": "explicit_this",
}
def _check_feature_supported(self, name, feature_name=name):
compiler = self.settings.compiler
cppstd = compiler.get_safe("cppstd", default_cppstd(self))
feature = self._feature_compatibility[feature_name]
# check C++ version
if not valid_min_cppstd(self, feature["std"]):
raise ConanInvalidConfiguration(
f"'{name}' requires at least cppstd={feature['std']} ({cppstd} in use)",
)
# check compiler version
min_version = feature["compiler"].get(str(compiler))
if min_version is None:
# not tested compiler being used - use at your own risk
return
if min_version == "":
raise ConanInvalidConfiguration(
f"'{name}' is not yet supported by any known {compiler} compiler"
)
if loose_lt_semver(str(compiler.version), min_version):
raise ConanInvalidConfiguration(
f"'{name}' requires at least {compiler}-{min_version} ({compiler}-{compiler.version} in use)"
)
def _is_feature_enabled(self, name):
compiler = self.settings.compiler
opt = self.options.get_safe(name)
feature_name = self._option_feature_map[name]
feature = self._feature_compatibility[feature_name]
min_version = feature["compiler"].get(str(compiler))
return bool(
opt is True
or (
opt == "auto"
and min_version
and not loose_lt_semver(str(compiler.version), min_version)
)
)
@property
def _build_all(self):
return bool(self.conf.get("user.mp-units.build:all", default=False))
@property
def _build_cxx_modules(self):
return self._is_feature_enabled("cxx_modules")
@property
def _use_fmtlib(self):
return not self._is_feature_enabled("std_format")
@property
def _skip_la(self):
return bool(self.conf.get("user.mp-units.build:skip_la", default=False))
@ -109,7 +199,7 @@ class MPUnitsConan(ConanFile):
def requirements(self):
self.requires("gsl-lite/0.41.0")
if self.options.use_fmtlib:
if self._use_fmtlib:
self.requires("fmt/10.2.1")
def build_requirements(self):
@ -119,27 +209,10 @@ class MPUnitsConan(ConanFile):
self.test_requires("wg21-linear_algebra/0.7.3")
def validate(self):
check_min_cppstd(self, "20")
def loose_lt_semver(v1, v2):
lv1 = [int(v) for v in v1.split(".")]
lv2 = [int(v) for v in v2.split(".")]
min_length = min(len(lv1), len(lv2))
return lv1[:min_length] < lv2[:min_length]
compiler = self.settings.compiler
min_version = self._minimum_compilers_version.get(str(compiler))
if min_version and loose_lt_semver(str(compiler.version), min_version):
raise ConanInvalidConfiguration(
f"{self.ref} requires at least {compiler} {min_version} ({compiler.version} in use)"
)
if not self.options.use_fmtlib:
min_version = self._std_format_minimum_compilers_version.get(str(compiler))
if min_version and loose_lt_semver(str(compiler.version), min_version):
raise ConanInvalidConfiguration(
f"`std::format` requires at least {compiler} {min_version} ({compiler.version} in use). "
"Use `-o use_fmtlib=True` instead."
)
self._check_feature_supported("mp-units", "minimum_support")
for key, value in self._option_feature_map.items():
if self.options.get_safe(key) is True:
self._check_feature_supported(key, value)
def layout(self):
cmake_layout(self)
@ -148,13 +221,19 @@ class MPUnitsConan(ConanFile):
tc = CMakeToolchain(self)
if self._build_all:
tc.cache_variables["CMAKE_VERIFY_INTERFACE_HEADER_SETS"] = True
if self.options.cxx_modules:
tc.cache_variables["MP_UNITS_DEV_BUILD_LA"] = not self._skip_la
if self._build_cxx_modules:
tc.cache_variables["CMAKE_CXX_SCAN_FOR_MODULES"] = True
tc.cache_variables["MP_UNITS_BUILD_CXX_MODULES"] = True
tc.cache_variables["MP_UNITS_DEV_BUILD_LA"] = (
self._build_all and not self._skip_la
)
tc.cache_variables["MP_UNITS_USE_FMTLIB"] = bool(self.options.use_fmtlib)
tc.cache_variables["MP_UNITS_BUILD_CXX_MODULES"] = str(
self.options.cxx_modules
).upper()
tc.cache_variables["MP_UNITS_API_STD_FORMAT"] = str(
self.options.std_format
).upper()
tc.cache_variables["MP_UNITS_API_STRING_VIEW_RET"] = str(
self.options.string_view_ret
).upper()
tc.cache_variables["MP_UNITS_API_NO_CRTP"] = str(self.options.no_crtp).upper()
tc.generate()
deps = CMakeDeps(self)
deps.generate()

View File

@ -0,0 +1,90 @@
# C++ compiler support (API/ABI) { #cpp-compiler-support }
!!! info
**mp-units** library tries to provide the best user experience possible with the C++ language.
To achieve that, it extensively uses the latest C++ language features.
Even though the library benefits from the latest C++ versions (if available), C++20 is enough
to compile and use all of the library's functionality. Newer features can be hidden behind
some [preprocessor macros](../users_guide/use_cases/wide_compatibility.md#compatibility-macros)
providing a backward-compatible way to use them.
The table below provides the minimum compiler version required to compile the code using a specific
C++ feature:
| C++ Feature | C++ version | gcc | clang | apple-clang | MSVC |
|-----------------------------------------------------------|:-----------:|:---:|:-----:|:-----------:|:----:|
| **Minimum support** | 20 | 12 | 16 | 15 | None |
| **`std::format`** | 20 | 13 | 17 | None | None |
| **C++ modules** | 20 | 14 | 17 | None | None |
| **Static `constexpr` variables in `constexpr` functions** | 23 | 13 | 17 | None | None |
| **Explicit `this` parameter** | 23 | 14 | 18 | None | None |
!!! important
Enabling/disabling features listed above may influence the API of the library and the ABI of
the customers' projects.
## `std::format`
- Provides [powerful text formatting capabilities](../users_guide/framework_basics/text_output.md#stdformat)
for C++.
- An alternative [fmtlib](https://github.com/fmtlib/fmt) library can be used instead if
- the C++ language feature is not supported,
- the customer's project did not switch to `std::format` yet (even when the compiler
supports it).
- To write code with wide compatibility
a [dedicated macro may be used](../users_guide/use_cases/wide_compatibility.md#mp_units_std_fmt).
- Tested with `__cpp_lib_format` [feature test macro](https://en.cppreference.com/w/cpp/feature_test).
- Related build options:
- Conan: [std_format](installation_and_usage.md#std_format)
- CMake: [MP_UNITS_API_STD_FORMAT](installation_and_usage.md#MP_UNITS_API_STD_FORMAT)
## C++ modules
- Provide new way to share declarations and definitions across translation units.
- If used, the library will distribute both "old-style" headers and module interface units
- associated with the same CMake targets.
- Even with full compiler support, a user may still decide to not pay for C++ modules compilation
if they are not needed by the customer's project.
- Feature test macro is not used for testing here because even if the compiler does not support
the entire C++ feature (e.g. header units), it is enough to build modules for this library.
- Related build options:
- Conan: [cxx_modules](installation_and_usage.md#cxx_modules)
- CMake: [MP_UNITS_BUILD_CXX_MODULES](installation_and_usage.md#MP_UNITS_BUILD_CXX_MODULES)
!!! note
More requirements for C++ modules support can be found in the
[CMake's documentation](https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html).
## Static `constexpr` variables in `constexpr` functions
- Allows returning `std::string_view` from the
[`unit_symbol()`](../users_guide/framework_basics/text_output.md#unit_symbol)
and [`dimension_symbol()`](../users_guide/framework_basics/text_output.md#dimension_symbol)
functions
- `std::string_view` type has a reference semantics so it has to point to a storage with
a longer lifetime.
- If this feature is not available, the API returns `mp_units::basic_fixed_string<CharT, N>` instead.
- Tested as `__cpp_constexpr >= 202211L` [feature test macro](https://en.cppreference.com/w/cpp/feature_test).
- Related build options:
- Conan: [string_view_ret](installation_and_usage.md#string_view_ret)
- CMake: [MP_UNITS_API_STRING_VIEW_RET](installation_and_usage.md#MP_UNITS_API_STRING_VIEW_RET)
## Explicit `this` parameter
- This feature removes the need for the usage of the CRTP idiom in the
[`quantity_spec` definitions](../users_guide/framework_basics/systems_of_quantities.md#defining-quantities).
- To write code with wide compatibility
a [dedicated macro may be used](../users_guide/use_cases/wide_compatibility.md#QUANTITY_SPEC).
- Tested with `__cpp_explicit_this_parameter` [feature test macro](https://en.cppreference.com/w/cpp/feature_test).
- Related build options:
- Conan: [no_crtp](installation_and_usage.md#no_crtp)
- CMake: [MP_UNITS_API_NO_CRTP](installation_and_usage.md#MP_UNITS_API_NO_CRTP)
*[CRTP]: Curiously Recurring Template Parameter

View File

@ -3,60 +3,12 @@
This chapter provides all the necessary information to obtain and build the code using **mp-units**.
It also describes how to build or distribute the library and generate its documentation.
## C++ compiler support { #cpp-compiler-support }
!!! info
**mp-units** library tries to provide the best user experience possible with the C++ language.
To achieve that, it extensively uses C++20 features and the
[explicit object parameter](https://en.cppreference.com/w/cpp/language/member_functions#Explicit_object_parameter)
from C++23.
Even though the library benefits from C++23 (if available), C++20 is enough to compile and
use all of the library's functionality. C++23 features are hidden behind
a [preprocessor macro](../users_guide/framework_basics/systems_of_quantities.md#defining-quantities)
providing a backward-compatible way to use it.
The below table provides the minimum compiler version required to compile the code using the
specific feature:
| Feature | gcc | clang | apple-clang | MSVC |
|----------------------|:---:|:-----:|:-----------:|:----:|
| **Minimum support** | 12 | 16 | 15 | None |
| **`std::format`** | 13 | 17 | None | None |
| **C++ modules** | 14 | 17 | None | None |
| **C++23 extensions** | 14 | 18 | None | None |
More requirements for C++ modules support can be found in the
[CMake's documentation](https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html).
## Modules
The **mp-units** library provides the following C++ modules.
```mermaid
flowchart TD
mp_units --- mp_units.systems --- mp_units.core
```
| C++ Module | CMake Target | Contents |
|--------------------|----------------------|----------------------------------------------------------|
| `mp_units.core` | `mp-units::core` | Core library framework and systems-independent utilities |
| `mp_units.systems` | `mp-units::systems` | All the systems of quantities and units |
| `mp_units` | `mp-units::mp-units` | Core + Systems |
!!! note
C++ modules are provided within the package only when [`cxx_modules`](#cxx_modules) Conan
option is set to `True`.
## Repository structure and dependencies
This repository contains three independent CMake-based projects:
- _./src_
- **_./src_**
- header-only project containing whole **mp-units** library
- _./src/CMakeList.txt_ file is intended as an **entry point for library users**
@ -68,7 +20,7 @@ This repository contains three independent CMake-based projects:
- [{fmt}](https://github.com/fmtlib/fmt) to provide text formatting of quantities
(if `std::format` is not supported yet on a specific compiler).
- _._
- **_._**
- project used as an **entry point for library development and CI/CD**
- it wraps _./src_ project together with usage examples and tests
@ -79,7 +31,7 @@ This repository contains three independent CMake-based projects:
library based on proposal [P1385](https://wg21.link/P1385) used in some examples
and tests.
- *./test_package*
- **_./test_package_**
- CMake library installation and Conan package verification.
@ -104,6 +56,27 @@ This repository contains three independent CMake-based projects:
[FAQ](faq.md#why-dont-we-have-cmake-options-to-disable-building-of-tests-and-examples).
## Modules
The **mp-units** library provides the following C++ modules:
```mermaid
flowchart TD
mp_units --- mp_units.systems --- mp_units.core
```
| C++ Module | CMake Target | Contents |
|--------------------|----------------------|----------------------------------------------------------|
| `mp_units.core` | `mp-units::core` | Core library framework and systems-independent utilities |
| `mp_units.systems` | `mp-units::systems` | All the systems of quantities and units |
| `mp_units` | `mp-units::mp-units` | Core + Systems |
!!! note
C++ modules are provided within the package only when [`cxx_modules`](#cxx_modules) Conan
option is set to `True`.
## Obtaining dependencies
This library assumes that most of the dependencies will be provided by the
@ -118,7 +91,7 @@ The rest of the dependencies responsible for documentation generation are provid
In case you are not familiar with Conan, to install it (or upgrade) just do:
```shell
pip3 install -U conan
pip install -U conan
```
After that, you might need to add a custom profile file for your development environment
@ -173,30 +146,59 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
## Build options
!!! note
Most of the below options are related to the C++ language features available in the compilers.
Please refer to the [C++ compiler support](cpp_compiler_support.md) chapter to learn more
about which C++ features are required and which compiler support them.
### Conan options
[cxx_modules](#cxx_modules){ #cxx_modules }
: [:octicons-tag-24: 2.2.0][cxx modules support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
: [:octicons-tag-24: 2.2.0][conan C++ modules support] · :octicons-milestone-24: `auto`/`True`/`False` (Default: `auto`)
Configures CMake to add C++ modules to the list of default targets.
[cxx modules support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
[conan C++ modules support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
[use_fmtlib](#use_fmtlib){ #use_fmtlib }
[std_format](#std_format){ #std_format }
: [:octicons-tag-24: 2.2.0][use fmtlib support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
: [:octicons-tag-24: 2.2.0][conan std::format support] · :octicons-milestone-24: `auto`/`True`/`False` (Default: `auto`)
Forces usage of [{fmt}](https://github.com/fmtlib/fmt) library instead of the C++20 Standard
Library features.
Enables the usage of [`std::format`](https://en.cppreference.com/w/cpp/utility/format/format)
and associated facilities for text formatting. If it is not supported, then
the [{fmt}](https://github.com/fmtlib/fmt) library is used instead.
[conan std::format support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
[string_view_ret](#string_view_ret){ #string_view_ret }
: [:octicons-tag-24: 2.2.0][conan returning string_view] · :octicons-milestone-24: `auto`/`True`/`False` (Default: `auto`)
Enables returning `std::string_view` from the
[`unit_symbol()`](../users_guide/framework_basics/text_output.md#unit_symbol)
and [`dimension_symbol()`](../users_guide/framework_basics/text_output.md#dimension_symbol)
functions. If this feature is not available, those functions will return
`mp_units::basic_fixed_string<CharT, N>` instead.
[conan returning string_view]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
[no_crtp](#no_crtp){ #no_crtp }
: [:octicons-tag-24: 2.2.0][conan no crtp support] · :octicons-milestone-24: `auto`/`True`/`False` (Default: `auto`)
Removes the need for the usage of the CRTP idiom in the
[`quantity_spec` definitions](../users_guide/framework_basics/systems_of_quantities.md#defining-quantities).
[conan no crtp support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
[use fmtlib support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
### Conan configuration properties
[`user.mp-units.build:all`](#user.mp-units.build-all){ #user.mp-units.build-all }
: [:octicons-tag-24: 2.2.0][build all support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
: [:octicons-tag-24: 2.2.0][conan build all support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
Enables compilation of all the source code, including tests and examples. To support this, it requires some additional Conan build dependencies described in
[Repository Structure and Dependencies](#repository-structure-and-dependencies).
@ -204,19 +206,19 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
[`tools.build:skip_test`](https://docs.conan.io/2/reference/commands/config.html?highlight=tools.build:skip_test#conan-config-list)
configuration property is set to `True`).
[build all support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
[conan build all support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
[`user.mp-units.build:skip_la`](#user-skip-la){ #user-skip-la }
: [:octicons-tag-24: 2.2.0][skip la support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
: [:octicons-tag-24: 2.2.0][conan skip la support] · :octicons-milestone-24: `True`/`False` (Default: `False`)
If `user.mp-units.build:all` is enabled, among others, Conan installs the external
[wg21-linear_algebra](https://conan.io/center/recipes/wg21-linear_algebra)
dependency and enables the compilation of linear algebra-based tests and usage examples.
Such behavior can be disabled with this option.
[skip la support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
[conan skip la support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
### CMake options
@ -229,16 +231,37 @@ tools.build:compiler_executables={"c": "gcc-12", "cpp": "g++-12"}
[build_cxx_modules support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
[`MP_UNITS_API_STD_FORMAT`](#MP_UNITS_API_STD_FORMAT){ #MP_UNITS_API_STD_FORMAT }
[`MP_UNITS_USE_FMTLIB`](#MP_UNITS_USE_FMTLIB){ #MP_UNITS_USE_FMTLIB }
: [:octicons-tag-24: 2.2.0][use fmtlib support] · :octicons-milestone-24: `AUTO`/`ON`/`OFF` (Default: `AUTO`)
: [:octicons-tag-24: 2.2.0][use fmtlib support] · :octicons-milestone-24: `ON`/`OFF` (Default: `OFF`)
Forces usage of [{fmt}](https://github.com/fmtlib/fmt) library instead of the C++20 Standard
Library features.
Enables the usage of [`std::format`](https://en.cppreference.com/w/cpp/utility/format/format)
and associated facilities for text formatting. If it is not supported, then
the [{fmt}](https://github.com/fmtlib/fmt) library is used instead.
[use fmtlib support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
[`MP_UNITS_API_STRING_VIEW_RET`](#MP_UNITS_API_STRING_VIEW_RET){ #MP_UNITS_API_STRING_VIEW_RET }
: [:octicons-tag-24: 2.2.0][cmake returning string_view] · :octicons-milestone-24: `AUTO`/`ON`/`OFF` (Default: `AUTO`)
Enables returning `std::string_view` from the
[`unit_symbol()`](../users_guide/framework_basics/text_output.md#unit_symbol)
and [`dimension_symbol()`](../users_guide/framework_basics/text_output.md#dimension_symbol)
functions. If this feature is not available, those functions will return
`mp_units::basic_fixed_string<CharT, N>` instead.
[cmake returning string_view]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
[`MP_UNITS_API_NO_CRTP`](#MP_UNITS_API_NO_CRTP){ #MP_UNITS_API_NO_CRTP }
: [:octicons-tag-24: 2.2.0][cmake no crtp support] · :octicons-milestone-24: `AUTO`/`ON`/`OFF` (Default: `AUTO`)
Removes the need for the usage of the CRTP idiom in the
[`quantity_spec` definitions](../users_guide/framework_basics/systems_of_quantities.md#defining-quantities).
[cmake no crtp support]: https://github.com/mpusz/mp-units/releases/tag/v2.2.0
#### Options for mp-units project developers
[`MP_UNITS_DEV_BUILD_LA`](#MP_UNITS_DEV_BUILD_LA){ #MP_UNITS_DEV_BUILD_LA }

View File

@ -16,27 +16,13 @@ The library source code is hosted on [GitHub](https://github.com/mpusz/mp-units)
??? info "Supported compilers"
This library tries to provide the best user experience possible with the C++ language.
To achieve that, it extensively uses C++20 features and the
[explicit object parameter](https://en.cppreference.com/w/cpp/language/member_functions#Explicit_object_parameter)
from C++23.
To achieve that, it extensively uses the latest C++ language features.
Even though the library benefits from C++23 (if available), C++20 is enough to compile and
use all of the library's functionality. C++23 features are hidden behind
a [preprocessor macro](users_guide/framework_basics/systems_of_quantities.md#defining-quantities)
providing a backward-compatible way to use it.
Even though the library benefits from the latest C++ versions (if available), C++20 is enough
to compile and use all of the library's functionality.
The below table provides the minimum compiler version required to compile the code using the
specific feature:
| Feature | gcc | clang | apple-clang | MSVC |
|----------------------|:---:|:-----:|:-----------:|:----:|
| **Minimum support** | 12 | 16 | 15 | None |
| **`std::format`** | 13 | 17 | None | None |
| **C++ modules** | 14 | 17 | None | None |
| **C++23 extensions** | 14 | 18 | None | None |
More requirements for C++ modules support can be found in the
[CMake's documentation](https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html).
Please refer to [C++ compiler support chapter](getting_started/cpp_compiler_support.md)
for more details.
=== "C++ modules"

View File

@ -3,7 +3,7 @@
!!! note
**mp-units** usage example applications are meant to be built on all of
[the supported compilers](../../getting_started/installation_and_usage.md#cpp-compiler-support).
[the supported compilers](../../getting_started/cpp_compiler_support.md).
This is why they benefit from the [Wide Compatibility](../use_cases/wide_compatibility.md) mode.
!!! tip

View File

@ -132,10 +132,15 @@ from such an instantiation.
Quantity specification definitions benefit from an
[explicit object parameter](https://en.cppreference.com/w/cpp/language/member_functions#Explicit_object_parameter)
added in C++23 to remove the need for CRTP idiom, which significantly simplifies the code.
However, as C++23 is far from being mainstream today, a portability macro `QUANTITY_SPEC()`
However, as C++23 is far from being mainstream today,
a [portability macro `QUANTITY_SPEC()`](../use_cases/wide_compatibility.md#QUANTITY_SPEC)
is provided and used consistently through the library to allow the code to compile with C++20
compilers, thanks to the CRTP usage under the hood.
See more in the
[C++ compiler support](../../getting_started/cpp_compiler_support.md#explicit-this-parameter)
chapter.
*[CRTP]: Curiously Recurring Template Parameter
For example, here is how the above quantity kind tree can be modeled in the library:

View File

@ -11,7 +11,7 @@ macros that can be used to ensure the wide compatibility of our code.
!!! note
Those macros are used in our short [example applications](../examples/tags_index.md) as those are meant
to be built on all of [the supported compilers](../../getting_started/installation_and_usage.md#cpp-compiler-support).
to be built on all of [the supported compilers](../../getting_started/cpp_compiler_support.md).
Some still do not support `std::format`, C++ modules, or C++ versions newer than C++20.
@ -155,5 +155,5 @@ use [fmtlib](https://github.com/fmtlib/fmt) as their primary formatting facility
from additional features provided with the library).
This macro resolves to either the `std` or `fmt` namespace, depending on the value of
[MP_UNITS_USE_FMTLIB](../../getting_started/installation_and_usage.md#MP_UNITS_USE_FMTLIB)
[MP_UNITS_API_STD_FORMAT](../../getting_started/installation_and_usage.md#MP_UNITS_API_STD_FORMAT)
CMake option.

View File

@ -130,6 +130,7 @@ nav:
- Introduction: getting_started/introduction.md
- Quick Start: getting_started/quick_start.md
- Look and Feel: getting_started/look_and_feel.md
- C++ compiler support (API/ABI): getting_started/cpp_compiler_support.md
- Installation and Usage: getting_started/installation_and_usage.md
- FAQ: getting_started/faq.md
- User's Guide:

View File

@ -31,43 +31,67 @@ include(CheckCXXFeatureSupported)
include(AddMPUnitsModule)
include(GNUInstallDirs)
# project options
# check if libc++ is being used
include(CheckLibcxxInUse)
check_libcxx_in_use(${projectPrefix}LIBCXX)
# project build options
option(${projectPrefix}BUILD_CXX_MODULES "Add C++ modules to the list of default targets" OFF)
message(STATUS "${projectPrefix}BUILD_CXX_MODULES: ${${projectPrefix}BUILD_CXX_MODULES}")
option(${projectPrefix}AS_SYSTEM_HEADERS "Exports library as system headers" OFF)
message(STATUS "${projectPrefix}AS_SYSTEM_HEADERS: ${${projectPrefix}AS_SYSTEM_HEADERS}")
# project API settings
function(cache_var_values name)
set_property(CACHE ${projectPrefix}${name} PROPERTY STRINGS ${ARGN})
if(NOT ${projectPrefix}${name} IN_LIST ARGN)
message(FATAL_ERROR
"Invalid value '${${projectPrefix}${name}}' provided for a cache variable ${projectPrefix}${name} (${ARGN} allowed)"
)
endif()
message(STATUS "${projectPrefix}${name}: ${${projectPrefix}${name}}")
endfunction()
option(${projectPrefix}USE_FMTLIB "Enables usage of fmtlib instead of the 'std::format' facilities" OFF)
message(STATUS "${projectPrefix}USE_FMTLIB: ${${projectPrefix}USE_FMTLIB}")
set(${projectPrefix}API_STD_FORMAT AUTO CACHE STRING "Enable `std::format` support")
cache_var_values(API_STD_FORMAT AUTO TRUE FALSE)
set(${projectPrefix}API_STRING_VIEW_RET AUTO CACHE STRING
"Enable returning `std::string_view` from `constexpr` functions"
)
cache_var_values(API_STRING_VIEW_RET AUTO TRUE FALSE)
set(${projectPrefix}API_NO_CRTP AUTO CACHE STRING "Enable class definitions without CRTP idiom")
cache_var_values(API_NO_CRTP AUTO TRUE FALSE)
# C++ features
check_cxx_feature_supported(__cpp_explicit_this_parameter ${projectPrefix}EXPLICIT_THIS_PARAMETER_SUPPORTED)
check_cxx_feature_supported(__cpp_lib_format ${projectPrefix}LIB_FORMAT_SUPPORTED)
check_cxx_feature_supported("__cpp_constexpr >= 202211L" ${projectPrefix}STATIC_CONSTEXPR_VARS_IN_CONSTEXPR_FUNCTIONS)
check_cxx_feature_supported(__cpp_explicit_this_parameter ${projectPrefix}EXPLICIT_THIS_PARAMETER_SUPPORTED)
if(${projectPrefix}EXPLICIT_THIS_PARAMETER_SUPPORTED)
message(STATUS "API/ABI: `quantity_spec` uses explicit `this` parameter in its definition")
else()
message(STATUS "API/ABI: `quantity_spec` uses CRTP in its definition")
# validate settings
if(${projectPrefix}API_STD_FORMAT STREQUAL "TRUE"
AND NOT
(${projectPrefix}LIB_FORMAT_SUPPORTED
# libc++ has a basic supports for std::format but does not set __cpp_lib_format
# https://github.com/llvm/llvm-project/issues/77773
OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "17"
AND ${projectPrefix}LIBCXX))
)
message(FATAL_ERROR "`std::format` enabled but not supported")
endif()
if(${projectPrefix}STATIC_CONSTEXPR_VARS_IN_CONSTEXPR_FUNCTIONS)
message(STATUS "API/ABI: `unit_symbol()` returns `std::string_view`")
else()
message(STATUS "API/ABI: `unit_symbol()` returns `fixed_string`")
if(${projectPrefix}API_STRING_VIEW_RET STREQUAL "TRUE" AND NOT
${projectPrefix}STATIC_CONSTEXPR_VARS_IN_CONSTEXPR_FUNCTIONS
)
message(FATAL_ERROR "`std::string_view` returns enabled but not supported")
endif()
# C++ modules
if(${projectPrefix}BUILD_CXX_MODULES)
if(CMAKE_VERSION VERSION_LESS "3.28.1")
message(FATAL_ERROR, "CMake versions before 3.28.1 do not support C++ modules properly")
if(${projectPrefix}API_NO_CRTP STREQUAL "TRUE" AND NOT ${projectPrefix}EXPLICIT_THIS_PARAMETER_SUPPORTED)
message(FATAL_ERROR "`NO_CRTP` mode enabled but explicit `this` parameter is not supported")
endif()
if(${projectPrefix}BUILD_CXX_MODULES STREQUAL "TRUE")
if(CMAKE_VERSION VERSION_LESS "3.29")
message(FATAL_ERROR "CMake versions before 3.29 do not support C++ modules properly")
endif()
cmake_minimum_required(VERSION 3.28.1)
# # none of the below seems to work
# cmake_policy(VERSION 3.28.1)
# cmake_policy(SET CMP0155 NEW)
set(${projectPrefix}TARGET_SCOPE "PUBLIC")
else()
set(${projectPrefix}TARGET_SCOPE "INTERFACE")

View File

@ -0,0 +1,41 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Mateusz Pusz
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 3.15)
function(check_libcxx_in_use variable)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
message(CHECK_START "Checking if libc++ is being used")
list(APPEND CMAKE_MESSAGE_INDENT " ")
include(CheckCXXSymbolExists)
check_cxx_symbol_exists(_LIBCPP_VERSION "ciso646" ${variable})
set(${variable} ${${variable}} PARENT_SCOPE)
list(POP_BACK CMAKE_MESSAGE_INDENT)
if(${variable})
message(CHECK_PASS "found")
else()
message(CHECK_FAIL "not found")
endif()
endif()
endfunction()

View File

@ -22,6 +22,15 @@
cmake_minimum_required(VERSION 3.23)
function(set_feature_flag name)
set(val_list "TRUE" "FALSE")
if(${projectPrefix}${name} IN_LIST val_list)
target_compile_definitions(
mp-units-core ${${projectPrefix}TARGET_SCOPE} ${projectPrefix}${name}=$<BOOL:${${projectPrefix}${name}}>
)
endif()
endfunction()
# find dependencies
if(NOT TARGET gsl::gsl-lite)
find_package(gsl-lite REQUIRED)
@ -78,11 +87,13 @@ add_mp_units_module(
MODULE_INTERFACE_UNIT mp-units-core.cpp
)
target_compile_definitions(
mp-units-core ${${projectPrefix}TARGET_SCOPE} ${projectPrefix}USE_FMTLIB=$<BOOL:${${projectPrefix}USE_FMTLIB}>
)
set_feature_flag(API_STD_FORMAT)
set_feature_flag(API_STRING_VIEW_RET)
set_feature_flag(API_NO_CRTP)
if(${projectPrefix}USE_FMTLIB)
if(${projectPrefix}API_STD_FORMAT STREQUAL "FALSE" OR (${projectPrefix}API_STD_FORMAT STREQUAL "AUTO"
AND NOT ${projectPrefix}LIB_FORMAT_SUPPORTED)
)
if(NOT TARGET fmt::fmt)
find_package(fmt REQUIRED)
endif()

View File

@ -110,3 +110,15 @@
#define MP_UNITS_CONSTRAINED_NTTP_WORKAROUND(X) X
#endif
#if !defined MP_UNITS_API_STRING_VIEW_RET && __cpp_constexpr >= 202211L
#define MP_UNITS_API_STRING_VIEW_RET 1
#endif
#if !defined MP_UNITS_API_NO_CRTP && __cpp_explicit_this_parameter
#define MP_UNITS_API_NO_CRTP 1
#endif

View File

@ -22,6 +22,7 @@
#pragma once
#include <mp-units/bits/external/hacks.h>
#include <mp-units/bits/dimension_concepts.h>
#include <mp-units/bits/expression_template.h>
#include <mp-units/bits/module_macros.h>
@ -29,7 +30,7 @@
namespace mp_units {
MP_UNITS_EXPORT
#ifdef __cpp_explicit_this_parameter
#ifdef MP_UNITS_API_NO_CRTP
template<auto...>
#else
template<typename, auto...>
@ -50,7 +51,7 @@ inline constexpr bool is_specialization_of_kind_of<kind_of_<Q>> = true;
template<typename T>
concept QuantityKindSpec = is_specialization_of_kind_of<T>;
#ifdef __cpp_explicit_this_parameter
#ifdef MP_UNITS_API_NO_CRTP
template<auto... Args>
void to_base_specialization_of_quantity_spec(const volatile quantity_spec<Args...>*);
#else
@ -65,7 +66,7 @@ inline constexpr bool is_derived_from_specialization_of_quantity_spec =
template<typename T>
inline constexpr bool is_specialization_of_quantity_spec = false;
#ifdef __cpp_explicit_this_parameter
#ifdef MP_UNITS_API_NO_CRTP
template<auto... Args>
inline constexpr bool is_specialization_of_quantity_spec<quantity_spec<Args...>> = true;
#else

View File

@ -24,7 +24,7 @@
#include <mp-units/bits/external/hacks.h>
#ifdef __cpp_explicit_this_parameter
#ifdef MP_UNITS_API_NO_CRTP
#define QUANTITY_SPEC(name, ...) \
inline constexpr struct name : ::mp_units::quantity_spec<__VA_ARGS__> { \
@ -38,6 +38,14 @@
#endif
#if !defined MP_UNITS_API_STD_FORMAT || !MP_UNITS_API_STD_FORMAT
#if __has_include(<fmt/format.h>)
#define MP_UNITS_USE_FMTLIB 1
#endif
#endif
#if MP_UNITS_USE_FMTLIB
MP_UNITS_DIAGNOSTIC_PUSH

View File

@ -319,7 +319,7 @@ MP_UNITS_EXPORT template<dimension_symbol_formatting fmt = dimension_symbol_form
return buffer.size();
};
#if __cpp_constexpr >= 202211L // Permitting static constexpr variables in constexpr functions
#if MP_UNITS_API_STRING_VIEW_RET // Permitting static constexpr variables in constexpr functions
static constexpr std::size_t size = get_size();
static constexpr auto buffer = detail::get_symbol_buffer<CharT, size, fmt>(D{});
return std::string_view(buffer.data(), size);

View File

@ -24,6 +24,7 @@
#include <mp-units/bits/expression_template.h>
#include <mp-units/bits/external/algorithm.h>
#include <mp-units/bits/external/hacks.h>
#include <mp-units/bits/external/type_name.h>
#include <mp-units/bits/external/type_traits.h>
#include <mp-units/bits/get_common_base.h>
@ -107,11 +108,11 @@ using to_dimension = std::remove_const_t<decltype(Q::dimension)>;
template<AssociatedUnit U>
[[nodiscard]] consteval auto get_associated_quantity(U);
#ifndef __cpp_explicit_this_parameter
#ifndef MP_UNITS_API_NO_CRTP
template<typename Self>
#endif
struct quantity_spec_interface {
#ifdef __cpp_explicit_this_parameter
#ifdef MP_UNITS_API_NO_CRTP
template<typename Self, UnitOf<Self{}> U>
[[nodiscard]] consteval Reference auto operator[](this Self self, U u)
{
@ -166,7 +167,7 @@ MP_UNITS_EXPORT_BEGIN
* types `speed` and `velocity` are considered not equal to `derived_dimension<length, per<time>>` or
* to each other.
*/
#ifdef __cpp_explicit_this_parameter
#ifdef MP_UNITS_API_NO_CRTP
template<auto...>
#else
template<typename, auto...>
@ -211,7 +212,7 @@ MP_UNITS_EXPORT_END
* @tparam BaseDimension base dimension for which a base quantity is being defined
* @tparam Args optionally a value of a `quantity_character` in case the base quantity should not be scalar
*/
#ifdef __cpp_explicit_this_parameter
#ifdef MP_UNITS_API_NO_CRTP
template<detail::BaseDimension auto Dim, one_of<quantity_character> auto... Args>
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
struct quantity_spec<Dim, Args...> : detail::quantity_spec_interface {
@ -254,7 +255,7 @@ struct quantity_spec<Self, Dim, Args...> : detail::quantity_spec_interface<Self>
* @tparam Eq quantity equation specification of a derived quantity
* @tparam Args optionally a value of a `quantity_character` in case the base quantity should not be scalar
*/
#ifdef __cpp_explicit_this_parameter
#ifdef MP_UNITS_API_NO_CRTP
template<detail::IntermediateDerivedQuantitySpec auto Eq, one_of<quantity_character> auto... Args>
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
struct quantity_spec<Eq, Args...> : detail::quantity_spec_interface {
@ -295,7 +296,7 @@ struct quantity_spec<Self, Eq, Args...> : detail::quantity_spec_interface<Self>
* @tparam Args optionally a value of a `quantity_character` in case the base quantity should not be scalar
* or `is_kind` in case the quantity starts a new hierarchy tree of a kind
*/
#ifdef __cpp_explicit_this_parameter
#ifdef MP_UNITS_API_NO_CRTP
template<detail::NamedQuantitySpec auto QS, one_of<quantity_character, struct is_kind> auto... Args>
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
struct quantity_spec<QS, Args...> : std::remove_const_t<decltype(QS)> {
@ -307,7 +308,7 @@ struct quantity_spec<Self, QS, Args...> : std::remove_const_t<decltype(QS)> {
static constexpr auto _parent_ = QS;
static constexpr quantity_character character = detail::quantity_character_init<Args...>(QS.character);
#ifndef __cpp_explicit_this_parameter
#ifndef MP_UNITS_API_NO_CRTP
template<typename Self_ = Self, UnitOf<Self_{}> U>
[[nodiscard]] MP_UNITS_CONSTEVAL Reference auto operator[](U u) const
{
@ -353,7 +354,7 @@ struct quantity_spec<Self, QS, Args...> : std::remove_const_t<decltype(QS)> {
* @tparam Args optionally a value of a `quantity_character` in case the base quantity should not be scalar
* or `is_kind` in case the quantity starts a new hierarchy tree of a kind
*/
#ifdef __cpp_explicit_this_parameter
#ifdef MP_UNITS_API_NO_CRTP
template<detail::NamedQuantitySpec auto QS, detail::IntermediateDerivedQuantitySpec auto Eq,
one_of<quantity_character, struct is_kind> auto... Args>
requires(!requires { QS._equation_; } ||
@ -418,7 +419,7 @@ struct quantity_spec<Self, QS, Eq, Args...> : quantity_spec<Self, QS, Args...> {
*/
template<detail::IntermediateDerivedQuantitySpecExpr... Expr>
struct derived_quantity_spec :
#ifdef __cpp_explicit_this_parameter
#ifdef MP_UNITS_API_NO_CRTP
detail::quantity_spec_interface,
#else
detail::quantity_spec_interface<derived_quantity_spec<Expr...>>,
@ -456,7 +457,7 @@ template<QuantitySpec Q>
} // namespace detail
#ifdef __cpp_explicit_this_parameter
#ifdef MP_UNITS_API_NO_CRTP
template<typename Q>
requires detail::QuantitySpecWithNoSpecifiers<Q> && (detail::get_kind_tree_root(Q{}) == Q{})
struct kind_of_<Q> : Q {
@ -1430,7 +1431,7 @@ template<QuantitySpec Q>
requires requires(Q q) { get_kind_tree_root(q); }
using to_kind = std::remove_const_t<decltype(get_kind_tree_root(Q{}))>;
#ifdef __cpp_explicit_this_parameter
#ifdef MP_UNITS_API_NO_CRTP
template<NamedQuantitySpec auto QS, auto... Args>
[[nodiscard]] consteval bool defined_as_kind(quantity_spec<QS, Args...>)
#else

View File

@ -840,7 +840,7 @@ MP_UNITS_EXPORT template<unit_symbol_formatting fmt = unit_symbol_formatting{},
return buffer.size();
};
#if __cpp_constexpr >= 202211L // Permitting static constexpr variables in constexpr functions
#if MP_UNITS_API_STRING_VIEW_RET // Permitting static constexpr variables in constexpr functions
static constexpr std::size_t size = get_size();
static constexpr auto buffer = detail::get_symbol_buffer<CharT, size, fmt>(U{});
return std::string_view(buffer.data(), size);

View File

@ -22,7 +22,7 @@
include(CMakeFindDependencyMacro)
if(MP_UNITS_USE_FMTLIB)
if(MP_UNITS_API_STD_FORMAT)
find_dependency(fmt)
endif()

View File

@ -22,13 +22,14 @@
#pragma once
#include <mp-units/bits/external/hacks.h>
#include <mp-units/quantity_spec.h>
#include <type_traits>
template<auto V, typename T>
inline constexpr bool is_of_type = std::is_same_v<std::remove_cvref_t<decltype(V)>, T>;
#ifdef __cpp_explicit_this_parameter
#ifdef MP_UNITS_API_NO_CRTP
#define QUANTITY_SPEC_(name, ...) \
inline constexpr struct name##_ : quantity_spec<__VA_ARGS__> { \

View File

@ -27,4 +27,4 @@ find_package(mp-units REQUIRED)
add_executable(test_package test_package.cpp)
target_link_libraries(test_package PRIVATE mp-units::mp-units)
target_compile_definitions(test_package PRIVATE MP_UNITS_USE_FMTLIB=$<BOOL:${MP_UNITS_USE_FMTLIB}>)
target_compile_definitions(test_package PRIVATE MP_UNITS_API_STD_FORMAT=$<BOOL:${MP_UNITS_API_STD_FORMAT}>)

View File

@ -39,8 +39,8 @@ class TestPackageConan(ConanFile):
def generate(self):
tc = CMakeToolchain(self)
tc.variables["MP_UNITS_USE_FMTLIB"] = bool(
self.dependencies["mp-units"].options.use_fmtlib
tc.variables["MP_UNITS_API_STD_FORMAT"] = bool(
self.dependencies["mp-units"].options.std_format
)
tc.generate()