Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract platform and feature detection to a separate file and add macro support for a number of C++20/23 features #93

Merged
merged 25 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b47beec
Add common Clion generated files to gitignore
Rinzii May 1, 2024
3741c71
Tell MSVC to report the correct value of __cplusplus instead of 199711L
Rinzii May 1, 2024
6a31309
Changed my mind on forcing msvc to properly report.
Rinzii May 1, 2024
5cb524c
First revision of compatibility layer
Rinzii May 2, 2024
d781880
Correct minor oversight & update the documentation and formating
Rinzii May 2, 2024
fad9ebb
Remove accidental macro redefinition
Rinzii May 2, 2024
0d7a8c3
Update the naming convention of attribute wrappers.
Rinzii May 2, 2024
a899543
Apply requested changes
Rinzii May 2, 2024
fafc4ff
Add a few more items and apply minor reshuffle
Rinzii May 2, 2024
91ef2df
Add wrapper for user generated static_assert
Rinzii May 4, 2024
438c8ae
Finalize formatting and wrapping up details
Rinzii May 4, 2024
0486f55
First initial wave of adjustments
Rinzii May 4, 2024
ef3d6d0
Add C++20 to the CI
Rinzii May 5, 2024
58a3bf1
Promote user generated static_asserts to the main header
Rinzii May 5, 2024
ef9dbbd
Bring in final changes to platform header
Rinzii May 5, 2024
0b81596
Fix typo
Rinzii May 5, 2024
9eb10cd
Remove duplicated macro
Rinzii May 5, 2024
e432049
Fix incorrect formatting
Rinzii May 5, 2024
c47c4f9
Add the ability to pass feature flags for the desired std to libassert
Rinzii May 5, 2024
c229fe1
Update to use option instead
Rinzii May 5, 2024
6a482ea
Fix cmake commands and set variables for specified std
Rinzii May 5, 2024
ba82044
Add proper switching between cxx standards
Rinzii May 5, 2024
0a13f97
Fix accidental chaining of make command
Rinzii May 5, 2024
d8545ad
Quick formatting/style fix
jeremy-rifkin May 7, 2024
cd72941
Oops
jeremy-rifkin May 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ on:
push:
pull_request:

# TODO: Check different standards?

jobs:
build-linux:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
compiler: [g++-10, clang++-14]
cxx_version: [ cxx_std_17, cxx_std_20 ]
target: [Debug, Release]
steps:
- uses: actions/checkout@v2
Expand All @@ -24,7 +23,8 @@ jobs:
cd build
cmake .. \
-DCMAKE_BUILD_TYPE=${{matrix.target}} \
-DCMAKE_CXX_COMPILER=${{matrix.compiler}}
-DCMAKE_CXX_COMPILER=${{matrix.compiler}} \
-DLIBASSERT_DESIRED_CXX_STANDARD="${{matrix.cxx_version}}"
make -j
build-macos:
runs-on: macos-14
Expand All @@ -33,6 +33,7 @@ jobs:
matrix:
compiler: [g++-12, clang++]
c_compiler: [g++-12, clang++]
cxx_version: [ cxx_std_17, cxx_std_20 ]
target: [Debug, Release]
steps:
- uses: actions/checkout@v2
Expand All @@ -42,14 +43,16 @@ jobs:
cd build
cmake .. \
-DCMAKE_BUILD_TYPE=${{matrix.target}} \
-DCMAKE_CXX_COMPILER=${{matrix.compiler}}
-DCMAKE_CXX_COMPILER=${{matrix.compiler}} \
-DLIBASSERT_DESIRED_CXX_STANDARD="${{matrix.cxx_version}}"
make -j
build-windows:
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
compiler: [cl, clang++]
cxx_version: [ cxx_std_17, cxx_std_20 ]
target: [Debug, Release]
steps:
- uses: actions/checkout@v2
Expand All @@ -62,13 +65,15 @@ jobs:
cmake .. `
-DCMAKE_BUILD_TYPE=${{matrix.target}} `
-DCMAKE_CXX_COMPILER=${{matrix.compiler}} `
-DLIBASSERT_DESIRED_CXX_STANDARD="${{matrix.cxx_version}}" `
msbuild .\libassert.sln
build-mingw:
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
compiler: [g++]
cxx_version: [ cxx_std_17, cxx_std_20 ]
target: [Debug, Release]
steps:
- uses: actions/checkout@v2
Expand All @@ -81,5 +86,6 @@ jobs:
cmake .. `
-DCMAKE_BUILD_TYPE=${{matrix.target}} `
-DCMAKE_CXX_COMPILER=${{matrix.compiler}} `
-DLIBASSERT_DESIRED_CXX_STANDARD="${{matrix.cxx_version}}" `
"-GUnix Makefiles"
make -j
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
.vs
.vscode
.cache
.idea
scratch
build*
cmake-build-*
__pycache__
compile_commands.json
CMakeUserPresets.json
21 changes: 16 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ include(cmake/PreventInSourceBuilds.cmake)
# used to support find_package
set(package_name "libassert")


