Giter Site home page Giter Site logo

manu343726 / siplasplas Goto Github PK

View Code? Open in Web Editor NEW
195.0 14.0 27.0 12.97 MB

A library for C++ reflection and introspection

Home Page: https://manu343726.github.io/siplasplas

License: MIT License

Python 7.19% CMake 4.10% C++ 79.90% C 8.74% Shell 0.07%
reflection libclang c-plus-plus

siplasplas's Introduction

siplasplas Build Status Build status Documentation GitHub issues Open

A library for C++ reflection and introspection

Features

Reflection metadata

All reflection metadata is processed by DRLParser, a python script that takes input about a proejct (Compilation options, include dirs, etc) and scans the project headers, generating C++ header files with the reflection information of the corresponding input header. All generated code is C++11 compatible.

CMake integration

Users should not worry about DRLParser and its input, a set of cmake scripts is given to simplify reflection in user projects. Just include siplasplas.cmake and invoke configure_siplasplas_reflection() with your target:

add_library(MyLibrary myLib.cpp)

target_include_directories(MyLibrary PUBLIC include/)
target_compile_options(MyLibrary PRIVATE -std=c++11 -Wall)

configure_siplasplas_reflection(MyLibrary)

This will add a custom pre-build target that automatically runs DRLParser and generates reflection metadata headers before building your library.

Static reflection

SIplasplas provides a template-based API to access to static reflection information of user defined types:

// particle.hpp

class Particle
{
public:
    struct Position
    {
        float x, y, z;
    };

    struct Color
    {
        float a, r, g, b;
    };

    enum class State
    {
        Alive,
        Dead
    };

    Position position;
    Color color;
    State state;
};

siplasplas uses a libclang based script to generate C++ code with all the metadata. After running this script, include both the user header and the generated header:

#include <particle.hpp>
#include <reflection/particle.hpp> // Reflection data (generated code)

std::vector<Particle> particles;

std::ostream& operator<<(std::ostream& os, const Particle::Position& position)
{
    using PositionClass = cpp::static_reflection::Class<Particle::Position>;

    os << "{";

    // For each coordinate in the Position class...
    cpp::foreach_type<PositionClass::Fields>([&](auto type)
    {
        using Field = cpp::meta::type_t<decltype(type)>;

        os << Field::spelling() << ": "            // Field name ("x", "y", "z")
           << cpp::invoke(Field::get(), position)  // Field value (Like C++17 invoke with member object ptr)
           << " ";
    });

    return os << "}";
}

std::ostream& operator<<(std::ostream& os, const Particle::Color& color)
{
    using ColorClass = cpp::static_reflection::Class<Particle::Color>;

    os << "{";

    // For each channel in the Color class...
    cpp::foreach_type<ColorClass::Fields>([&](auto type)
    {
        using Field = cpp::meta::type_t<decltype(type)>;

        os << Field::spelling() << ": "             // channel name (r, g, b, ...)
           << cpp::invoke(Field::get(), color)*255  // channel value
           << " ";
    });

    return os << "}";
}

std::ostream& operator<<(std::ostream& os, const Particle::State& state)
{
    // Use static reflection to get the name of the enum value:
    return os << cpp::static_reflection::Enum<Particle::State>::toString(state);
}

int main()
{
    for(const auto& particle : particles)
    {
        std::cout << "position: " << particle.position << std::endl;
        std::cout << "color: " << particle.color << std::endl;
        std::cout << "state: " << particle.state << std::endl;
    }
}

The static reflection API currently supports:

  • User defined class types: Source information, set of public non-static member objects and functions, member types.
  • User defined enumeration types: Set of enum constants values, enum constants names, to/from string methods
  • User defined functions

Dynamic reflection

Siplasplas also supports dynamic reflection in the form of a simple entity based component system:

cpp::dynamic_reflection::Runtime runtime = loadDynamicReflection();

// Get dynamic reflection info of the class ::Particle::Position:
cpp::dynamic_reflection::Class&  positionClass = runtime.class_("Particle").class_("Position");

// Manipulate a particle object using dynamic reflection:
Particle particle;
positionCLass.field_("x").get(particle.position) = 42.0f; // particle.position.x = 42

