Skip to content

wusatosi/exemplar

 
 

Repository files navigation

beman.exemplar: A Beman Library Exemplar

Continuous Integration Tests

beman.exemplar is a minimal C++ library conforming to The Beman Standard. This can be used as a template for those intending to write Beman libraries. It may also find use as a minimal and modern C++ project structure.

Implements: std::identity proposed in Standard Library Concepts (P0898R3).

Usage

std::identity is a function object type whose operator() returns its argument unchanged. std::identity serves as the default projection in constrained algorithms. Its direct usage is usually not needed.

Usage: default projection in constrained algorithms

The following code snippet illustrates how we can achieve a default projection using beman::exemplar::identity:

#include <beman/exemplar/identity.hpp>

namespace exe = beman::exemplar;

// Class with a pair of values.
struct Pair
{
    int n;
    std::string s;

    // Output the pair in the form {n, s}.
    // Used by the range-printer if no custom projection is provided (default: identity projection).
    friend std::ostream &operator<<(std::ostream &os, const Pair &p)
    {
        return os << "Pair" << '{' << p.n << ", " << p.s << '}';
    }
};

// A range-printer that can print projected (modified) elements of a range.
// All the elements of the range are printed in the form {element1, element2, ...}.
// e.g., pairs with identity: Pair{1, one}, Pair{2, two}, Pair{3, three}
// e.g., pairs with custom projection: {1:one, 2:two, 3:three}
template <std::ranges::input_range R,
          typename Projection>
void print(const std::string_view rem, R &&range, Projection projection = exe::identity>)
{
    std::cout << rem << '{';
    std::ranges::for_each(
        range,
        [O = 0](const auto &o) mutable
        { std::cout << (O++ ? ", " : "") << o; },
        projection);
    std::cout << "}\n";
};

int main()
{
    // A vector of pairs to print.
    const std::vector<Pair> pairs = {
        {1, "one"},
        {2, "two"},
        {3, "three"},
    };

    // Print the pairs using the default projection.
    print("\tpairs with beman: ", pairs);

    return 0;
}

Full runnable examples can be found in examples/ (e.g., ./examples/identity_as_default_projection.cpp).

Building beman.exemplar

Dependencies

This project has no C or C++ dependencies.

Build-time dependencies:

  • cmake
  • ninja, make, or another CMake-supported build system
    • CMake defaults to "Unix Makefiles" on POSIX systems

How to install dependencies

Dependencies install exemplar on Ubuntu 24.04
# Install tools:
apt-get install -y cmake make ninja-build

# Toolchains:
apt-get install                           \
  g++-14 gcc-14 gcc-13 g++-14             \
  clang-18 clang++-18 clang-17 clang++-17
Dependencies install exemplar on MAC OS $VERSION
# TODO
Dependencies install exemplar on Windows $VERSION
# TODO

How to build beman.exemplar

This project strives to be as normal and simple a CMake project as possible. This build workflow in particular will work, producing a static libbeman.exemplar.a library, ready to package with its headers:

cmake --workflow --preset gcc-debug
cmake --workflow --preset gcc-release
cmake --install build/gcc-release --prefix /opt/beman.exemplar
Build beman.exemplar (verbose logs)
# Configure beman.exemplar via gcc-debug workflow for development.
$ cmake --workflow --preset gcc-debug
Executing workflow step 1 of 3: configure preset "gcc-debug"

Preset CMake variables:

  CMAKE_BUILD_TYPE="Debug"
  CMAKE_CXX_COMPILER="g++"
  CMAKE_CXX_FLAGS="-fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=leak -fsanitize=undefined"
  CMAKE_CXX_STANDARD="20"

-- The CXX compiler identification is GNU 11.4.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/g++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- The C compiler identification is GNU 11.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Found Python3: /usr/bin/python3.10 (found version "3.10.12") found components: Interpreter
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
-- Configuring done
-- Generating done
-- Build files have been written to: /home/runner/work/exemplar/exemplar/build/gcc-debug