# create base project
project(
libassert
Expand Down Expand Up @@ -87,6 +88,7 @@ target_sources(
${target_name} PRIVATE
# include
include/libassert/assert.hpp
include/libassert/platform.hpp
)

# add /src files to target
Expand Down Expand Up @@ -152,11 +154,20 @@ target_include_directories(
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
)

# require C++17 support
target_compile_features(
${target_name}
PUBLIC cxx_std_17
)
# If the user has not defined a C++ standard, default to C++17
if (NOT DEFINED LIBASSERT_DESIRED_CXX_STANDARD)
target_compile_features(
${target_name}
PUBLIC cxx_std_17
)
message(STATUS "libassert: Using cxx_std_17 for target ${target_name}")
else()
target_compile_features(
${target_name}
PUBLIC ${LIBASSERT_DESIRED_CXX_STANDARD}
)
message(STATUS "libassert: Using ${LIBASSERT_DESIRED_CXX_STANDARD} for target ${target_name}")
endif()

if(LIBASSERT_SANITIZER_BUILD)
add_compile_options(-fsanitize=address)
Expand Down
127 changes: 39 additions & 88 deletions include/libassert/assert.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,9 @@
#include <expected>
#endif

#if defined(_MSVC_LANG) && _MSVC_LANG < 201703L
#error "libassert requires C++17 or newer"
#elif !defined(_MSVC_LANG) && __cplusplus < 201703L
#pragma error "libassert requires C++17 or newer"
#endif
#include "libassert/platform.hpp"

#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
#if LIBASSERT_STD_VER >= 20
#include <compare>
#endif

Expand All @@ -56,81 +52,6 @@
// Block comments are used to create some visual separation and try to break the library into more manageable parts.
// I've tried as much as I can to keep logically connected parts together but there is some bootstrapping necessary.

// =====================================================================================================================
// || Preprocessor stuff ||
// =====================================================================================================================

#ifdef _WIN32
#define LIBASSERT_EXPORT_ATTR __declspec(dllexport)
#define LIBASSERT_IMPORT_ATTR __declspec(dllimport)
#else
#define LIBASSERT_EXPORT_ATTR __attribute__((visibility("default")))
#define LIBASSERT_IMPORT_ATTR __attribute__((visibility("default")))
#endif

#ifdef LIBASSERT_STATIC_DEFINE
#define LIBASSERT_EXPORT
#define LIBASSERT_NO_EXPORT
#else
#ifndef LIBASSERT_EXPORT
#ifdef libassert_lib_EXPORTS
/* We are building this library */
#define LIBASSERT_EXPORT LIBASSERT_EXPORT_ATTR
#else
/* We are using this library */
#define LIBASSERT_EXPORT LIBASSERT_IMPORT_ATTR
#endif
#endif
#endif

#define LIBASSERT_IS_CLANG 0
#define LIBASSERT_IS_GCC 0
#define LIBASSERT_IS_MSVC 0

#if defined(__clang__)
#undef LIBASSERT_IS_CLANG
#define LIBASSERT_IS_CLANG 1
#elif defined(__GNUC__) || defined(__GNUG__)
#undef LIBASSERT_IS_GCC
#define LIBASSERT_IS_GCC 1
#elif defined(_MSC_VER)
#undef LIBASSERT_IS_MSVC
#define LIBASSERT_IS_MSVC 1
#include <iso646.h> // alternative operator tokens are standard but msvc requires the include or /permissive- or /Za
#else
#error "Libassert: Unsupported compiler"
#endif

#if LIBASSERT_IS_CLANG || LIBASSERT_IS_GCC
#define LIBASSERT_PFUNC __extension__ __PRETTY_FUNCTION__
#define LIBASSERT_ATTR_COLD [[gnu::cold]]
#define LIBASSERT_ATTR_NOINLINE [[gnu::noinline]]
#define LIBASSERT_UNREACHABLE_CALL __builtin_unreachable()
#else
#define LIBASSERT_PFUNC __FUNCSIG__
#define LIBASSERT_ATTR_COLD
#define LIBASSERT_ATTR_NOINLINE __declspec(noinline)
#define LIBASSERT_UNREACHABLE_CALL __assume(false)
#endif

#if LIBASSERT_IS_MSVC
#define LIBASSERT_STRONG_EXPECT(expr, value) (expr)
#elif defined(__clang__) && __clang_major__ >= 11 || __GNUC__ >= 9
#define LIBASSERT_STRONG_EXPECT(expr, value) __builtin_expect_with_probability((expr), (value), 1)
#else
#define LIBASSERT_STRONG_EXPECT(expr, value) __builtin_expect((expr), (value))
#endif

// deal with gcc shenanigans
// at one point their std::string's move assignment was not noexcept even in c++17
// https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
#if defined(_GLIBCXX_USE_CXX11_ABI)
// NOLINTNEXTLINE(misc-include-cleaner)
#define LIBASSERT_GCC_ISNT_STUPID _GLIBCXX_USE_CXX11_ABI
#else
// assume others target new abi by default - homework
#define LIBASSERT_GCC_ISNT_STUPID 1
#endif

// always_false is just convenient to use here
#define LIBASSERT_PHONY_USE(E) ((void)libassert::detail::always_false<decltype(E)>)
Expand All @@ -143,13 +64,6 @@
#pragma warning(disable: 4251; disable: 4275)
#endif

#if LIBASSERT_IS_GCC || __cplusplus >= 2020002L
// __VA_OPT__ needed for GCC, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=44317
#define LIBASSERT_VA_ARGS(...) __VA_OPT__(,) __VA_ARGS__
#else
// clang properly eats the comma with ##__VA_ARGS__
#define LIBASSERT_VA_ARGS(...) , ##__VA_ARGS__
#endif

// =====================================================================================================================
// || Core utilities ||
Expand Down Expand Up @@ -1849,8 +1763,45 @@ namespace libassert {
#define assert_val(expr, ...) LIBASSERT_INVOKE_VAL(expr, true, true, "assert_val", assertion, , __VA_ARGS__)
#endif

// Wrapper macro to allow support for C++26's user generated static_assert messages.
// The backup message version also allows for the user to provide a backup version that will
// be used if the compiler does not support user generated messages.
// More info on user generated static_assert's
// can be found here: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2741r1.pdf
//
// Currently the functionality works as such. If we are in a C++26 environment, the user generated message will be used.
// If we are not in a C++26 environment, then either the static_assert will be used without a message or the backup message.
// TODO: Maybe give these a better name? Ideally one that is shorter and more descriptive?
// TODO: Maybe add a helper to make passing user generated static_assert messages easier?
#if defined(__cpp_static_assert) && __cpp_static_assert >= 202306L
#ifdef LIBASSERT_LOWERCASE
#define libassert_user_static_assert(cond, constant) static_assert(cond, constant)
#define libassert_user_static_assert_backup_msg(cond, msg, constant) static_assert(cond, constant)
#define user_static_assert(cond, constant) static_assert(cond, constant)
#define user_static_assert_backup_msg(cond, msg, constant) static_assert(cond, constant)
#else
#define LIBASSERT_USER_STATIC_ASSERT(cond, constant) static_assert(cond, constant)
#define LIBASSERT_USER_STATIC_ASSERT_BACKUP_MSG(cond, msg, constant) static_assert(cond, constant)
#define USER_STATIC_ASSERT(cond, constant) static_assert(cond, constant)
#define USER_STATIC_ASSERT_BACKUP_MSG(cond, msg, constant) static_assert(cond, constant)
#endif
#else
#ifdef LIBASSERT_LOWERCASE
#define libassert_user_static_assert(cond, constant) static_assert(cond)
#define libassert_user_static_assert_backup_msg(cond, msg, constant) static_assert(cond, msg)
#define user_static_assert(cond, constant) static_assert(cond)
#define user_static_assert_backup_msg(cond, msg, constant) static_assert(cond, msg)
#else
#define LIBASSERT_USER_STATIC_ASSERT(cond, constant) static_assert(cond)
#define LIBASSERT_USER_STATIC_ASSERT_BACKUP_MSG(cond, msg, constant) static_assert(cond, msg)
#define USER_STATIC_ASSERT(cond, constant) static_assert(cond)
#define USER_STATIC_ASSERT_BACKUP_MSG(cond, msg, constant) static_assert(cond, msg)
#endif
#endif


#endif // LIBASSERT_HPP

// Intentionally done outside the include guard. Libc++ leaks `assert` (among other things), so the include for
// assert.hpp should go after other includes when using -DLIBASSERT_LOWERCASE.
#ifdef LIBASSERT_LOWERCASE
Expand Down
Loading
Loading