// You can also create objects dynamically:
auto particle2 = runtime.class_("Particle").create();

// Returned objects are dynamically manipulable too:
particle2["color"]["r"] = 0.5f;

The dynamic reflection API can be used to load APIs from external libraries at runtime in a straightforward way:

int main()
{
    cpp::DynamicLibrary lib{"libmylibrary.so"};
    cpp::dynamic_reflection::Runtimeloader loader{lib};
    cpp::dynamic_reflection::Runtime& runtime = loader.runtime();

    auto myObject = runtime.class_("MyClass").create();

    // Invoke MyClass::function with params 1 and "hello":
    myObject("function")(1, std::string("hello!"));
}

Other features:

Siplasplas offers other features, building blocks for the APIs explained above, including:

  • Type erasure: A module dedicated to type erasure, with classes designed to manipulate type erased functions, member object pointers, and objects.

  • Signals: Siplasplas implements a simple message passing system for inter-thread communication.

  • CMake API: With the ultimate goal of providing the basis for a work in progress runtime C++ compilation module, siplasplas implements a C++ API to configure and build existing CMake projects.

  • Utilities: Dynamic library loading, aligned malloc, assertions, function type introspection, metaprogramming, hashing, etc. Lots of stuff!

Supported compilers

siplasplas has been tested in GCC 5.1/5.2/6.1, Clang 3.6/3.7/3.8, and Visual Studio 2015.

Documentation

Documentation is available here

The documentation is available in Doxygen and Standardese format, each one with multiple versions corresponding to the latest documentation of each siplasplas release and active branch.

Installation

NOTE: siplasplas is a work in progress project subject to changes. We don't currently provide any kind of API or ABI stability guarantee, nor a production-ready installation process. The following instructions are to build siplasplas from sources.

TL;DR

You can build siplasplas from sources:

$ git clone https://github.com/Manu343726/siplasplas --recursive
$ cd siplasplas
$ mkdir build
$ cd build
$ cmake ..
$ cmake --build .

Or download the bootstrap cmake script and point it to one of the siplasplas releases:

set(SIPLASPLAS_PACKAGE_URL <url to siplasplas release package>)
set(SIPLASPLAS_INSTALL_DRLPARSER_DEPENDENCIES ON) # Download DRLparser deps with pip
set(SIPLASPLAS_LIBCLANG_VERSION 3.8.0) # libclang version
set(SIPLASPLAS_DOWNLOAD_LIBCLANG ON) # Download and configure libclang automatically

include(bootstrap.cmake)

This will download and configure a siplasplas installation in your buildtree. After including bootstrap.cmake, a FindSiplasplas.cmake module is available in your module path to link against the different siplasplas modules:

find_package(Siplasplas)

target_link_libraries(MyLibrary PUBLIC siplasplas-reflection-dynamic)

The module defines one imported library for each siplasplas module. All inter-module dependencies are already solved.

Prerequisites

  • Python 2.7: The siplasplas relfection engine uses a libclang-based parser witten in python. Python 2.7 and pip for Python 2.7 are neccesary. All dependencies are handled automatically (Seeconfiguration bellow).

  • Mercurial: The Entropia Filesystem Watcher dependency is hosted on bitbucket using Mercurial for source control. Mercurial is needed to download the dependency.

  • Doxygen: Needed only if documentation build is enabled. See configuration bellow.

  • Libclang: Siplasplas will use the libclang library distributed as part of the system clang installation by default, but it can be configured to download and build libclang automatically. See configuration.

Dependencies

All siplasplas dependencies are managed automatically through CMake, users don't have to worry about installing deps. Anyway, here is the list of the thrid party dependencies of siplasplas:

siplasplas also depends on some python modules:

Download and configure the project

Clone the siplasplas repository

$ git clone https://github.com/Manu343726/siplasplas --recursive

Create a build/ directory inside the local repository

$ cd siplasplas
$ mkdir build

Run cmake in the build directory

$ cd build
$ cmake ..

Make sure you installed all the requirements before running cmake, siplasplas configuration may fail if one or more of that requirements is missing.

To build the library, invoke the default build target:

$ cmake --build . # Or just "make" if using Makefiles generator