Executing workflow step 2 of 3: build preset "gcc-debug"

[1/14] Building CXX object src/beman/exemplar/CMakeFiles/beman.exemplar.dir/identity.cpp.o
[2/14] Linking CXX static library src/beman/exemplar/libbeman.exemplar.a
[3/14] Building CXX object examples/CMakeFiles/beman.exemplar.examples.identity_direct_usage.dir/identity_direct_usage.cpp.o
[4/14] Linking CXX executable examples/beman.exemplar.examples.identity_direct_usage
[5/14] Building CXX object _deps/googletest-build/googletest/CMakeFiles/gtest_main.dir/src/gtest_main.cc.o
[6/14] Building CXX object src/beman/exemplar/CMakeFiles/beman.exemplar.tests.dir/identity.t.cpp.o
[7/14] Building CXX object _deps/googletest-build/googlemock/CMakeFiles/gmock_main.dir/src/gmock_main.cc.o
[8/14] Building CXX object _deps/googletest-build/googlemock/CMakeFiles/gmock.dir/src/gmock-all.cc.o
[9/14] Building CXX object _deps/googletest-build/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o
[10/14] Linking CXX static library lib/libgtest.a
[11/14] Linking CXX static library lib/libgtest_main.a
[12/14] Linking CXX static library lib/libgmock.a
[13/14] Linking CXX static library lib/libgmock_main.a
[14/14] Linking CXX executable src/beman/exemplar/beman.exemplar.tests

Executing workflow step 3 of 3: test preset "gcc-debug"

Test project /home/runner/work/exemplar/exemplar/build/gcc-debug
    Start 1: IdentityTest.call_identity_with_int
1/4 Test #1: IdentityTest.call_identity_with_int ...........   Passed    0.13 sec
    Start 2: IdentityTest.call_identity_with_custom_type
2/4 Test #2: IdentityTest.call_identity_with_custom_type ...   Passed    0.01 sec
    Start 3: IdentityTest.compare_std_vs_beman
3/4 Test #3: IdentityTest.compare_std_vs_beman .............   Passed    0.01 sec
    Start 4: IdentityTest.check_is_transparent
4/4 Test #4: IdentityTest.check_is_transparent .............   Passed    0.01 sec

100% tests passed, 0 tests failed out of 4

Total Test time (real) =   0.18 sec

# Configure beman.exemplar via gcc-release workflow for direct usage.
$ cmake --workflow --preset gcc-release
Executing workflow step 1 of 3: configure preset "gcc-release"

Preset CMake variables:

  CMAKE_BUILD_TYPE="RelWithDebInfo"
  CMAKE_CXX_COMPILER="g++"
  CMAKE_CXX_FLAGS="-O3"
  CMAKE_CXX_STANDARD="20"

-- The CXX compiler identification is GNU 11.4.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/g++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- The C compiler identification is GNU 11.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Found Python3: /usr/bin/python3.10 (found version "3.10.12") found components: Interpreter
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
-- Configuring done
-- Generating done
-- Build files have been written to: /home/runner/work/exemplar/exemplar/build/gcc-release

Executing workflow step 2 of 3: build preset "gcc-release"

