packages feed

hoppy-docs 0.8.0 → 0.9.0

raw patch · 3 files changed

+120/−63 lines, 3 filesdep ~basedep ~hoppy-generatordep ~hoppy-runtimesetup-changedPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base, hoppy-generator, hoppy-runtime

API changes (from Hackage documentation)

Files

Setup.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2024 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by
hoppy-docs.cabal view
@@ -1,12 +1,12 @@ name: hoppy-docs-version: 0.8.0+version: 0.9.0 synopsis: C++ FFI generator - Documentation-homepage: http://khumba.net/projects/hoppy+homepage: https://khumba.net/projects/hoppy license: AGPL-3 license-file: LICENSE author: Bryan Gardiner <bog@khumba.net> maintainer: Bryan Gardiner <bog@khumba.net>-copyright: Copyright 2015-2021 Bryan Gardiner+copyright: Copyright 2015-2024 Bryan Gardiner category: Foreign build-type: Simple cabal-version: 1.24@@ -19,10 +19,10 @@   exposed-modules:       Foreign.Hoppy.Documentation.UsersGuide   build-depends:-      base >=4.7 && <5+      base >=4.10 && <5     , haskell-src >=1.0 && <1.1-    , hoppy-generator >=0.8 && <0.9-    , hoppy-runtime >=0.8 && <0.9+    , hoppy-generator >=0.9 && <0.10+    , hoppy-runtime >=0.9 && <0.10   hs-source-dirs: src   ghc-options: -W -fwarn-incomplete-patterns -fwarn-unused-do-bind   default-language: Haskell2010
src/Foreign/Hoppy/Documentation/UsersGuide.hs view
@@ -1,6 +1,6 @@ -- This file is part of Hoppy. ----- Copyright 2015-2021 Bryan Gardiner <bog@khumba.net>+-- Copyright 2015-2024 Bryan Gardiner <bog@khumba.net> -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU Affero General Public License as published by@@ -28,6 +28,9 @@   -- ** Project setup   -- $getting-started-project-setup +  -- ** Alternate project structures+  -- $getting-started-alternate-project-structures+   -- ** A first binding   -- $getting-started-a-first-binding @@ -129,21 +132,16 @@ code generators, some runtime support for Haskell bindings, and interface definitions for the C++ standard library. -Bindings using Hoppy have three Cabal packages:--- A Haskell generator program (in @\/myproject-generator@) that knows the-interface definition and generates code for the next two parts.--- A C++ library (in @\/myproject-cpp@) that gets compiled into a shared object-containing the C++ half of the bindings.+Bindings using Hoppy can be structured many different ways, but the recommended+approach is to use two Cabal packages: -- A Haskell library (in @\/myproject@) that links against the C++ library and-exposes the bindings.+- A \"generator\" library that contains all of the binding definitions for your+  project, and links to @hoppy-generator@ to be able to do code generation. -The path names are suggested subdirectories of a project, and are used in this-document, but are not required.  Despite the second being called a C++ library-and containing C++ code, all three of these are Haskell packages, built using-Cabal.+- The actual binding library that includes the C++ and Haskell code generated by+  the previous package, as well as any other wrapper logic you want, and does+  the actual linking to C++.  This package calls the generator library early in+  the build process, via a custom @Setup.hs@.  -} {- $getting-started@@ -154,39 +152,85 @@ {- $getting-started-project-setup  To set up a new Hoppy project, it's recommended to start with the template-project in the @example\/@ directory.  You can find this in the Hoppy source-repository:+project in the @examples\/two-package-example\/@ directory.  You can find this+in the Hoppy source repository: -<https://gitlab.com/khumba/hoppy/tree/master/example>+<https://git.sr.ht/~khumba/hoppy/tree/master/item/examples/two-package-example> -This is a minimal project that defines a C++ function to reverse a @std::string@,-exposes that to Haskell via a library, and provides a demo program that uses the-library.  The @example\/install.sh@ script simply compiles and installs the-generator, C++, and Haskell packages in turn.+This is a minimal project that defines a C++ function to reverse a+@std::string@, exposes that to Haskell via a library, and provides a demo+program that uses the library.  The C++ standard library is linked to, but you+can link to any C++ library you need this way. -The generator package specifies the C++ interface to be exposed, using the-functions and data types described in the rest of this section.+The bundled example program reads lines from standard input, reverses the+character in each one, and writes the result back to standard output.  Calling+it like so produces the following output: -The C++ package is mostly empty, primarily containing a @Setup.hs@ file that-invokes Hoppy build hooks, and any C++ code of our own that we want to bind to,-beyond what's provided by third-party libraries.  For this example, we add a-@reverse()@ function and make use of the C++ standard library.  If we were-writing a binding for an existing third-party library, we might not need to-provide any C++ code ourselves here.  When building this package, Hoppy-generates some C++ code and then relies on a Makefile we provide for linking it-together with any code we provided (see @example\/example-cpp\/Makefile@).  If-you are relying on a system library, you can link to it in the Makefile.+> (echo one; echo two; echo three) | cabal v2-run hoppy-two-package-example+>+> eno+> owt+> eerht -The Haskell package is even more empty than the C++ one.  It contains a similar-@Setup.hs@ to invoke Hoppy.  Nothing else is included in the package's library,-although you are free to add your own Haskell modules.  The executable ties-everything together by calling the C++ code.  It reverses the characters of each-input line it sees.+There are two Cabal packages in this example.  The first, called+@hoppy-two-package-example-generator@, specifies the C++ interface to be+exposed, using the functions and data types described in the rest of this+section, from the @hoppy-generator@ package.  All this package does is expose a+top-level @Interface@ object to be used by the next package. -To publish this project, one would upload all three packages to Hackage.  (But-make sure to rename it first!)+The second package, called @hoppy-two-package-example@, is the actual bindings.+Consumers of your bindings will depend on this package (and @hoppy-runtime@+which contains commonly-needed support functions) and ignore the generator+package. +There are a few parts to the binding package.  The first are the C++ files+@example\/cpp\/utils.{cpp,hpp}@ which contain the @reverse()@ function that we+are wrapping.  This demonstrates how to provide additional C++ code in your+bindings, although this is not required if you have no logic to add.++The @hoppy-two-package-example.cabal@ file for this project uses @build-type:+Custom@ with a nondefault @Setup.hs@.  Our @Setup.hs@ invokes the generator at+configure time, to generate C++ and Haskell glue code that can talk to each+other.  To do this, we need the @custom-setup@ block to declare that our+@Setup.hs@ needs our generator, along with @hoppy-generator@ and+@hoppy-runtime@.  The generator will produce two modules, which are declared in+the library's @exposed-modules@ and @autogen-modules@ lists.  The generator also+produces some C++ files that we need to include under @cxx-sources@ (albeit+indirectly).  In the @Setup.hs@ itself, rather than using the standard @main =+defaultMain@, we call into the Hoppy generator, passing in the interface+definition, plus some directory names so that Hoppy knows where to find files.++To publish this project, one would upload both packages to Hackage.  Make sure+to rename them first!+ -}+{- $getting-started-alternate-project-structures++It is also possible to structure your bindings as one, or three, packages.  One+package can be achieved by writing the Hoppy interface definitions directly in+the @Setup.hs@ of the binding package.  The downside to this is that the entire+interface must be specified in one file, but this may be suitable for small+APIs.++Three packages can be used if the C++ building infrastructure provided by+@cxx-sources@ isn't enough, and you need to use a more general build system+(make, CMake, etc.) and have full control over the build process.  Here, the+binding package is split into two separate C++ and Haskell packages.  The C+++binding package uses @Setup.hs@ to generate C++ code and run the desired C+++build process, and install the resulting shared object, but contains no Haskell+modules.  The Haskell binding package then contains the generated Haskell code,+but only links to the shared objects from the C++ binding package.++Using three packages is the traditional way to use Hoppy and worked before Cabal+added @cxx-sources@.  It's the method used by Qtah, which needs significant+custom build logic, but also demonstrates what can be done, for example dynamic+version detection of Qt, and further wrapping of all generated modules to make+identifiers shorter, add typeclass instances, etc.++Examples containing one, two, and three packages are present in the @examples/@+directory of the Hoppy repository.++-} {- $getting-started-a-first-binding  A complete C++ API is specified using Haskell data structures in@@ -350,14 +394,25 @@ -} {- $getting-started-types -Let's take a break from @std::string@ for a moment and talk about how we-represent data types in Hoppy.+Let's take a break from @std::string@ and talk about how we represent data types+in Hoppy.  All C++ types are represented with the 'Type' data type, values of which are in the "Foreign.Hoppy.Generator.Types" module.  This includes primitive numeric types, object types, function types, pointers and references, @void@, the const-qualifier, etc.+qualifier, etc.  'Type's tell Hoppy how to perform conversions when Haskell code+calls C++ code or vice versa. +The association between C++ types and 'Type's is not necessarily one-to-one.+For a single C++ type, it is perfectly okay to use 'Type's that specify+different conversions in different situations.  A simple example would be two+different functions that return pointers to objects of a particular class, but+one function transfers ownership to the caller, so using 'toGcT' would make+sense.  A more complicated example would be a function that returns an object+pointer, where in one situation you want to pass the pointer back to Haskell+directly, and in another situation you want the object converted to a Haskell+record.+ A Hoppy 'Type' value has a corresponding C++ type, and also what we refer to as a C type, and possibly a Haskell type.  The C++ type is, of course, whatever C++ type the 'Type' structure represents.  The Haskell type is the Haskell data type@@ -812,7 +867,7 @@ And a method binding:  @-'makeFn' "reverse" Nothing 'Nonpure' ['objT' c_string] $ 'objT' c_string+'makeFn' \"reverse\" Nothing 'Nonpure' ['objT' c_string] $ 'objT' c_string @  We get the following Haskell function and instance:@@ -1008,7 +1063,7 @@ allocate our G instance on the heap, and create a second class F that holds a @shared_ptr\<G>@ and whose @operator()@ calls through to G. -This way, the existance of the F and G objects are invisible to the foreign+This way, the existence of the F and G objects are invisible to the foreign language, and (for now) passing these callbacks back to the foreign language is not supported. @@ -1073,9 +1128,9 @@ alignment :: 'CppEnum' alignment =   'makeAutoEnum' ('ident' \"Alignment\") Nothing 'EnumUnscoped'-  [ "LeftAlign"-  , "CenterAlign"-  , "RightAlign"+  [ \"LeftAlign\"+  , \"CenterAlign\"+  , \"RightAlign\"   ] @ @@ -1363,15 +1418,17 @@ Catching a wildcard (i.e. @catch (...)@) is supported, but no information is available about the caught value. -Implementation-wise, an in-flight C++ exception in Haskell always owns the-object (which is on the heap).  An exception coming from C++ into Haskell (it's-a heap temporary) will be given to the garbage collector.  Hence, for ease of-use, caught exceptions should always be garbage-collected.  Also, when throwing-from Haskell, throwing will always take ownership of the object.  If 'throwCpp'-gets a non-GCed object, then it will be given to the garbage collector; and then-the exception will be thrown as a Haskell exception.  If the exception-propagates out to a callback and back into C++, then a temporary non-GCed copy-will be passed over the gateway, and rethrown as a value object on the C++ side.+Implementation-wise, in-flight C++ exceptions in Haskell are always owned by the+throwing machinery, and the exception object always lives on the C++ heap.  An+exception being thrown from C++ into Haskell (a heap temporary) will be given to+the garbage collector, for ease of use, so do not delete it manually.++In the other direction, when throwing a C++ exception from Haskell, throwing+again takes ownership of the object.  If 'throwCpp' gets a non-GCed object, then+it will be given to the garbage collector; and then the exception will be thrown+as a Haskell exception.  If the exception propagates out to a callback and back+into C++, then a temporary non-GCed copy will be passed over the gateway, and+rethrown as a value object on the C++ side.  In the above strategy, when throwing an exception from Haskell that propagates to C++, it is wasteful to make the thrown object GCed, just to have to create a