Configuration

The default cmake invocation will build siplasplas as dynamic libraries (one per module) using the default generator. Also, siplasplas configuration can be modified using some options and variables:

The syntax to pass variables to cmake during configuration is -D<VARIABLE>=<VALUE>, for example:

$ cmake .. -DSIPLASPLAS_VERBOSE_CONFIG=ON

  • CMAKE_BUILD_TYPE: Build type to be used to build the project (Debug, Release, etc). Set to Debug by default.

  • SIPLASPLAS_VERBOSE_CONFIG: Configure siplasplas using detailed output. OFF by default.

  • SIPLASPLAS_LIBRARIES_STATIC: Build static libraries. FALSE by default.

  • SIPLASPLAS_BUILD_EXAMPLES: Build siplasplas examples in addition to libraries. OFF by default.

  • SIPLASPLAS_BUILD_TESTS: Build siplasplas unit tests. OFF by default.

  • SIPLASPLAS_BUILD_DOCS: Generate targets to build siplasplas documentation. OFF by default.

  • SIPLASPLAS_INSTALL_DRLPARSER_DEPENDENCIES: Install reflection parser python dependencies. ON by default. This needs pip version 2.7 installled. Dependencies can be manually installed too, there's is a requirements.txt file in <siplasplas sources>/src/reflection/parser/. The requirements file doesn't cover the clang dependency, you must install the clang package with the same version of your installed libclang. For example, given:

    $ clang --version
    clang version 3.8.0 (tags/RELEASE_380/final)
    ...

    you must install clang==3.8.0 package for Python 2.7.

  • SIPLASPLAS_DOWNLOAD_LIBCLANG: Download libclang from LLVM repository. If enabled, siplasplas will download LLVM+Clang version ${SIPLASPLAS_LIBCLANG_VERSION} from the LLVM repositories. This overrides SIPLASPLAS_LIBCLANG_INCLUDE_DIR, SIPLASPLAS_LIBCLANG_SYSTEM_INCLUDE_DIR, and SIPLASPLAS_LIBCLANG_LIBRARY variables. OFF by default.

  • SIPLASPLAS_LIBCLANG_VERSION: Version of libclang used by the reflection parser. Inferred from the installed clang version by default.

    NOTE: siplasplas has been tested with libclang 3.7 and 3.8 only. siplasplas sources use C++14 features, a clang version with C++14 support is needed. Actually, the siplasplas configuration uses -std=c++14 option, which limits the range of supported versions.

  • SIPLASPLAS_LIBCLANG_INCLUDE_DIR: Path to the LLVM includes. When building docs, Standardese tool is built using this configuraton too. Inferred by default.

  • SIPLASPLAS_LIBCLANG_SYSTEM_INCLUDE_DIR: Path to the installed clang includes. When building docs, Standardese tool is built using this configuraton too. Inferred by default.

  • SIPLASPLAS_LIBCLANG_LIBRARY: Path to the libclang library. When building docs, Standardese tool is built using this configuraton too. Inferred by default.

Acknowledgements

Many thanks to:

  • Jonathan "foonathan" Müller, as always
  • George "Concepticide" Makrydakis, for feedback, debates, and "Guys, what the fuck is gitter?"
  • Diego Rodriguez Losada, for feedback, palmeritas, and blue boxes
  • Asier González, for holding on for six months in my C++ course, which eventually became this project
  • To all my ByThech WM&IP team mates, for having to suffer me saying "this with reflection would be so easy!" every single day, and specifically to Javier Martín and Antonio Pérez for feedback
  • All my twitter followers, still there even with docens of tweets a day about reflection! Seriously, some of the best people of the C++ community are there and give me a lot of feedback and ideas
  • Jens Weller and the Fortune God, thanks for accepting my Meeting C++ 2016 talk about siplasplas

License

siplasplas project is released under the MIT open source license. This license applies to all C++ sources, CMake scripts, and any other file except explicitly stated.

siplasplas's People

Contributors

alvarber avatar blorente avatar manu343726 avatar manusharded avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

siplasplas's Issues

Fix libclang pip package version

Clang 3.8 was released two weeks ago, and the python libclang bindings package was updated accordingly. This broke our reflection CI builds since I just wrote clang (Without version) as a requirement in the requirements.txt file, which downloads the latest version.

The requirement should be fixed to the clang version installed in the system

Variant internal layout and ctti::type_id_t

There are some redditors complaining about fixed storage of ctti::detail::string (The type that stores type names at compile-time as part of ctti::type_id_t). This actually affects cpp::Variant too since it uses too much space for the usual type names we have in a variant (int, char, Entity, etc. ctti::detail::string length is 256 by default IIRC).

See comments here: https://www.reddit.com/r/programming/comments/3we1fy/getting_the_type_of_a_template_argument_as_string/?ref=share&ref_source=link

Implement cpp::DynamicLibrary on Windows

As part of Visual Studio fixes I've moved OS API specifics into private functions of dynamiclibrary.cpp, but current windows implementation just throw.

We should implement dynamic library loading on WIndows using LoadLibrary() API.

Documentation

Alternatives?

  • Doxygen + github pages?
  • Markdown/sphinx + readthedocs?
  • @foonathan's Next Great Project?

Any class

Any must extend SimpleAny functionality by adding support for runtime-injectable methods and properties.

An example:

class MyClass
{
public:
    void f();
};

MyOherClass
{
public:
    void g(int i);
    int i = 42;
};

Any createObject(const MyClass& myClass)
{
    Any any{myClass};

    any("f") = &MyClass::f;

    return any;
}

Any createObject(const MyOtherClass& myOtherClass)
{
    Any any{myOtherClass};

    any("g") = &MyOtherClass::g;
    any["i"] = &MyOtherClass::i;

    return any;
}

std::vector<Any> objects = {
    createObject(MyClass()),
    createObject(MyOtherClass())
};

Automatically deploy packages

Last changes on reflection-demangling branch add library packaging setup (built libraries, headers, built examples, and examples sources are packaged), and automatic packaging as part of CI builds. Deploy is missing, we need github credentials to deploy to github releases.

Here are the github deploy to github docs: https://docs.travis-ci.com/user/deployment/releases/

I prefer the user/password approach, it's simpler than getting access tokens.

Ping @AlvarBer

Update the README

Update the readme with the instructions already shown in the wwebsite main page

Fix style of doxygen template parameters

I'm not sure what class the HTML uses for template declarations. What I want is to have template<typename T> and that kind of stuff to have the same style of the function declarations

Could not find executable test_variant

After trying to compile the project as we did today in class, using the same commands, I was not able to build the "test" objective.

The commands I run were:

git clone --recursive https://github.com/GueimUCM/siplasplas.git
cd siplasplas && mkdir build && cd build
cmake ..
make run_example_variant
make test

That last make test threw:

UpdateCTestConfiguration  from :[directory]/siplasplas/build/DartConfiguration.tcl
UpdateCTestConfiguration  from :[directory]/siplasplas/build/DartConfiguration.tcl
Test project [directory]/siplasplas/build
Constructing a list of tests
Done constructing a list of tests
Checking test dependency graph...
Checking test dependency graph end
test 1
    Start 1: variant
Could not find executable [directory]/siplasplas/build/tests/test_variant
Looked in the following places:
[several directories]

1: Test command: 
Unable to find executable: [directory]/siplasplas/build/tests/test_variant
1/2 Test #1: variant ..........................***Not Run   0.00 sec
test 2
    Start 2: linear_allocator
Could not find executable [directory]/siplasplas/build/tests/test_linear_allocator
Looked in the following places:
[several directories]

2: Test command: 
Unable to find executable: [directory]/siplasplas/build/tests/test_linear_allocator
2/2 Test #2: linear_allocator .................***Not Run   0.00 sec

0% tests passed, 2 tests failed out of 2

Total Test time (real) =   0.00 sec

The following tests FAILED:
      1 - variant (Not Run)
      2 - linear_allocator (Not Run)
Errors while running CTest

Testing

