Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/wavewave/fficxx
Haskell-C++ Foreign Function Interface Generator
https://github.com/wavewave/fficxx
cplusplus ffi haskell haskell-libraries wrapper
Last synced: 6 days ago
JSON representation
Haskell-C++ Foreign Function Interface Generator
- Host: GitHub
- URL: https://github.com/wavewave/fficxx
- Owner: wavewave
- Created: 2011-11-12T05:39:10.000Z (almost 13 years ago)
- Default Branch: master
- Last Pushed: 2023-08-30T18:55:32.000Z (about 1 year ago)
- Last Synced: 2024-10-16T05:33:41.867Z (20 days ago)
- Topics: cplusplus, ffi, haskell, haskell-libraries, wrapper
- Language: Haskell
- Homepage:
- Size: 5.63 MB
- Stars: 141
- Watchers: 12
- Forks: 13
- Open Issues: 42
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
What is fficxx?
===============![Build](https://github.com/wavewave/fficxx/actions/workflows/build.yml/badge.svg)
fficxx ("eff fix") is an automatic haskell Foreign Function Interface (FFI) generator to C++.
To use fficxx, you write a Haskell model of the C++ public interfaces and fficxx generates both a C wrapper and associated haskell functions and type classes which reflect specified model of the C++ interfaces. It is currently the user's responsibility to specify a correct model of the C++ interfaces, because fficxx does not presently check for model correctness.
While haskell has a well-specified standard for C FFI, making haskell-C++ FFI is an arbitrary and painful process. Since Object-Oriented Programming (OOP) paradigm and Functional Programming (FP) paradigm are different, automatic translation of C++ libraries to haskell libraries is not a straightforward task. The goal of fficxx is to minimize this disparity and maximize user's convenience by providing familiar interface to the original C++ library as a result.
Public Haskell-C++ binding generated by fficxx are now collected in [fficxx-projects](https://github.com/wavewave/fficxx-projects).
fficxx is separated into generator part and runtime part:
* fficxx : FFI types and binding generator library
* fficxx-runtime : runtime modules needed for various common routinesHaskell packages that are generated from fficxx will be dependent on fficxx-runtime.
In addition, C++ standard library under `std` namespace is being generated as a package from fficxx.
* stdcxx: generated by ./stdcxx-gen/Gen.hsGetting Started
===============fficxx is mainly packaged in nix.
`shell.nix` is for development,
```
nix-shell shell.nix
```
and `use.nix` is for using the generated binding package.
```
nix-shell use.nix
```For all build,
```
nix-build release.nix
```OOP Model in fficxx
===================fficxx generates haskell codes at raw level (C wrapper and haskell foreign pointer that are directly matched with C/C++ types) and at high level (newtype wrapper for raw level pointer and haskell typeclasses reflecting OOP class hierarchy). Haskell does not have a concept of subtyping, i.e. we do not provide any easy way to create a new subclass and overload member functions from existing classes on haskell side. However, fortunately, one can describe the OOP subclass relationship using a typeclass interface as a contract for a class `b` to be equal to or a subclass of `a`. In a sense, typeclasses are Interface Definition Language (IDL) for describing OOP classes. Thus, a C++ class is represented by both haskell concrete type (for a C++ class itself) and typeclass (a set of classes that can be equal to or a subclass of the C++ class).
Assuming that there is a C++ class `A`. fficxx generates a haskell type `A`. This haskell type `A` is nothing but a newtype wrapping `ForeignPtr` tagged by `RawA`.
```
data RawAnewtype A = A (ForeignPtr RawA)
```
`RawA` exists only for the purpose of a phantom type to be used as tags for `Ptr` in FFI imports (`foreign import` statements.) When programming with fficxx-generated code at high level, programmers should seldom encounter `Raw` types. An instance object of C++ class `A` is a value of haskell type `A`. To create an instance, fficxx provides a smart constructor (`newA`) if specified with a corresponding constructor.Therefore, one can create an instance from a concrete haskell type, and pass it to any functions which needs them. On Haskell side, member functions of a C++ class are nothing but functions whose first argument is the same as the corresponding haskell type to the class. For example, if the class `A` has a member function `foo` of signature `void A::foo( int param )`, then fficxx generates a high level function
```
foo :: A -> CInt -> IO ()
```
which is a wrapper for a raw level FFI call defined by
```
foriegn import ccall "A_foo" c_foo :: Ptr RawA -> CInt -> IO ()
```
where `A_foo` is a generated C shim function for `A::foo`. So one can translate the following C++ code
```
A* a = new A();
a->foo(3);
```
to the haskell code (in do-block of IO monad)
```
do a <- newA
foo a 3
```
Haskell type `A` can be used in the arbitrary argument position. Assume there is another member function `bar` of `A` which takes an object of `A` as an argument like `void A::bar( A* a )`. Then, we have
```
bar :: A -> A -> IO ()
```
for which `x->bar(y)` (`x`,`y` are of class `A`) corresponds to `bar x y`.In this example, the C++ class `A` may have the following declaration:
```
class A
{
public:
A();
virtual void foo( int );
virtual void bar( A* );
};
```
To reflect subtype relations, fficxx creates an interface typeclass `IA` for `A`, which is defined as
```
class IA a where
foo :: a -> CInt -> IO ()
bar :: (IA b) => a -> b -> IO ()
```
which declares all C++ virtual functions as members. Then, haskell type `A` is a typeclass instance of `IA`:
```
instance IA A where
-- foo :: A -> CInt -> IO ()
foo = ...
-- bar :: (IA b) => A -> b -> IO ()
bar = ...
```
so that `foo` and `bar` functions we considered in the above example were actually defined in the `IA` instance definition of A.
Note that the type signature of `bar` allows generic typeclass instances of `IA` as the argument (paraterized by `b`).Now consider another C++ class `B` which is a subclass of `A`:
```
class B : public A
{
public:
B();
virtual int baz() ;
}
```
Again, we will have a concrete haskell type `B` and an object of `B` will be created as a value from the `newB` constructor function.
A typeclass `IB` is also generated as well, and it reflects the inheritance relationship for C++ class as constraints:
```
class (IA b) => IB b where
baz :: b -> IO CInt
```
Thanks to the constraints `(IA b) =>` in the declaration, every instance of `IB` must have implementation of `IA`. This is true for `B`, too.
So fficxx generates
```
instance IA B where
foo = ...
bar = ...instance IB B where
baz = ...
```
This instance generation (*implemenation of C++ class*) is automaticaly done by fficxx, but it's not guaranteed for future subclassing. Any type which implements instances of `IA` and `IB` can be regarded as a subclass of `B`, but it's not automatically done as we have in OOP. The scope of fficxx is to generate such implementations only for existing C++ classes.References
==========## C Macro tricks
We use C Macro tricks described in the following:
* http://jhnet.co.uk/articles/cpp_magic
* https://stackoverflow.com/questions/45585903/c-macros-how-to-map-another-macro-to-variadic-arguments
* https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
* https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
* https://stackoverflow.com/questions/3046889/optional-parameters-with-c-macros/3048361#3048361## C++ Template tricks
* https://en.cppreference.com/w/cpp/language/template_argument_deduction
* http://anderberg.me/2016/08/01/c-variadic-templates/
* https://crascit.com/2015/03/21/practical-uses-for-variadic-templates/## C++ Template Peculiarity
* https://stackoverflow.com/questions/2354210/can-a-c-class-member-function-template-be-virtual