[1/14] Building CXX object src/beman/exemplar/CMakeFiles/beman.exemplar.dir/identity.cpp.o
[2/14] Linking CXX static library src/beman/exemplar/libbeman.exemplar.a
[3/14] Building CXX object examples/CMakeFiles/beman.exemplar.examples.identity_direct_usage.dir/identity_direct_usage.cpp.o
[4/14] Linking CXX executable examples/beman.exemplar.examples.identity_direct_usage
[5/14] Building CXX object _deps/googletest-build/googletest/CMakeFiles/gtest_main.dir/src/gtest_main.cc.o
[6/14] Building CXX object src/beman/exemplar/CMakeFiles/beman.exemplar.tests.dir/identity.t.cpp.o
[7/14] Building CXX object _deps/googletest-build/googlemock/CMakeFiles/gmock_main.dir/src/gmock_main.cc.o
[8/14] Building CXX object _deps/googletest-build/googlemock/CMakeFiles/gmock.dir/src/gmock-all.cc.o
[9/14] Building CXX object _deps/googletest-build/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o
[10/14] Linking CXX static library lib/libgtest.a
[11/14] Linking CXX static library lib/libgtest_main.a
[12/14] Linking CXX static library lib/libgmock.a
[13/14] Linking CXX executable src/beman/exemplar/beman.exemplar.tests
[14/14] Linking CXX static library lib/libgmock_main.a

Executing workflow step 3 of 3: test preset "gcc-release"

Test project /home/runner/work/exemplar/exemplar/build/gcc-release
    Start 1: IdentityTest.call_identity_with_int
1/4 Test #1: IdentityTest.call_identity_with_int ...........   Passed    0.00 sec
    Start 2: IdentityTest.call_identity_with_custom_type
2/4 Test #2: IdentityTest.call_identity_with_custom_type ...   Passed    0.00 sec
    Start 3: IdentityTest.compare_std_vs_beman
3/4 Test #3: IdentityTest.compare_std_vs_beman .............   Passed    0.00 sec
    Start 4: IdentityTest.check_is_transparent
4/4 Test #4: IdentityTest.check_is_transparent .............   Passed    0.00 sec

100% tests passed, 0 tests failed out of 4

Total Test time (real) =   0.01 sec

# Run examples.
$ build/gcc-release/examples/beman.exemplar.examples.identity_direct_usage
2024
Install beman.exemplar (verbose logs)
# Install build artifacts from `build` directory into `opt/beman.exemplar` path.
$ cmake --install build/gcc-release --prefix /opt/beman.exemplar
-- Install configuration: "RelWithDebInfo"
-- Up-to-date: /opt/beman.exemplar/lib/libbeman.exemplar.a
-- Up-to-date: /opt/beman.exemplar/include/beman/exemplar/identity.hpp


# Check tree.
$ tree /opt/beman.exemplar
/opt/beman.exemplar
├── include
│   └── beman
│       └── exemplar
│           └── identity.hpp
└── lib
    └── libbeman.exemplar.a

4 directories, 2 files
Disable tests build

To build this project with tests disabled (and their dependencies), simply use BEMAN_EXEMPLAR_BUILD_TESTING=OFF as documented in upstream CMake documentation:

cmake -B build -S . -DBEMAN_EXEMPLAR_BUILD_TESTING=OFF

Integrate beman.exemplar into your project

Use beman.exemplar directly from C++

If you want to use beman.exemplar from your project, you can include beman/exemplar/*.hpp files from your C++ source files

#include <beman/exemplar/identity.hpp>

and directly link with libbeman.exemplar.a

# Assume /opt/beman.exemplar staging directory.
$ c++ -o identity_usage examples/identity_usage.cpp \
    -I /opt/beman.exemplar/include/ \
    -L/opt/beman.exemplar/lib/ -lbeman.exemplar
Use beman.exemplar directly from CMake

For CMake based projects, you will need to use the beman.exemplar CMake module to define the beman::exemplar CMake target:

find_package(beman.exemplar REQUIRED)

You will also need to add beman::exemplar to the link libraries of any libraries or executables that include beman/exemplar/*.hpp in their source or header file.

target_link_libraries(yourlib PUBLIC beman::exemplar)
Use beman.exemplar from other build systems

Build systems that support pkg-config by providing a beman.exemplar.pc file. Build systems that support interoperation via pkg-config should be able to detect beman.exemplar for you automatically.

Contributing

Please do! Issues and pull requests are appreciated.

About

Example Beman project

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • CMake 43.0%
  • C++ 42.2%
  • Dockerfile 13.9%
  • Shell 0.9%