The library needs in depth testing for being relyable
and "serious" enough to be published. The following is a list of
priorities, of modules that should be covered by tests:

  1. Static reflection API:
    • Function, Field, Class, Enum. Most of this classes are just
      bridges to the generated code, so it's hard to add tests there. At least
      Enum has some functionality (fromString()/toString()) that needs to be
      tested.
    • At least black-box test the API for occurrencesof types, members, missing fields,
      etc. Check that the API gives right data from a given source.
  2. Dynamic reflection runtime:
    • Unit test Type: Registration, data, etc.
    • Unit test Object.
    • Unit test Object manipulation: Function invocation, assignment, etc.
    • Unit test Object pool. Consider a more relyable pool implementation (Ahem @foonathan).
    • Unit test automatic data registration: By default runtime dynamic reflection data should match
      that collected by static reflection API.

Add cpp::Optional type

Maybe directly wrapping a variant? An unary variant with empty state can be considered an optional

template<typename T>
class Optional
{
    Optional() = default;

    template<typename... Args>
    Optional(Args&&... args) :
        _variant{T{std::forward<Args>(args)...}
    {}

    explicit operator bool() const
    {
        return !_variant.empty();
    }

    const T& get() const
    {
        if(_variant.empty())
            throw std::runtime_error{"Empty optional!"};
        else
            return _variant.get<T>();
    }

    const T* operator->() const
    {
        return &get();
    }

private:
    cpp::Variant<T> _variant;
};

cpp::Optional<int> readInt();

int main()
{
    auto input = readInt();

    if(input)
        std::cout << input.get() << std::endl;
    else
        std::cout << "No input!" << std::endl;
}

plugin example segfault

the plugin reflection example (Loading dynamically reflected types from dynamic libraries at runtime) segfaults at exit. It seems that the dynamic reflection runtime has references to the dynamic library types (cpp::dynamic_reflection::Type::TypeBehavior instances instanced by the dynamic library when registering its types) instanced by the library side. After unloading the library, that types metadata is freed by the executable side.

Solution: Pass a callback to SIPLASPLAS_REFLECTION_LOAD() instead of a reference to the reflection runtime, to ensure registration is run on the executable side.

English README

There is some people coming here from reddit, so an English README file would help.

Check design of cpp::dynamic_reflection::Object tests

This tests mock the 5 special member functions of a class (default ctor,
copy ctor, copy assignment operator, etc) to check whether they are called
or not during different operations of the Object wrapper. The mocks get
pointers to the objects involved in the special member function invocation
to also check if the call was done in the right object.

The problem with this approach is that the mocks call expectations may
fail depending on the behavior of the allocator being used by Type class
(Currently std::free()). The naive approach of comparing pointers to
objects to check for their identity could (and it does) fail if for
whatever reason the allocator returns the same address an
already-deallocated tested object had
. Which is kind of ironic since
that behavior is a sign the allocator is performing well, improving cache
locallity.

In that case, the mock call expectation on a special function would fail,
since these expectectations are set to be called once per tested object
(which is the default behavior of GMock's EXPECT_CALL()).

That said, I didn't find a better alternative for this tests...

Cannot run tests under Cygwin

I have built GCC 5.2.0 under my cygwin setup. Linking of gtest library against test executables fail. Note all rest targets (Both examples and the gtest libraries themselves) are built and linked successfully. It seems that I have not configured correctly stdlibc++ build.

value-semantics concepts

Create concepts to check value semantics operations of a type, i.e.:

  • default construction
  • construction from value of type U
  • copy construction
  • move construction
  • copy asignment
  • move assignment

Also create features to implement value semantics operations of a type, i.e.:

  • default construction
  • construction from value of type U
  • copy construction
  • move construction
  • copy asignment
  • move assignment

dynamic_reflection::Type::toString() relies on expression SFINAE, fails on VS 2015

The check fails and Type::toString()/Type::fromString() invoke cpp::lexical_cast() even if the type has no stream operators overloaded. This is covered by the refactorization being done in feature/typeerasure. It should be handled there with proper isolated checking of stream operators (See cpp::concepts::InputStreamable and cpp::concepts::OutputStreamable traits in that branch), so I will not fix this now as part of fix-windows-support since this is the kind of issue that refactorization is intended to solve.

So, I don't consider this issue part of fix-windows-support but to be reevaluated when feature/typeerasure will be ready. Close it then.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.