![**The C++ Information Broker**](https://github.com/jfalcou/spy/raw/main/logo.png) # Purpose Detection and versioning of operating systems, compilers, architecture and other element are traditionally done using preprocessor macros. Library like [Boost.Predef](https://www.boost.org/doc/libs/release/doc/html/predef.html) provides a sanitized interface on top of those but still live in a world where the preprocessor is king. SPY is a C++17 (and onward) library that gathers similar information and provides a `constexpr` compatible interface to access those information, thus making their exploitation within `constexpr` context possible. **References:** ![**Our CppCon 2019 Ligthning talk video**](https://www.youtube.com/watch?v=t406o2EhG-A) - [Our CppCon 2019 Lightning talk slides](https://docs.google.com/presentation/d/1nSBhU4pr5EWznni0MYsyDkMCr3O3q2XS-KQdz2_BRRI/edit?usp=sharing) - [Boost.Predef](https://www.boost.org/doc/libs/release/doc/html/predef.html) # How to install ## Using CMake After cloning the repository, run `CMake` with an install prefix path then run the `install` target using `Make` or any other build system. ~~~~~ bash git clone https://github.com/jfalcou/spy.git mkdir build cd build cmake .. -DCMAKE_INSTALL_PREFIX=path/to/install/folder make install ~~~~~ ## Manually After cloning the repository, copy the `spy.hpp` file into the folder of your choice. ~~~~~ bash git clone https://github.com/jfalcou/spy.git cp -r include/spy.hpp path/to/install/folder ~~~~~ ## Sample usage SPY is usable by simply including the `spy.hpp` file as demonstrated here: Just compile this example using a C++17 compliant compiler. Don't forget to add the path to the SPY library file to your favorite compiler's options. ## Redistribuable include If you want to use SPY in your own project but want to keep a low imprint on your own source code, one can copy the single `spy.hpp` file provided at the root of the include folder. # User manual ## Supported detectors SPY can detect: - Architecture family via the `spy::architecture` object. - Supported SIMD extension sets - OS vendor via the `spy::operating_system` object. - Compiler vendor and version (in the M.N.P format) via the `spy::compiler` object. - libc vendor and version (in the M.N.P format) via the `spy::libc` object. - stdlib vendor and version (in the M.N.P format) via the `spy::stdlib` object. The simplest usage of those objects is to pass them to an output stream to get a readable display of their information. [**Run it on Compiler Explorer**](https://godbolt.org/z/Kd6cT9qPz) ## Comparing vendors ### Main Information Knowing is half the battle, we may want to compare the current compiler or OS to a given one so you can branch off your code based on this information. Here is the list of each detected vendor for each SPY objects. | Detector | Supported vendor | | ----------------------- | ------------------------------------------------------------------------------ | | `spy::architecture` | `x86_`, `amd64_`, `ppc_`, `arm_` | | `spy::operating_system` | `android_`, `bsd_`, `cygwin_`, `ios_`, `linux_`, `macos_`, `unix_`, `windows_` | | `spy::compiler` | `clang_`, `gcc_`, `intel_`, `msvc_`, `emscripten_`, `dpcpp_`, `nvcc_` | | `spy::libc` | `cloudabi_`, `gnu_` `uc_`, `vms_`, `zos_` | | `spy::stdlib` | `gnucpp_`, `libcpp_` | Here is a sample code comparing some detectors to a specific vendor: [**Run it on Compiler Explorer**](https://godbolt.org/z/8rz9q84Ez) ### Other Informations Additional features can be checked using the `spy::supports` namespace: - Checking for POSIX capability via `spy::supports::posix_` - Checking for status of address and threads sanitizers via `spy::supports::sanitizers_status`, `spy::supports::address_sanitizers_status` and `spy::supports::thread_sanitizers_status`. `spy::supports::sanitizers_status` is set to true if either `spy::supports::address_sanitizers_status` or `spy::supports::thread_sanitizers_status` is true. - Checking if current translation unit is compiled with some accelerator specific mode via either `spy::supports::sycl`, that is set if the code is compiled with the `-fsycl` option, or `spy::supports::cuda`, that is set if the code is compiled from a `.cu` file. ## Comparing versions Checking for a vendor is sometimes not enough, we need to check which version of a given component is used. To do this, you can compare a detector to a given version value using any comparison operators. Versions are build using a custom literal suffix based on the vendor name (`_vendor`) and a series of integral values separated by `'`. | Detector | Supported version suffixes | | --------------- | ------------------------------------------------------------------------------ | | `spy::compiler` | `_clang`, `_gcc`, `_intel`, `_msvc`, `_em` | | `spy::libc` | `_cloudabi`, `_gnu` `_uc`, `_vms`, `_zos` | | `spy::stdlib` | `_gnucpp`, `_libcpp` | The following code demonstrates such comparisons: [**Run it on Compiler Explorer**](https://godbolt.org/z/hhxh5r5q9) ## Handling SIMD extensions ### Instructions sets SIMD extensions set detection is made so that one can ask if the current SIMD extension is exactly, below or above a given reference instruction set. Detectable instructions sets depends on SIMD hardware vendor | Architecture | Supported SIMD instructions sets | | ------------- | ------------------------------------------------------------------------------------ | | X86 | `sse1_`, `sse2_`, `sse3_`, `ssse3_`, `sse41_`, `sse42_`, `avx_`, `avx2_`, `avx512_` | | Power PC | `vmx_`, `vmx_2_03_`, `vmx_2_05_`, `vmx_2_06_`, `vmx_2_07_`, `vmx_3_00_`, `vmx_3_01_` | | | `vsx_`, `vsx_2_06_`, `vsx_2_07_`, `vsx_3_00_`, `vsx_3_01_` | | ARM | `neon_`,`asimd_`,`sve_`,`sve128_`,`sve256_`,`sve512_`,`sve1024_` | | WASM | `simd128_` | Complete set of comparison operators is provided for those sets. Order of instructions sets are built so that if an instructions set supersedes another, it is considered greater than. For example, `avx_` is greater than `sse41_` as the former is a super-set of the later. Moreover, the `spy::simd_instruction_set` object exposes a constexpr `width` static field that contains the size in bits of the current SIMD instructions set registers. [**Run it on Compiler Explorer**](https://godbolt.org/z/Wj9PE9ahP) ### SIMD Architectures One can also simply asks if a given family of instructions set is available. [**Run it on Compiler Explorer**](https://godbolt.org/z/Pn5TrePMo) ### Supplemental Instructions sets Some SIMD instructions set provides supplemental instructions on top of existing system. Those supplemental instruction set can be checked using the `spy::supports` namespace. [**Run it on Compiler Explorer**](https://godbolt.org/z/36K8bvrxK) The complete list of supplemental instruction sets si given in the following table. | Architecture | Supported SIMD instructions sets | | ------------- | ------------------------------------------------------------------------------------------------------------------------------- | | X86 AVX | `xop_`, `fma_`, `fma4_` | | X86 AVX512 | `avx512::bw_`, `avx512::cd_`, `avx512::dq_`, `avx512::er_`, `avx512::ifma_`, `avx512::pf_`, `avx512::vl_`, `avx512::popcntdq_`, `avx512::_4fmaps_`, `avx512::vnniw_`, `avx512::vbmi_`, `avx512::bf16_`, `avx512::bitalg_`, `avx512::vbmi2_`, `avx512::vnni_`, `avx512::vpintersect_` | # Caveat with `if constexpr` The detection and comparisons of versions using SPY detectors are subject to some caveats that stem from the way `if constexpr` behaves. As both branch of the `if constexpr` are ODR_checked, all functions and type names must be defined even if not used. This means that this can't compile whatsoever: Post C++20, we advice you to use concepts with template functions: # License This library is licensed under the Boost Software License as specified in the LICENSE.md file. If you use SPY in your project or product, feel free to send us an email so we can advertise it here. ``` Boost Software License 1.0 Copyright : SPY Project Contributors Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ```