From 790c0aa1819ccd73e0d5cb009a6c3459ffeb83a0 Mon Sep 17 00:00:00 2001 From: Colin Kiama Date: Sat, 4 May 2024 21:46:26 +0100 Subject: [PATCH] Create "Writing a VAPI manually" Developer Guide (#30) --- source/developer-guides/bindings.rst | 8 ++ .../bindings/writing-a-vapi-manually.rst | 29 +++++ .../01-00-prerequisites.rst | 20 ++++ .../02-00-getting-started.rst | 8 ++ .../02-01-the-vapi-file.rst | 17 +++ .../02-02-attribution-and-license.rst | 20 ++++ .../02-03-the-ccode-attribute.rst | 14 +++ .../02-04-create-a-root-namespace.rst | 34 ++++++ .../02-05-include-the-c-header-files.rst | 16 +++ .../02-06-symbol-name-translations.rst | 77 ++++++++++++ .../02-07-code-formatting-conventions.rst | 7 ++ .../02-08-documentation-and-valadoc-org.rst | 45 +++++++ .../02-09-the-version-attribute.rst | 25 ++++ .../03-00-using-auto-memory-management.rst | 26 ++++ .../03-01-pointers-in-c.rst | 12 ++ ...-constants-the-stack-and-the-heap-in-c.rst | 32 +++++ ...03-03-the-concept-of-ownership-in-vala.rst | 8 ++ .../03-04-binding-to-c-heap-handnlers.rst | 33 ++++++ ...0-recognizing-vala-semantics-in-c-code.rst | 13 ++ .../04-01-constants.rst | 22 ++++ .../04-02-enums-and-flags.rst | 89 ++++++++++++++ .../04-03-simple-type-structs.rst | 112 ++++++++++++++++++ .../04-04-structs.rst | 50 ++++++++ .../04-05-compact-classes.rst | 82 +++++++++++++ .../04-06-functions.rst | 12 ++ .../04-07-delegates.rst | 24 ++++ ...0-fundamentals-of-binding-a-c-function.rst | 10 ++ ...reference-parameters-and-return-values.rst | 76 ++++++++++++ .../05-02-ownership.rst | 13 ++ .../05-03-nullability.rst | 19 +++ .../05-04-static-methods.rst | 7 ++ ...ng-the-position-of-generated-arguments.rst | 26 ++++ ...es-and-changing-an-argument-s-position.rst | 18 +++ ...apting-a-signature-with-a-vala-wrapper.rst | 6 + .../05-08-variadic-arguments.rst | 10 ++ .../05-09-functions-that-do-not-return.rst | 5 + ...ods-that-change-the-instance-reference.rst | 19 +++ ...ds-that-destroy-the-instance-reference.rst | 26 ++++ .../06-00-adding-vala-friendly-semantics.rst | 11 ++ .../06-01-to-string-methods.rst | 3 + .../06-02-properties.rst | 34 ++++++ .../06-03-collections.rst | 93 +++++++++++++++ ...-function-s-parameter-and-return-types.rst | 8 ++ .../07-01-basic-types.rst | 4 + .../07-02-structs.rst | 45 +++++++ .../07-03-arrays.rst | 47 ++++++++ .../07-04-strings-and-buffers.rst | 8 ++ .../07-05-function-pointers.rst | 34 ++++++ ...6-parameters-of-variable-type-generics.rst | 84 +++++++++++++ .../07-07-pointers.rst | 4 + .../08-00-binding-a-c-struct-s-fields.rst | 10 ++ .../08-01-structs.rst | 4 + .../08-02-pointers-to-structs.rst | 26 ++++ .../08-03-arrays.rst | 59 +++++++++ .../08-04-function-pointers.rst | 68 +++++++++++ .../08-05-unions.rst | 26 ++++ .../09-00-extra-hints.rst | 9 ++ .../10-00-awkward-situations.rst | 10 ++ .../10-01-array-lengths.rst | 42 +++++++ .../10-02-dependently-typed-ownership.rst | 46 +++++++ .../10-03-member-length.rst | 14 +++ .../10-04-owned-array-of-unowned-objects.rst | 3 + .../10-05-shared-context-delgates.rst | 22 ++++ source/developer-guides/index.rst | 8 ++ source/index.rst | 1 + 65 files changed, 1793 insertions(+) create mode 100644 source/developer-guides/bindings.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/01-00-prerequisites.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-01-the-vapi-file.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-02-attribution-and-license.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-03-the-ccode-attribute.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-04-create-a-root-namespace.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-05-include-the-c-header-files.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-06-symbol-name-translations.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-07-code-formatting-conventions.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-08-documentation-and-valadoc-org.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-09-the-version-attribute.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-01-pointers-in-c.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-02-constants-the-stack-and-the-heap-in-c.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-03-the-concept-of-ownership-in-vala.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-04-binding-to-c-heap-handnlers.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-01-constants.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-02-enums-and-flags.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-03-simple-type-structs.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-04-structs.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-05-compact-classes.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-06-functions.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-07-delegates.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-01-out-and-reference-parameters-and-return-values.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-02-ownership.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-03-nullability.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-04-static-methods.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-05-changing-the-position-of-generated-arguments.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-06-default-values-and-changing-an-argument-s-position.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-07-adapting-a-signature-with-a-vala-wrapper.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-08-variadic-arguments.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-09-functions-that-do-not-return.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-10-methods-that-change-the-instance-reference.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-11-methods-that-destroy-the-instance-reference.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics/06-01-to-string-methods.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics/06-02-properties.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics/06-03-collections.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-01-basic-types.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-02-structs.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-03-arrays.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-04-strings-and-buffers.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-05-function-pointers.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-06-parameters-of-variable-type-generics.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-07-pointers.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-01-structs.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-02-pointers-to-structs.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-03-arrays.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-04-function-pointers.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-05-unions.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/09-00-extra-hints.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-01-array-lengths.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-02-dependently-typed-ownership.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-03-member-length.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-04-owned-array-of-unowned-objects.rst create mode 100644 source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-05-shared-context-delgates.rst create mode 100644 source/developer-guides/index.rst diff --git a/source/developer-guides/bindings.rst b/source/developer-guides/bindings.rst new file mode 100644 index 0000000..ac5e2bb --- /dev/null +++ b/source/developer-guides/bindings.rst @@ -0,0 +1,8 @@ +Bindings +======== + +.. toctree:: + :glob: + :maxdepth: 1 + + bindings/* \ No newline at end of file diff --git a/source/developer-guides/bindings/writing-a-vapi-manually.rst b/source/developer-guides/bindings/writing-a-vapi-manually.rst new file mode 100644 index 0000000..f593c6b --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually.rst @@ -0,0 +1,29 @@ +Writing a VAPI Manually +======================= + +This document intends to be a tutorial and reference on how to write a Vala binding to an existing C library. If the library uses GLib, do not follow this document. Instead read :doc:`Generating a VAPI with GObject Introspection `. A library may not follow the GLib coding practices precisely, but it is better to fix the library to work with GObject Introspection than to write a manual binding. + +C programmers are a rather liberal bunch; certain procedures are done in a multitude of ways depending on the mood of the programmer, whereas Vala is much more restricted. This guide cannot possibly cover all possible cases of different APIs written by C programmers. It is your job to understand the C API and present it with Vala-friendly semantics. + +There is a lot of material in this document and that can make it hard to take in at first. A practical approach to working through the tutorial would be to: + +1. | Bind an enum first because enums are easy to test. + + | Once your test gives the expected result you know that the build process works. This means working through the "Getting Started" section and the "Enums and Flags" sub-section. Binding an enum also introduces the idea that there isn't a straight mapping from C to Vala + +2. | Bind the creation and destruction of a compact class next. + + | This means working through the "Using Vala's Automatic Memory Management" section and starting to understand that a struct in C can be bound as either a simple type, a struct or a compact class in Vala. The binding can be tested by looking at the C code produced from a single line in Vala like ``new MyBoundCompactClass ();`` + +3. | Bind methods of the compact class. + + | This is when your binding starts to become useful and it will also give an overview of this document. Once you have an overview the document becomes more of a reference for solving tricky function bindings + +The above assumes that the library is written in an object oriented style of C. A C binding, however, is only made up of structs and functions so understanding that in enough detail is the purpose of the approach. + +.. toctree:: + :glob: + :maxdepth: 1 + :numbered: + + */* \ No newline at end of file diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/01-00-prerequisites.rst b/source/developer-guides/bindings/writing-a-vapi-manually/01-00-prerequisites.rst new file mode 100644 index 0000000..8630629 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/01-00-prerequisites.rst @@ -0,0 +1,20 @@ +Prerequisites +============= + +To write the binding collect the following: + +* a functional copy of the library with headers +* the documentation for the library, if such a thing exists +* the source, if possible +* examples or tutorials that you can use as tests for your binding + +If the library is written in C++, you cannot bind it to Vala unless there is a separate C binding of the C++ library (e.g., LLVM). + +If you are using vim, you may wish to add the following to your .vimrc: + +.. code-block:: vim + + :noremap "gyiwO[CCode (cname = ""gpa")] + +which allows you to insert an attribute to make it easier to rename a function by pressing F8 while your cursor is on the symbol. + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started.rst b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started.rst new file mode 100644 index 0000000..cfd5341 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started.rst @@ -0,0 +1,8 @@ +Getting Started +=============== + +.. toctree:: + :maxdepth: 2 + :glob: + + 02-00-getting-started/* \ No newline at end of file diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-01-the-vapi-file.rst b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-01-the-vapi-file.rst new file mode 100644 index 0000000..e65c977 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-01-the-vapi-file.rst @@ -0,0 +1,17 @@ +The VAPI File +============= + +Check if the library's development package has installed a `pkg-config `_ file (.pc file extension). If so, give your VAPI file the same name. For example libfoo.pc should have the VAPI called libfoo.vapi. This allows the details of the library files to be automatically picked up and passed through to the C compiler and linker. + +When developing a VAPI a typical command to build the tests against the binding would be: + +.. code-block:: shell + + valac --vapidir . --pkg libfoo program_using_libfoo.vala + +The dot after ``--vapidir`` tells ``valac`` to include the current directory when looking for VAPI files. +The ``--pkg libfoo`` switch tells ``valac`` to look for a VAPI called ``libfoo.vapi``. Note the the ``.vapi`` suffix is dropped. If the VAPI also has the same name as a ``.pc`` file then ``valac`` will find and use the ``.pc`` file to extract the relevant library details to pass to the C compiler and linker. + +Example VAPI files can be found in the `of the Vala git repository `_ of the Vala git repository. Files stating they have been generated by ``vapigen`` have been generated through GObject Introspection and are not examples of manually written bindings. + +Once you have a working VAPI file, even if it is only a subset of the library's functionality, please consider sharing the file. See `Vala Extra VAPIs `_ and :doc:`Why Distribute Bindings Upstream `. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-02-attribution-and-license.rst b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-02-attribution-and-license.rst new file mode 100644 index 0000000..646d221 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-02-attribution-and-license.rst @@ -0,0 +1,20 @@ +Attribution and License +======================= + +To distribute the VAPI through one of the main repositories a copyright notice will be required. It may be easier to deal with this formality at the start of writing the binding. + +The copyright notice should include an attribution and a copy of the license. The attribution is your name along with your email address. This identifies you as the author of the VAPI and a point of contact in the very unlikely event a third party is identified as using the binding in breach of the license. Free software and open source licenses allow the VAPI file to be copied as long as the terms of the license are met. The license should be the same as the library's license. This ensures compatibility between the binding and the library. + +The copyright notice should be between multi-line comments, not documentation comments: + +.. code-block:: vala + + /* + * Copyright (c) 2016 My Name + * + * This library is free software...[or whichever license is used by the library] + * + */ + +Documentation comments have an additional asterisk at the beginning, ``/**``, and would be picked up by ``valadoc``. The use of ``valadoc`` is covered later. + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-03-the-ccode-attribute.rst b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-03-the-ccode-attribute.rst new file mode 100644 index 0000000..9414663 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-03-the-ccode-attribute.rst @@ -0,0 +1,14 @@ +The CCode Attribute +=================== + +Vala generates C code in a certain style, examples are Vala following its own naming conventions and the ordering of automatically generated parameters. The ``CCode`` attribute provides fine control of the C code produced by Vala and will be used extensively when binding a C library that uses its own conventions. + +The ``CCode`` attribute will be used for: + +* including a C header file +* converting from Vala naming conventions to a library's naming conventions +* binding a library to Vala's assisted memory management +* controlling the position of function call arguments, especially Vala generated arguments +* overcoming various edge cases + +These are introduced at the relevant points throughout the tutorial. For a single reference see the `Vala Manual Attributes Section `_. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-04-create-a-root-namespace.rst b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-04-create-a-root-namespace.rst new file mode 100644 index 0000000..0b4af56 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-04-create-a-root-namespace.rst @@ -0,0 +1,34 @@ +Create a Root Namespace +======================= + +Normally all the bindings for a library are placed into a single root namespace. For example libfoo or foolib, would best be placed in a namespace called Foo. This follows the naming convention above. For example an initial VAPI would be: + +.. code-block:: vala + + namespace Foo { + // bindings + } + +The binding can then either be used in a Vala program by prefixing the namespace, e.g.: + +.. code-block:: vala + + void main () { + Foo.library_function(); + } + +or bring the VAPI namespace into the scope of the file: + +.. code-block:: vala + + using Foo; + + void main () { + library_function (); + } + +Namespaces also provide a convenient way to group functions. Typically, for GLib-based libraries, the ``x_y_foo`` patterns can be translated directly into a namespace as ``x.y.foo``. Since most C libraries do not follow these conventions, things are slightly murkier. As general rules of thumb, try the following: + +* Move global variables, functions, constants, enums, flags, and delegate definitions into the class and struct definitions if they are clearly related only to that type. That is, it might make sense to move the ``enum FooOptions`` into ``class Foo`` as simply ``Options``. Note that structs cannot contain enum, flag, or delegate definitions; only constants and static methods. +* Use header files and directories as a guide. If the headers are stored as ``foo-2.0/db/{handle,transaction,row}.h`` or ``foo-2.0/db_{handle,transaction,row}.h`` or if ``foo-2.0/db.h`` contains definitions for ``foo_handle``, ``foo_tx``, and ``foo_row``, there's a good chance that creating a namespace ``Db`` is a logical grouping. +* Create namespaces for large groups of related constants. Sometimes, constant collections cannot be converted to enums, in which case, grouping them into a namespace is much easier to manage. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-05-include-the-c-header-files.rst b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-05-include-the-c-header-files.rst new file mode 100644 index 0000000..d425050 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-05-include-the-c-header-files.rst @@ -0,0 +1,16 @@ +Include the C Header Files +========================== + +The ``CCode`` attribute ``cheader_filename`` defines the comma separated list of headers to include in the generated C. For example, + +.. code-block:: vala + + [CCode (cheader_filename = "libfoo/foo.h")] + namespace Foo { + // bindings + } + +Try to apply headers to namespaces or containing types. Applying it to an outer context prevents having to repeat it in the inner context. + +A library will often have a single header that includes a number of sub-headers. For an example see the ``_ header. In these cases only the main header file needs to be included. + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-06-symbol-name-translations.rst b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-06-symbol-name-translations.rst new file mode 100644 index 0000000..47a2f56 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-06-symbol-name-translations.rst @@ -0,0 +1,77 @@ +Symbol Name Translations +======================== + +Vala has symbol name translation rules from Vala to C. The default rules follow the GLib naming conventions, but for a binding the name translations can be customised with the ``lower_case_cprefix``, ``cprefix`` and ``cname`` CCode details. + +The following example illustrates the default symbol name translation rules. Vala's name translation rules apply to both Vala programs and bindings. Compile the following example program with ``valac --ccode name_conversion_example.vala`` then examine how the Vala symbol names have been translated: + +.. code-block:: vala + + void main () { + Foo.Bar a = new Foo.Bar (); + a.test (); + var b = Foo.Bar.UNCHANGING; + } + + namespace Foo { + [Compact] + class Bar { + public const int UNCHANGING = 42; + public void test () { + } + } + } + +The use of the ``[Compact]`` attribute makes the C code simpler and so easier to read, but the name translation rules apply to full Vala classes as well. Here is a table that summarizes the example's translations: + ++------------------------+------------------------+------------------------------------------+ +| *Vala Identifier* | *C Identifier* | *Notes* | ++========================+========================+==========================================+ +| ``Foo.Bar`` | ``FooBar`` | This is the data type | ++------------------------+------------------------+------------------------------------------+ +| ``new Foo.Bar ()`` | ``foo_bar_new ()`` | This is the constructor function | ++------------------------+------------------------+------------------------------------------+ +| ``a.test ()`` | ``foo_bar_test (a)`` | This is a function acting on an instance | ++------------------------+------------------------+------------------------------------------+ +| ``Foo.Bar.UNCHANGING`` | ``FOO_BAR_UNCHANGING`` | A constant defined with the type | ++------------------------+------------------------+------------------------------------------+ + +When binding the library the Vala symbol names should follow the following conventions and then ``lower_case_cprefix``, ``cprefix`` and ``cname`` can be used to ensure the C symbol name matches the library: + ++---------------------------+---------------------------------------------------+----------------------------+----------------------------+ +| *Vala Semantics* | *Vala Convention* | *Default Translation to C* | *Modify with CCode Detail* | ++===========================+===================================================+============================+============================+ +| Classes | !TitleCase | | | ++---------------------------+---------------------------------------------------+----------------------------+----------------------------+ +| Constants | UPPER_SNAKE_CASE | | | ++---------------------------+---------------------------------------------------+----------------------------+----------------------------+ +| Delegates | !TitleCase | | | ++---------------------------+---------------------------------------------------+----------------------------+----------------------------+ +| Enums and Flags | !TitleCase | | | ++---------------------------+---------------------------------------------------+----------------------------+----------------------------+ +| Fields | lower_snake_case | | | ++---------------------------+---------------------------------------------------+----------------------------+----------------------------+ +| Methods | lower_snake_case | | | ++---------------------------+---------------------------------------------------+----------------------------+----------------------------+ +| Namespaces | !TitleCase | title_case\_ | ``lower_case_cprefix`` | +| | | | | +| | | TITLE_CASE\_ | ``lower_case_cprefix`` | +| | | | | +| | | !TitleCase | ``cprefix`` | ++---------------------------+---------------------------------------------------+----------------------------+----------------------------+ +| Properties | lower_snake_case | | | ++---------------------------+---------------------------------------------------+----------------------------+----------------------------+ +| Structs | !TitleCase | | | ++---------------------------+---------------------------------------------------+----------------------------+----------------------------+ +| Type Variables (Generics) | T (A single uppercase letter). | | | +| | For maps, K, V are preferred for keys and values. | | | ++---------------------------+---------------------------------------------------+----------------------------+----------------------------+ + +Where appropriate, expand cryptic C names into more understandable Vala ones (e.g., ``Tx`` into ``Transaction``). Vala is usually much more compact than C, so we are willing to make different trade-offs and favor readability over being concise a bit more than C programmers generally do. In particular, ``var`` saves a lot of writing long type names and import helps make better use of prefixes. + +Note the following: + +* the use of ``cprefix`` and ``lower_case_cprefix`` with a namespace +* the priority of a class over a namespace when using ``cprefix`` and ``lower_case_cprefix`` +* the use of ``cname`` with a function and constant + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-07-code-formatting-conventions.rst b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-07-code-formatting-conventions.rst new file mode 100644 index 0000000..9b7f2bb --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-07-code-formatting-conventions.rst @@ -0,0 +1,7 @@ +Code Formatting Conventions +=========================== + +* Tabs for indentation +* A space before an opening parenthesis and no space afterwards +* A space either side of equals +* No space before a comma, but a space after \ No newline at end of file diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-08-documentation-and-valadoc-org.rst b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-08-documentation-and-valadoc-org.rst new file mode 100644 index 0000000..b573f49 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-08-documentation-and-valadoc-org.rst @@ -0,0 +1,45 @@ +Documentation and Valadoc.org +============================= + +`Valadoc.org `_ is often the first website a Vala developer visits when seeking how to use a binding. A new VAPI commited to `Vala Extra VAPIs `_ can be added to Valadoc.org by adding the VAPI to the `list of downloaded packages `_ at Valadoc.org and submitting a pull request to the `Valadoc.org repository `_. See the `libcolumbus pull request `_ as an example. + +Valadoc.org is frequently re-generated. When Valadoc.org is re-generated VAPIs are pulled in from ``vala-extra-vapis`` and documentation generated from them. If no documentation comments are associated with a VAPI then Valadoc.org will only show the symbols in the VAPI. + +Add a documentation comment before a symbol in the VAPI. A documentation comment is a C multiline comment with an additional asterisk: + +.. code-block:: vala + + /** + * Brief description of class Foo + * + * Long description of class Foo, which can include an example + */ + [CCode (cname = "foo", ref_function = "foo_retain", unref_function = "foo_release")] + [Compact] + public class Foo { + // Details of binding + } + +The comments can include additional markup. Details are at `Valadoc Comment Markup `_. + +The documentation can be generated locally to test how it will appear. First, download and build ``valadoc``: + +.. code-block:: shell + + git clone git://git.gnome.org/valadoc + cd valadoc + ./autogen.sh + make + make install + +Second, generate the documentation: + +.. code-block:: shell + + cd my_binding_directory + valadoc --directory docs --force --package-name mybinding mybinding.vapi + +This will generate the HTML documentation in the ``docs`` directory. ``valadoc`` expects the ``docs`` directory to not exist, but ``--force`` overrides this. ``--package-name mybinding`` will create a sub-directory called ``mybinding`` in ``docs`` that contains the generated documentation for ``mybinding.vapi``. + +The locally generated documentation will have the same structure as ``valadoc.org``, although the visual styling may differ. + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-09-the-version-attribute.rst b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-09-the-version-attribute.rst new file mode 100644 index 0000000..0560271 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/02-00-getting-started/02-09-the-version-attribute.rst @@ -0,0 +1,25 @@ +The Version Attribute +===================== + +Vala symbol's can be annotated with the ``[Version]`` attribute. This allows a symbol to be marked as +experimental, deprecated and to indicate version information. For example: + +.. code-block:: vala + + namespace Test { + [Version (experimental = true)] + public void test_function_1 (); + + [Version (deprecated = true)] + public void test_function_2 (); + + [Version (deprecated_since = "2.0")] + public void test_function_3 (); + + [Version (deprecated = true, deprecated_since = "2.0", replacement = "test_function_5", since = "1.0")] + public void test_function_4 (); + + [Version (since = "1.0")] + public void test_function_5 (); + } + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management.rst b/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management.rst new file mode 100644 index 0000000..447dc5f --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management.rst @@ -0,0 +1,26 @@ +Using Vala's Automatic Memory Management +======================================== + +When writing Vala code, including code using a C library, memory management is handled by the Vala compiler. There is usually no need to manually claim and free memory. When writing a binding, however, it is an important part of the process to accurately instruct the Vala compiler how to use the C library's memory management calls. This is a one time job and means anyone then using the binding can take advantage of a binding that is much easier to write code for. + +Vala's memory allocation and types are a bit more involved than most languages. In Python, everything is a dynamically-typed object and it is allocated out of the ether then gets garbage collected. In C, memory allocation is largely handled by the user and types are simply descriptions of memory considered at compile time. Vala lives somewhere trying to cover all the bases at once. Importantly, the types in Vala imply something about the memory management. + +There are 4 memory management schemes in Vala: + ++-------------------+--------------------+--------------+---------------+ +| **Scheme** | **Memory Manager** | **Helpers?** | **Copy Cost** | ++===================+====================+==============+===============+ +| Values | C compiler | No | Cheap | ++-------------------+--------------------+--------------+---------------+ +| Parented | C compiler | Yes | Expensive | ++-------------------+--------------------+--------------+---------------+ +| Singly-Owned | Heap allocator | Yes | Expensive | ++-------------------+--------------------+--------------+---------------+ +| Reference-Counted | Heap allocator | Yes | Cheap | ++-------------------+--------------------+--------------+---------------+ + +.. toctree:: + :maxdepth: 2 + :glob: + + 03-00-using-auto-memory-management/* \ No newline at end of file diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-01-pointers-in-c.rst b/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-01-pointers-in-c.rst new file mode 100644 index 0000000..cc92f6c --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-01-pointers-in-c.rst @@ -0,0 +1,12 @@ +Pointers in C (or what all these \*'s mean) +=========================================== + +The asterisk, ``*``, is the indirection operator in C. Although, be aware it is also the multiplication operator. The indirection operator means an identifier contains a pointer to a memory location. Usually the data type held in the memory location is also indicated. For example ``int *identifier`` means an ``int`` is held at the memory location pointed to by ``identifier``. The data type, however, does not have to be specified and instead the "generic" type can be used: ``void *identifier``. + +There can be multiple levels of indirection, e.g. ``char **identifier``. + +The 'address of' operator is ampersand, ``&``. + +The use of the indirection operator and the address of operator is relevant to binding function signatures, which is covered in a later section. For a comprehensive explanation of pointers in C see `you need to know about pointers in C `_. + +For now it is enough to understand that the pointer gives no indication of how the memory pointed to is managed. It is not known from seeing a pointer in the C code whether the memory is constant, stack allocated or heap allocated. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-02-constants-the-stack-and-the-heap-in-c.rst b/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-02-constants-the-stack-and-the-heap-in-c.rst new file mode 100644 index 0000000..14fbeb6 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-02-constants-the-stack-and-the-heap-in-c.rst @@ -0,0 +1,32 @@ +Constants, the Stack and the Heap in C +====================================== + +Data in C can be allocated using a mechanism that stops it from being changed during the running of the program. These are known as constants. Data can also be allocated using two other schemes: the stack and the heap. These three schemes need to be understood when writing a binding. The main reason is so heap memory is allocated and deallocated properly by Vala code when using the binding, but also to make sure the binding doesn't apply heap rules to the other two schemes. + +To better understand these three schemes it is helpful to analyse how they handle memory in four stages: + +1. Declaration +2. Allocation +3. Initialization +4. Deallocation + +Declaration informs the compiler of how much memory will be needed. For example ``uint8`` lets the compiler know at least 8 bits (a byte) is needed, or ``double`` will likely require more memory than ``float``. The exact size of each type is platform dependent and will be resolved by the compiler. + +Allocation is the process of exclusively reserving an area of memory. Where the memory is allocated from is based on the memory scheme. + +Once the memory has been allocated the memory needs to be initialized to the required value. For example ``int a = 128;`` will set the memory reserved for an ``int`` to the value of ``128``. + +Deallocating the memory means it can be used again by other parts of the program. + ++--------------+-----------------+----------------+--------------------+------------------+ +| | **Declaration** | **Allocation** | **Initialization** | **Deallocation** | ++==============+=================+================+====================+==================+ +| **Constant** | Compile time | Compiler | Compile time | Program exit | ++--------------+-----------------+----------------+--------------------+------------------+ +| **Stack** | Compile time | Compiler | Run time | Compiler | ++--------------+-----------------+----------------+--------------------+------------------+ +| **Heap** | Compile time | Coder | Run time | Coder | ++--------------+-----------------+----------------+--------------------+------------------+ + +The C compiler does some memory management. This happens when items are placed on the stack or inside another structure: the compiler creates the space needed to hold these objects. Otherwise, ``malloc`` and ``free`` are used to allocate space from the heap. If any instance contains references to other instances, helper functions are needed to do the allocate and deallocate those references. + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-03-the-concept-of-ownership-in-vala.rst b/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-03-the-concept-of-ownership-in-vala.rst new file mode 100644 index 0000000..3791a48 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-03-the-concept-of-ownership-in-vala.rst @@ -0,0 +1,8 @@ +The Concept of "Ownership" in Vala +================================== + +.. todo:: + + This section was originally empty. + See ``_ for infomation + about ownership in Vala diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-04-binding-to-c-heap-handnlers.rst b/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-04-binding-to-c-heap-handnlers.rst new file mode 100644 index 0000000..656b531 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/03-00-using-auto-memory-management/03-04-binding-to-c-heap-handnlers.rst @@ -0,0 +1,33 @@ +Binding to C Heap Handlers +========================== + +One of the unique features of Vala is to have both singly-owned instances and reference-counted instances. Reference-counted instances can be stored in new locations and memory management done by counting the number of references; destruction of the instance is done when there are no more references to that instance. Singly-owned instances have a single authoritative reference and, when that reference is destroyed, the instance is destroyed. Reference-counted objects can thus be “copied” by increasing the reference count while singly-owned instances cannot be copied without duplicating the actual data in them, if that is even possible. + +While this is primarily a concern for objects, all instances in Vala must subscribe to one of these memory management schemes. Different types of objects can follow different schemes and some types can subscribe to different schemes depending on subtle differences in declaration. + ++-----------------------------------+-------------------+----------------------------------------------+--------------------------------------------------+ +| **Vala Type** | **Scheme** | **C Type** | **Memory Management Binding Needed?** | ++===================================+===================+==============================================+==================================================+ +| Enum and Flag | Value | int | No | ++-----------------------------------+-------------------+----------------------------------------------+--------------------------------------------------+ +| Delegate ``(has_target = false)`` | Value | Function Pointer | No | ++-----------------------------------+-------------------+----------------------------------------------+--------------------------------------------------+ +| Delegate ``(has_target = true)`` | Value | Function Pointer and Void Pointer | No | ++-----------------------------------+-------------------+----------------------------------------------+--------------------------------------------------+ +| Delegate ``(has_target = true)`` | Singly-Owned | Function Pointer and Void Pointer | Yes, use ``free_function`` | ++-----------------------------------+-------------------+----------------------------------------------+--------------------------------------------------+ +| Simple-Type Struct | Value | Various Basic Types or a Struct | No | ++-----------------------------------+-------------------+----------------------------------------------+--------------------------------------------------+ +| Struct | Value | Struct, but passed as a Pointer to a Struct | No | ++-----------------------------------+-------------------+----------------------------------------------+--------------------------------------------------+ +| Struct | Parented | Struct, but passed as a Pointer to a Struct | Yes, use ``destroy_function`` | ++-----------------------------------+-------------------+----------------------------------------------+--------------------------------------------------+ +| Compact Class | Singly-Owned | Pointer to a Struct | Yes, use ``free_function`` | ++-----------------------------------+-------------------+----------------------------------------------+--------------------------------------------------+ +| Compact Class | Reference-Counted | Pointer to a Struct | Yes, use ``ref_function`` and ``unref_function`` | ++-----------------------------------+-------------------+----------------------------------------------+--------------------------------------------------+ +| Pointer | Value | Pointer to Contents | No | ++-----------------------------------+-------------------+----------------------------------------------+--------------------------------------------------+ +| Array | Singly-Owned | Pointer to Element Type (and Integer Length) | Yes, use ``free_function`` | ++-----------------------------------+-------------------+----------------------------------------------+--------------------------------------------------+ + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code.rst b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code.rst new file mode 100644 index 0000000..3e298f3 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code.rst @@ -0,0 +1,13 @@ +Recognizing Vala Semantics in C Code +==================================== + +An important difference between C and Vala is that Vala is more semantically expressive. For instance, in C `char*` can mean several things. It could be a string, an array, a pointer to a single character, an out parameter returning a character, a pointer to a character that will be modified by the routine. It is also completely unclear if this pointer can be null. Vala expresses these differences syntactically, so writing the binding requires understanding the intent of the original code. + +It is easiest to start by looking through the header files and determining all the important types to be bound. For each one, find any allocation functions, copy functions and cleanup functions. From these, the right binding strategy can be inferred. + +.. toctree:: + :maxdepth: 2 + :glob: + + 04-00-recognizing-vala-semantics-in-c-code/* + \ No newline at end of file diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-01-constants.rst b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-01-constants.rst new file mode 100644 index 0000000..9afb531 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-01-constants.rst @@ -0,0 +1,22 @@ +Constants +========= + +This sub-section introduces: +* the ``#define`` pre-processor directive in C +* the stages the Vala compiler follows + +A constant does not vary during the running of a program and must be a simple type or string. As an example, if the C library defines a constant through a ``#define`` statement: + +.. code-block:: c + + #define CUSTOM_PI 3.14159265358979323846 + +``#define`` is simple text substitution by the pre-processor. So relevant occurrences of ``CUSTOM_PI`` are replaced with ``3.14159265358979323846`` by the C pre-processor before the C code is then compiled. This is why no type information is given. Also, because this is done before compilation it is implicit that the value is constant. + +When binding this to Vala the type information and that it is constant are made explicit: + +.. code-block:: vala + + public const double CUSTOM_PI; + +An important point to note is the value is not bound, only the identifier. Vala will use the identifier in the generated C code and then the C pre-processor will replace it with the value before compilation. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-02-enums-and-flags.rst b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-02-enums-and-flags.rst new file mode 100644 index 0000000..3204d9a --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-02-enums-and-flags.rst @@ -0,0 +1,89 @@ +Enums and Flags +=============== + +While C has support for enums, C programmers often do not use enums, opting instead for #defines. Both of these structures can be bound to Vala enums. + +This first example is a straight mapping between a C enum and a Vala enum. The C: + +.. code-block:: c + + typedef enum { + FOO_A, + FOO_B, + FOO_C, + } foo_e; + + +and the Vala binding: + +.. code-block:: vala + + [CCode (cname = "foo_e", cprefix = "FOO_", has_type_id = false)] + public enum Foo { + A, + B, + C + } + +Note how ``cprefix`` is used in the above example to prepend ``FOO_`` to all the Vala values when the C is generated. + +The second example shows how a series of definitions of constants in C can be mapped to a Vala enum: + +.. code-block:: c + + #define BAR_X 1 + #define BAR_Y 2 + #define BAR_Z 3 + +.. code-block:: vala + + [CCode (cname = "int", cprefix = "BAR_", has_type_id = false)] + public enum Bar { + X, + Y, + Z + } + +Check where the ``enum`` is used to determine the correct type, though ``int`` and ``unsigned int`` are the most common. + +There is also a common tendency to use combinable bit patterns. These are convertible to Vala flags enums. + +.. code-block:: c + + #define FOO_READ (1<<0) + #define FOO_WRITE (1<<1) + #define FOO_CREATE (1<<2) + +.. code-block:: vala + + [CCode (cname = "int", cprefix = "FOO_", has_type_id = false)] + [Flags] + public enum Foo { + READ, + WRITE, + CREATE + } + + +In Vala, enums and flags may have member functions. In particular, ``strerr``-like functions are best converted to member functions. + +Enums may also inherit, so if one set of flags is a superset of another, but they are logically separate, this can be done using inheritance. + +.. code-block:: c + + #define FOO_A 1 + #define FOO_B 2 + #define FOO_C 3 + #define FOO_D 4 + /* takes FOO_A or B only */ + void do_something(int); + /* takes any FOO_ value */ + void do_something_else(int); + +.. code-block:: vala + + [CCode (cname = "int", cprefix = "FOO_", has_type_id = false)] + public enum Foo { A, B } + [CCode (cname = "int", cprefix = "FOO_", has_type_id = false)] + public enum FooExtended : Foo { C, D } + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-03-simple-type-structs.rst b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-03-simple-type-structs.rst new file mode 100644 index 0000000..d815b10 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-03-simple-type-structs.rst @@ -0,0 +1,112 @@ +Simple Type Structs +=================== + +C libraries often define new types for numeric handles, sizes and offsets. To translate these to a VAPI file, just use the ``SimpleType`` attribute with a struct and inherit from the same simple type in the C header. + +An example: + +.. code-block:: c + + typedef uint32_t people_inside; + +would be defined in the VAPI file as: + +.. code-block:: vala + + [SimpleType] + [CCode (cname = "people_inside", has_type_id = false)] + public struct PeopleInside : uint32 { + } + + +When inheriting from an existing type, all the methods will be carried forward. For sizes and offsets, this is probably desirable; for handles, it is probably not. For example, a UNIX file descriptor is stored in an integer, but adding or multiplying two file handles has no sense. In this case, it is preferable not to inherit from a numeric type and add the attribute ``IntegerType (rank=X)`` so the Vala compiler can automatically cast a type into an integer of an appropriate size when needed (e.g., initialising from an integral constant). + +An example from XCB: + +.. code-block:: c + + typedef uint32_t xcb_atom_t; + +would be defined in the VAPI file as: + +.. code-block: vala + + [SimpleType] + [IntegerType (rank = 9)] + [CCode (cname = "xcb_atom_t", has_type_id = false)] + public struct AtomT { + } + + +The ranks for the common types, as defined in the *glib-2.0.vapi* and *posix.vapi* files, are: + ++----------+-----------------------+------------------+ +| **Rank** | **Types in glib-2.0** | **Other Use** | ++==========+=======================+==================+ +| 1 | gint8 | | +| | | | +| | gfloat | | ++----------+-----------------------+------------------+ +| 2 | gchar | | +| | | | +| | gdouble | | ++----------+-----------------------+------------------+ +| 3 | guchar | Posix.cc_t | +| | | | +| | guint8 | | ++----------+-----------------------+------------------+ +| 4 | gshort | | +| | | | +| | gint16 | | ++----------+-----------------------+------------------+ +| 5 | gushort | | +| | | | +| | guint16 | | ++----------+-----------------------+------------------+ +| 6 | gint | Posixpid_t | +| | | | +| | gint32 | | ++----------+-----------------------+------------------+ +| 7 | guint | Posix.speed_t | +| | | | +| | guint32 | Posix.tcflag_t | +| | | | +| | gunichar | | ++----------+-----------------------+------------------+ +| 8 | glong | Posix.clock_t | +| | | | +| | gssize | | +| | | | +| | time_t | | ++----------+-----------------------+------------------+ +| 9 | gulong | Posix.nfds_t | +| | | | +| | gsize | Posix.key_t | +| | | | +| | | Posix.fsblkcnt_t | +| | | | +| | | Posix.fsfilcnt_t | +| | | | +| | | Posix.off_t | +| | | | +| | | Posix.uid_t | +| | | | +| | | Posix.gid_t | +| | | | +| | | Posix.mode_t | +| | | | +| | | Posix.dev_t | +| | | | +| | | Posix.ino_t | +| | | | +| | | Posix.nlink_t | +| | | | +| | | Posix.blksize_t | +| | | | +| | | Posix.blkcnt_t | ++----------+-----------------------+------------------+ +| 10 | gint64 | | ++----------+-----------------------+------------------+ +| 11 | guint64 | | ++----------+-----------------------+------------------+ + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-04-structs.rst b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-04-structs.rst new file mode 100644 index 0000000..368ddd1 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-04-structs.rst @@ -0,0 +1,50 @@ +Structs +======= + +Note that a struct on the C side can contain the Vala equivalent of instance data of an object and so be bound to a compact class in Vala. This is covered in a later section. This section covers binding C structs and C primitives to Vala structs. + +A common pattern in C is a parented structure, like this: + +.. code-block:: c + + typedef struct { + int a; + int *b; + } foo_t; + void foo_init(foo_t*); + void foo_free(foo_t*); + +The correct binding is: + +.. code-block:: vala + + [CCode (cname = "foo_t", destroy_function = "foo_free", has_type_id = false)] + public struct Foo { + int a; + int *b; // We can do better later + [CCode (cname = "foo_init")] + public Foo (); + } + +The great trap with this is the naming: ``foo_free`` does not free the pointer it is passed. There may be no way of knowing for sure other than reading the implementation of ``foo_free``. The full structure for ``Foo`` must be given for a ``struct``. For compact classes it may be opaque (i.e., the contents of the ``struct`` are not provided), though not necessarily. + +The next example illustrates the use of an empty ``destroy_function`` and has a default value for the struct: + +.. code-block:: c + + typedef struct { + int x; + int y; + } bar_t; + #define BAR_INITIALIZER {0, 1} + + +.. code-block:: vala + + [CCode (cname = "bar_t", destroy_function = "", default_value = "BAR_INITIALIZER", has_type_id = false)] + public struct Bar { + int x; + int y; + } + +It's important to note that if a struct doesn't have a destroy function specified, Vala will generate one given there are any fields in the struct which look like they need to be deallocated, which may or may not behave correctly depending on the context. An empty ``destroy_function`` will keep the generated code correct and prevent Vala from generating a destructor. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-05-compact-classes.rst b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-05-compact-classes.rst new file mode 100644 index 0000000..834f3c2 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-05-compact-classes.rst @@ -0,0 +1,82 @@ +Compact Classes +=============== + +Vala has `three types of class `_: GObject subclasses, GType classes and compact classes. The relevant parts of a non-GLib based C library can be bound to a compact class in Vala. + + +Singly-Owned Classes +-------------------- + +The most common case is the singly-owned compact class, which follows one of these patterns: + +.. code-block:: c + + typedef struct foo Foo; + /* Create a new Foo handle. */ + Foo *foo_make(void); + /* Make a copy of a Foo. */ + Foo *foo_dup(Foo*); + /* Free a Foo handle. */ + void foo_free(Foo*); + + typedef struct bar *Bar; + /* Open a new Bar from a file, NULL if an error occurs. */ + Bar bar_open(const char *filename); + /* Dispose of a Bar when finished. */ + void bar_close(Bar); + +These should both be bound as compact classes. The ``foo_make`` and ``bar_open`` functions will allocate memory and create a new instance of the type (this is where documentation is helpful). There's an important subtle difference between these two: where the pointer is mentioned. In the case of ``Foo``, the pointer is mentioned in every function, while ``Bar`` has it baked into the ``typedef.`` Vala will always add a star, so ``Bar`` will be actually be bound using ``struct bar``. + +The second difference is the constructor: ``Foo``'s constructor will not fail, but ``Bar``'s might fail. Vala constructors are not permitted to return null. ``Bar``'s constructor is best bound as a static method, as these can return null. + +.. code-block:: vala + + [CCode (cname = "Foo", free_function = "foo_free")] + [Compact] + public class Foo { + [CCode (cname = "foo_make")] + public Foo (); + + [CCode (cname = "foo_dup")] + public Foo dup (); + } + + [CCode (cname = "struct bar", free_function = "bar_close", has_type_id = false)] + [Compact] + public class Bar { + [CCode (cname = "bar_open")] + public static Bar? open (string filename); + } + +In case explicit duplication is needed, include a member function of the copy function called ``dup()``, if available. + + +Reference-Counted Classes +------------------------- + +Reference-counted classes usually have a pattern as follows: + +.. code-block:: c + + typedef struct foo Foo; + Foo *foo_new(); + Foo *foo_retain(Foo*); + void foo_release(Foo*); + +and should be bound as: + +.. code-block:: vala + + [CCode (cname = "foo", ref_function = "foo_retain", unref_function = "foo_release")] + [Compact] + public class Foo { + [CCode (cname = "foo_new")] + public Foo (); + [CCode (cname = "foo_retain")] + public void @ref (); + [CCode (cname = "foo_release")] + public void unref (); + } + + +The ``ref`` and ``unref`` function are provided as a courtesy to the user such that they might manually change the reference counts in difficult situations. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-06-functions.rst b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-06-functions.rst new file mode 100644 index 0000000..bc6c149 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-06-functions.rst @@ -0,0 +1,12 @@ +Functions +========= + +These are functions that work alone and can be used without needing previous calls to other functions. This is a simple example of the Posix VAPI file for the ``sync`` system call: + +.. code-block:: vala + + [CCode (cname = "sync")] + void sync(); + +The ccode attribute, ``cname``, specifies the C name to use. This avoids ``valac`` appending the current namespace to the function name, ensuring that a call to ``Posix.sync()`` in vala will map to a call to ``sync()`` in C, and not to ``posix_sync()``. + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-07-delegates.rst b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-07-delegates.rst new file mode 100644 index 0000000..8a51a21 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/04-00-recognizing-vala-semantics-in-c-code/04-07-delegates.rst @@ -0,0 +1,24 @@ +Delegates +========= + +C permits the definition of function pointers, which are pointers to code matching a certain signature that may be executed. The major problem with this is that it does not pass information from the caller, through the library, to the callback. In other languages, a closure is an encapsulation of code and state. C programmers sometimes emulate this behaviour by passing a void pointer of “user data” or “context” that acts as the state portion of the closure. + +Vala supports both of these modes: a delegate may be targeted (i.e., a closure) or targetless (i.e., a function pointer). This is controlled by the has_target value, which defaults to true. The position of the target is assumed to be the last value in the argument list, which is typically where most C programs put it, though they occasionally place it first. + +.. code-block:: c + + typedef int(*compute_func)(int a, int b); + typedef double(*analyze_func)(int a, int b, void *userdata); + +.. code-block:: vala + + [CCode (cname = "compute_func", has_target = false)] + public delegate int ComputeFunc (int a, int b); + [CCode (cname = "analyze_func")] + public delegate double AnalyzeFunc (int a, int b); + + +If the position of the context is not the last parameter, set the CCode attribute, ``delegate_target_pos``, as per :doc:`Changing the Position of Parameters <../05-00-fundamentals-of-binding-a-c-function/05-05-changing-the-position-of-generated-arguments>`. + +It is common for C programmers not to create a ``typedef`` for a function pointer, instead opting to include it directly. Create a delegate and do not set the ``cname``. If possible, contribute a patch to the library to create a ``typedef``. + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function.rst b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function.rst new file mode 100644 index 0000000..de8f602 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function.rst @@ -0,0 +1,10 @@ +Fundamentals of Binding a C Function +==================================== + +A function signature comprises the parameters of the function and any return value. + +.. toctree:: + :maxdepth: 2 + :glob: + + 05-00-fundamentals-of-binding-a-c-function/* \ No newline at end of file diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-01-out-and-reference-parameters-and-return-values.rst b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-01-out-and-reference-parameters-and-return-values.rst new file mode 100644 index 0000000..4c92a0a --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-01-out-and-reference-parameters-and-return-values.rst @@ -0,0 +1,76 @@ +Out and Reference Parameters and Return Values +============================================== + +C makes rather heavy use of out parameters as an alternate method to returning. Unfortunately, because of the non-uniform nature of this return system, it is rather confusing. + +For all types except structs, when returned, the instance is returned, per usual. Any supplementary information (delegate targets, array lengths) are quietly appended as out parameters. To return another value, a parameter may be declared as ``out``. Vala will assume the function will accept a pointer to this value, which it will populate upon return. A ``ref`` parameter is similar, but the parameter must be initialised before the function is called and the function may manipulate its value. + +Consider the following: + +.. code-block:: c + +int div_and_mod(int a, int b, int *mod) { + *mod = a % b; + return a / b; +} + +.. code-block:: vala + + public int div_and_mod (int a, int b, out int mod); + + +This works just as easily for class type parameters: + +.. code-block:: c + + int open_file_and_fd(const char *filename, FILE **file) { + FILE *f = fopen(filename, "r"); + if (file) + *file = f; + return (f == NULL) ? -1 : fileno(f); + } + +.. code-block:: vala + + public int open_file_and_fd (string filename, out FileStream file); + +For arrays and delegates, this means returning both the parameter and its associated parameters: + +.. code-block:: c + +void do_approximation(int *input_array, int input_length, int **output_array, int *output_length); + +.. code-block:: vala + + public void do_approximation (int[] input, out int[] output); + + +Note that when you think of an “out array” what you may actually want is just a buffer. If the caller allocates the memory, you want a buffer, not an out array. + +Returning structs is rather different. Because struct's memory is allocated by the caller, an out parameter for a struct is indistinguishable from a regular pointer. Moreover, returning a struct actually means including a hidden out parameter. + +.. code-block:: vala + + public struct Foo { … } + public Foo get_foo (int x); + public void get_foo2 (int x, out Foo f); + +.. code-block:: c + + void get_foo(int x, foo *ret); + void get_foo2(int x, foo *ret); + +To return a struct directly, the question mark operator will box it, and make it look heap allocated: + +.. code-block:: vala + + public Foo? get_foo (int x); + public int make_foo (int y, out Foo? f); + +.. code-block:: c + + foo *get_foo(int x); + int make_foo(int y, foo **f); + +The ownership rules in :doc:``05-02-ownership`` apply. + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-02-ownership.rst b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-02-ownership.rst new file mode 100644 index 0000000..522d090 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-02-ownership.rst @@ -0,0 +1,13 @@ + +Ownership +========= + +All parameters are, by default, unowned, unless marked with the ``owned`` keyword. All return values and ``ref`` and ``out`` parameters are, by default, owned, unless marked with the ``unowned`` keyword. The basic types mentioned above have no ownership since they may be copied at will. + +It is often the case that a function will return one of its input values, particularly when filling a buffer. It is crucial that the ownership is correct. If not done correctly, Vala will acquire a second copy of the pointer that it thinks it has to free, and free the same chunk of memory twice, leaking to a bad time spent in Valgrind. + +**If ownership semantics are not correct, either a memory leak has been written or a double-free has been written.** It is frequently the case that one needs to read the source to be absolutely sure that ownership semantics are correct. + +Often C programmers will mark return values as const when they are unowned. + +See also: :doc:`10-00-awkward-situations/10-02-dependently-typed-ownership`. \ No newline at end of file diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-03-nullability.rst b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-03-nullability.rst new file mode 100644 index 0000000..3a9f91b --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-03-nullability.rst @@ -0,0 +1,19 @@ +Nullability +=========== +For most types, appending a question mark allows the type to be null. Generally, C programmers do a lousy job of conveying whether a particular parameter may be null. For any type which is, underneath, a pointer (arrays, compact classes, arrays, and delegates) nullability does not change the C type. That is, if ``Foo`` is a class, then ``Foo foo`` and ``Foo? foo`` have the same C signature. For simple types, enums, and flags, adding nullability lifts the type to a pointer. That is ``bool b`` has the C type ``gboolean b`` and ``bool? b`` has the C type ``gboolean *b``. Parented structs are a special case. When passed as parameters, they are always passed as a pointer, so nullability makes only a semantic difference; when return values, nullability changes the behaviour, as discussed below. + +Vala always assume an out parameter can be null. For example: + +.. code-block:: vala + + public delegate void ComputeFunc (int x); + public void get_compute_func (double epsilon, out ComputeFunc func); + + ComputeFunc f; + get_compute_func (3.14158, out f); + f (3); // f should never be a null pointer. + get_compute_func (2.72, null); // This is perfectly okay according to Vala. + + +It's important to note that nullability refers to the type of the parameter, not the parameter handling. Many C libraries do not check that an out parameter is not null before accessing it, resulting in a segmentation fault. There is no syntax in Vala to prevent this. + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-04-static-methods.rst b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-04-static-methods.rst new file mode 100644 index 0000000..4155042 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-04-static-methods.rst @@ -0,0 +1,7 @@ +Static Methods +============== + +Enums, flags, simple types, structs and classes can contain functions. When the Vala compiler generates the C function call the data structure will be included as the first argument. To prevent the automatic generation of the argument use the ``static`` keyword with the function definition in the VAPI. + +Binding static methods is, in fact, simpler than binding member methods, as there is no instance. Care should be taken to organise static methods into logical places: some should be in the containing namespace and some should be in the type definition. In general, methods that produce instances of the type (i.e., things that act like constructors that might fail) belong in the type definition. + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-05-changing-the-position-of-generated-arguments.rst b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-05-changing-the-position-of-generated-arguments.rst new file mode 100644 index 0000000..5f17050 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-05-changing-the-position-of-generated-arguments.rst @@ -0,0 +1,26 @@ +Changing the Position of Generated Arguments +============================================ + +The default behaviour of Vala is to keep the position of arguments in a Vala caller the same as the position of parameters in the C function callee. Where an argument is not explicit on the Vala side, for example instance data, Vala assumes it will be in a certain position. Instance data is assumed to be the first parameter of the C function, but this can be changed via the ``instance_pos`` CCode attribute to any position. The Vala position system is used for the instance position (``instance_pos``), array length position (``array_length_pos``), delegate target position (``delegate_target_pos``), and can even be used to reorder parameters (``pos``). + +Vala's positioning system is a little confusing at first, so it bears explanation. +Suppose we have a Vala function as follows: + +.. code-block:: vala + + public class Foo { + public delegate int Transform (double a); + public int[] compute (int x, Transform t); + } + +The generated signature for ``compute`` will be: + +.. code-block:: c + + int *foo_compute(Foo self, int x, foo_transform t, void *t_userdata, int *array_len) + +I have marked the parameters that occur verbatim in Vala with their positions. From Vala's perspective, the position of self must be less than 1. Similarly, ``t_userdata`` must be greater than 2, and ``array_len`` must be greater than ``t_userdata`` for this ordering to make sense. Vala allows floating point values to describe this ordering. Once can think of ``self`` as having position 0, ``t``'s context as having position 2.1, and the returned array length as having position 2.2. This is just one possible set of values. It could also be 0.9, 2.5, 2.8, respectively, and produce the same result. + +By default, Vala will set the instance to be 0, any array length to be the position of the array plus 0.1, any delegate's target to be the position of the delegate plus 0.1, any destructor for an owned delegate to be the position of the delegate plus 0.2. + +If the order does not suit the C function, it is possible to reorder them using appropriate values, however you must keep the total order clean in your mind. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-06-default-values-and-changing-an-argument-s-position.rst b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-06-default-values-and-changing-an-argument-s-position.rst new file mode 100644 index 0000000..0874655 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-06-default-values-and-changing-an-argument-s-position.rst @@ -0,0 +1,18 @@ +Default Values and Changing an Argument's Position +================================================== + +Since C does not have default parameters, there are sometimes duplicate C functions to act in this way: + +.. code-block:: c + + int foo_compute(Foo *f, int base_height); + int foo_compute_ex(Foo *f, int base_height, Table *t, struct opts *opts); + + +Since Vala does have default parameters, it may be beneficial to only bind the extended version, but only if the default values are unlikely to change. This is generally true in where the documentation reads “set to null to determine automatically”. If unsure, it is best to bind both. + +.. code-block:: vala + + [CCode (cname = "foo_compute_ex")] + public compute (int base_height, Table t = null, opts? opts = null); + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-07-adapting-a-signature-with-a-vala-wrapper.rst b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-07-adapting-a-signature-with-a-vala-wrapper.rst new file mode 100644 index 0000000..80eaec4 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-07-adapting-a-signature-with-a-vala-wrapper.rst @@ -0,0 +1,6 @@ +Adapting a Signature with a Vala Wrapper +======================================== + +It is possible to adapt an existing function signature by using a wrapper function written in Vala. This can be used to make the signature more Vala friendly. + +This is usually done by making the C binding ``private`` and making the wrapper call the ``private`` method. The wrapper is also written in the VAPI file. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-08-variadic-arguments.rst b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-08-variadic-arguments.rst new file mode 100644 index 0000000..8ff02a7 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-08-variadic-arguments.rst @@ -0,0 +1,10 @@ +Variadic Arguments (a.k.a. “...”) +================================= + +C variadic argument system is treacherous and includes lots of potential ways to break. Vala, unfortunately, inherits them. Vala adds a few safeties, but also introduced some new problems. + +One safety put in place is that if the method's ``CCode`` attribute includes ``sentinel = "X"``, then X will always be appended as the last parameter. Since lists are often terminated by a special value, usually null, this can prevent variadic argument overruns. + +Additionally, Vala can do type checking on ``printf``-like and ``scanf``-like function by adding the ``PrintfFunction`` or ``ScanfFunction`` attributes. However, if the format strings have been modified to include special values, these formatting tokens will not work as intended. + +Return values that append to the end of a function, such as array length returns, and delegate contexts, will often interact badly with variadic arguments, since the Vala compiler will erroneously place the parameter after the “...” in the definition. When dealing with variadic functions, it is best to specify all positions explicitly. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-09-functions-that-do-not-return.rst b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-09-functions-that-do-not-return.rst new file mode 100644 index 0000000..54d3b6a --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-09-functions-that-do-not-return.rst @@ -0,0 +1,5 @@ +Functions That Do Not Return +============================ + +If a function will never return, the attribute ``NoReturn`` allows the compiler's analyzer to know that no code executed after that statement will ever be executed. This is rare, but useful for statements which call ``abort`` or ``exit`` underneath. + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-10-methods-that-change-the-instance-reference.rst b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-10-methods-that-change-the-instance-reference.rst new file mode 100644 index 0000000..70ce3e5 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-10-methods-that-change-the-instance-reference.rst @@ -0,0 +1,19 @@ +Methods that Change the Instance Reference +========================================== + +Sometimes methods return a new pointer to the instance (think realloc). Declare the function in the VAPI returns void and add the attribute ``ReturnsModifiedPointer``. + +.. code-block:: c + + typedef struct table Table; + Table *table_grow(Table *t, size_t object_count); + + +.. code-block:: vala + + [Compact] + [CCode (cname = "Table")] + public class Table { + [ReturnsModifiedPointer] + public void grow (size_t object_count); + } diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-11-methods-that-destroy-the-instance-reference.rst b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-11-methods-that-destroy-the-instance-reference.rst new file mode 100644 index 0000000..6936f8c --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/05-00-fundamentals-of-binding-a-c-function/05-11-methods-that-destroy-the-instance-reference.rst @@ -0,0 +1,26 @@ +Methods that Destroy the Instance Reference +=========================================== + +If a method destroys the instance (that is, frees it) it can be marked with the ``DestroysInstance`` attribute. The method must return void. Although in most cases such a method would be bound as the ``free_function`` of the compact class. + +If a function destroys an instance but provides a useable return value, instead, bind it as a static method which takes an owned variable for the instance: + +.. code-block:: c + + typedef struct transaction Transaction; + Transaction begin_tx(Database *db); + void transaction_abort(Transaction *tx); + void transaction_commit(Transaction *tx); + bool transaction_try_commit(Transaction *tx); + + +.. code-block:: vala + + [Compact] + [CCode (cname = "Transaction", free_function = "transaction_abort")] + public class Transaction { + public Transaction (Database db); + [DestroysInstance] + public void commit (); + public static bool try_commit (owned Transaction tx); + } diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics.rst b/source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics.rst new file mode 100644 index 0000000..000b536 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics.rst @@ -0,0 +1,11 @@ +Adding Vala Friendly Semantics +============================== +All bound methods should be public unless working around some awkward situation. The Vala compiler does not respect visibility in VAPI files, so defining private methods simply prevents them from appearing in the :doc:`Valadoc `, not from being accessible. + +Vala has some special method names that allow the method to be used with Vala syntax. Differences between C and Vala can be captured using the ``CCode`` attribute. + +.. toctree:: + :maxdepth: 2 + :glob: + + 06-00-adding-vala-friendly-semantics/* \ No newline at end of file diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics/06-01-to-string-methods.rst b/source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics/06-01-to-string-methods.rst new file mode 100644 index 0000000..b4a9837 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics/06-01-to-string-methods.rst @@ -0,0 +1,3 @@ +to_string () Methods +==================== +Binding a method as ``to_string ()`` will allow the method to be used in a Vala string template without needing to write the method identifier in the Vala source code. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics/06-02-properties.rst b/source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics/06-02-properties.rst new file mode 100644 index 0000000..b7025f8 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics/06-02-properties.rst @@ -0,0 +1,34 @@ +Properties +========== + +Vala allows compact classes to have properties, which are syntactic sugar for get and set method pairs. Often C objects with opaque implementations will provide a collection of functions to query state about the instance. These can be converted to properties given the following: + +* The ``get`` method has the signature ``T get(I self)`` and the set method has the signature ``void set(I self, T val)``. They need not actually occur in pairs. +* The ``get`` method does not have side effects that are not obvious to the user. +* The ``get`` method is cheap to call. +* The ``set`` method does not have error information being returned. + +Unlike most return types, the return of a get method is assumed to be unowned unless explicitly ``owned``. + +Consider: + +.. code-block:: c + + typedef struct foo Foo; + int foo_item_count(Foo f); + int foo_max_items(Foo f); + void foo_set_max_items(Foo f); + +.. code-block:: vala + + public class Foo { + public int item_count { + [CCode (cname = "foo_item_count")] get; + } + public int max_items { + [CCode (cname = "foo_max_items")] get; + [CCode (cname = "foo_set_max_items")] set; + } + } + +All the usual ``CCode`` attributes may be applied to ``get;`` and ``set;`` and ``owned`` may be applied to change the default ownership of ``get;``. Note that changing the ownership of the property is the wrong thing to do unless the instance doesn't actually own the value provided to it by ``set;``. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics/06-03-collections.rst b/source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics/06-03-collections.rst new file mode 100644 index 0000000..6a6e8b5 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/06-00-adding-vala-friendly-semantics/06-03-collections.rst @@ -0,0 +1,93 @@ +Collections +=========== + +Vala has several standard method names that are designed to work with Vala syntaxes like ``foreach``. + +The ``get ()`` method is used by Vala to implement the square bracket indexing syntax. For example a ``list`` instance with a ``get`` method that returns a list item, ``list.get (index)``, can also be written ``list [index]``. + +In the next example the C function signature returns an item in the collection: + +.. code-block:: c + + blkid_partition + blkid_partlist_get_partition (blkid_partlist ls, + int n); + +This could be bound in the VAPI as: + +.. code-block:: vala + + [Compact] + [CCode (cname = "blkid_partlist")] + public class ListOfPartitions { + [CCode (cname = "blkid_partlist_get_partition")] + public unowned Partition get (int index); + } + + +Note that ``[CCode (cname = "blkid_partlist_get_partition")]`` is used to change the Vala method name ``get`` to the name required in C. The binding can then be used in Vala code to get an item in the collection: + +.. code-block:: vala + + var partition = partitions [count]; + +``set`` is the Vala method to replace an item in the collection. ``set`` must return ``void``. + +Both the index methods, ``get`` and ``set``, can take as many parameters as the C function allowing for multi-dimensional indexes to be bound. With ``set`` in Vala the final parameter must be the new value. + +By binding a ``size`` property in Vala to a function that returns the size of the collection in C then Vala's ``foreach`` keyword can be used with the collection. The ``get`` index method is also required. The following example continues with the !PartitionList example above. The C function signature to get the size of the list is: + +.. code-block:: c + + int + blkid_partlist_numof_partitions (blkid_partlist ls); + +This is bound as: + +.. code-block:: vala + + [Compact] + [CCode (cname = "blkid_partlist")] + public class ListOfPartitions { + [CCode (cname = "blkid_partlist_get_partition")] + public unowned Partition get (int index); + public int size { [CCode (cname = "blkid_partlist_numof_partitions")] get; } + } + +Note that the CCode ``cname`` translation is inside the body of the property. + +The binding can now be used in Vala code with ``foreach``: + +.. code-block:: vala + + foreach (var partition in partitions) { /* do something with the partition */ } + +If the collection is unowned then Vala will give an error: ``duplicating ListOfPartitions instance, use unowned variable or explicitly invoke copy method``. See `Bug 661876 `_. + +For an unowned collection a ``for`` loop will still work: + +.. code-block:: vala + + for (int count = 0; count < partitions.size; count++) { + var partition = partitions [count]; + /* do something with the partition */ + } + +For container-like instances, Vala provides syntactic sugar to convert certain operations into method calls: + +.. code-block:: vala + + x in a → a.contains (x) + a[x, y] → a.get (x, y) + a[x, y] = z → a.set (x, y, z); + foreach (var x in a) { … } → var x; var i = a.iterator (); while ((x = i.next_value ()) != null) {...} + foreach (var x in a) { … } → var i = a.iterator (); while (i.next ()) { var x = i.get (); … } + +If appropriate, providing methods that match these prototypes will allow use of the sugar. + +``contains`` must return ``bool``. + +Iterators require an intermediate object to be the holder of the iteration state. That class must implement a next_value function that returns the next value or null if iteration is to stop or it may have a next method with signature ``bool next ()`` that moves to the next element and returns true if there is one and a method ``T get ()`` to retrieve the current value of the iterator. It is rare for a C program to have the interface needed to do this. + +Use your best judgement in deciding whether or not to use these conventions. This is modifying the interface, but it does tend to make the resulting interface easier to use. + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types.rst b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types.rst new file mode 100644 index 0000000..c1d013d --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types.rst @@ -0,0 +1,8 @@ +Binding a C Function's Parameter and Return Types +================================================= + +.. toctree:: + :maxdepth: 2 + :glob: + + 07-00-binding-a-c-function-s-parameter-and-return-types/* \ No newline at end of file diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-01-basic-types.rst b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-01-basic-types.rst new file mode 100644 index 0000000..2da489c --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-01-basic-types.rst @@ -0,0 +1,4 @@ +Basic Types +=========== + +The most basic types (``int``, ``double``, ``size_t``) can simply be translated. There are various version of some types (e.g., ``uint32_t`` and ``u_int32_t`` are the same, but defined in different headers), but this can all be harmonised when binding. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-02-structs.rst b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-02-structs.rst new file mode 100644 index 0000000..2540873 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-02-structs.rst @@ -0,0 +1,45 @@ +Structs +======= + +The majority of libraries receive structs passed by reference and it is also the default behaviour of Vala to pass structs by reference. So to pass a struct as an argument in a function or method call you just need to specify the type of struct and the variable name. For example the C code: + +.. code-block:: c + + typedef struct foo { + int x; + int y; + }; + void compute_foo(foo *f); + +would be bound as: + +.. code-block:: vala + + [CCode (cname = "foo", has_type_id = false)] + public struct Foo { + public int x; + public int y; + }; + void compute_foo(Foo f); + +Very rarely a C library function is written to receive a struct passed by value and not reference. You will see the ``struct`` keyword used in the C function's parameter. You may also see ``const struct``. To get Vala to pass the struct by value the ``[SimpleType]`` annotation needs to be added to the Vala binding of the struct. The following pattern in C: + +.. code-block:: c + + typedef struct foo { + int x; + int y; + }; + void compute_foo(struct foo f); + +would be bound as: + +.. code-block:: vala + + [CCode (cname = "foo", has_type_id = false)] + [SimpleType] + public struct Foo { + public int x; + public int y; + } + void compute_foo(Foo f); diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-03-arrays.rst b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-03-arrays.rst new file mode 100644 index 0000000..6d90155 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-03-arrays.rst @@ -0,0 +1,47 @@ +Arrays +====== + +Vala arrays are designed to match most of the C array semantics. Since C arrays, generally, have no explicit length, Vala needs special hints to know what to do. There are several cases for the length of an array, discussed below. For a parameter, a ``CCode`` attribute attached to that parameter controls the array's binding. For a return value, the ``CCode`` attribute **of the method** controls the array's binding. + + +Array Length is Passed as an Argument +------------------------------------- + +By default, Vala assumes the first case and does the following transformation: + +.. code-block:: vala + + void foo (double[] array); + double[] foo (float f); + +.. code-block:: c + + void foo(double *array, int array_length); + double *foo(float f, int *array_length); + +If the C code does this, there are still two potential mismatches: the order of parameters and the type of the array length. Often, the array length is a ``size_t`` or ``unsigned int``. The ``array_length_pos`` can move the position of the array's length parameter, see :doc:`Changing the Position of Parameters <../05-00-fundamentals-of-binding-a-c-function/05-05-changing-the-position-of-generated-arguments>`. The ``array_length_type`` specifies a string with the C type of the array (e.g., ``size_t``). + + +Array is Null-Terminated +------------------------ + +The ``array_null_terminated`` will assume the array is null terminated, like a string is, and set the array length automatically by iterating over the items in the array. Since Vala always allocates padding in arrays with the final element as null, passing a Vala-declared array in does not involve modifying the array in any way. + + +Array Length is a Constant Expression +------------------------------------- + +The ``array_length_cexpr`` can be set to the C expression that populates the array's value. It does not have access to the array, the instance of the object being called, or any other context. It must be a context-free expression. + + +Array Length is Unknown +----------------------- + +If the array length is unknown, setting ``array_length = false`` in the ``CCode`` attribute will cause Vala to set the array's ``.length`` property to -1 and not pass the length when used as a parameter. + + +Array Length is Known by Some Awkward Means +------------------------------------------- + +This is only applicable for arrays being returned. If the array's length can be determined, but non-trivially, a wrapper function can be included that sets the array's ``.length property`` to the correct value. See :doc:`Array Lengths <../10-00-awkward-situations/array-lengths>`. + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-04-strings-and-buffers.rst b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-04-strings-and-buffers.rst new file mode 100644 index 0000000..6283a08 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-04-strings-and-buffers.rst @@ -0,0 +1,8 @@ +Strings and Buffers +=================== + +In C, strings and buffers are generally treated like arrays, but Vala may require slightly more finesse. In Vala, a string is a null-terminated list of UTF-8 data that is immutable. If the use case is anything but that, an array of ``uint8`` is the prefered way of dealing with that data. + +Frequently, functions take a buffer, fill it with a string and then return the buffer or null (e.g., ``realpath``\(3)). The buffer should be a ``uint8[]`` and the return value an ``unowned string?``, typically. + +Again, check thoroughly for the ownership of strings being returned. Frequently, the caller does not free the string, especially if it is marked ``const``. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-05-function-pointers.rst b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-05-function-pointers.rst new file mode 100644 index 0000000..a85b0a4 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-05-function-pointers.rst @@ -0,0 +1,34 @@ +Function Pointers +================= + +Function pointers in C are bound as delegates in Vala. A delegate is a type that declares the function signature a function pointer should have. A function pointer can also have an associated data parameter called a target. + +For delegates without targets, they can simply be treated as simple types. + +For targeted delegates, the target must be included. Vala, by default, assumes this will be after the function pointer itself, but this can be adjusted with the ``delegate_target_pos``. The position where the target is received is defined in the delegate's definition; not the calling function. + +A delegate with a target cannot be trivially duplicated, since the target must also be duplicated. Thus, targeted delegates are treated much like singly-owned classes, which can be reassigned, but not multiply referenced. + +If the method is going to retain a reference to the delegate, then it needs a helper function to destroy the delegate after it has finished. This position is after the target, but can be set with the ``delegate_target_destroy_notify_pos``. + +If a delegate is being returned, which is rather rare, the target and destroy notifier are assumed to be out parameters. + +.. code-block:: c + + typedef void (*foo_func)(int x, void *context); + + void call_foo(foo_func f, void *context); + void call_foo_later(foo_func f, void *context, void(*free_context)(void*)); + foo_func get_foo(void **context); + foo_func make_foo(void **context, void(**free_context)(void*)); + +.. code-block:: vala + + [CCode (cname = "foo_func", has_target = true)] + public delegate void FooFunc (int x); + + public void call_foo (FooFunc f); + public void call_foo_later (owned FooFunc f); + public unowned FooFunc get_foo (); + public FooFunc make_foo (); + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-06-parameters-of-variable-type-generics.rst b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-06-parameters-of-variable-type-generics.rst new file mode 100644 index 0000000..270acbb --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-06-parameters-of-variable-type-generics.rst @@ -0,0 +1,84 @@ +Parameters of Variable Type (Generics) +====================================== + +Vala's generics can be applied to C functions using void pointers as generic value arguments. Memory management and generics tend not to get along well, so it may be beneficial to avoid this situation where possible. In particular, generic structs that own instances of the generic can behave strangely. Also, putting owned structs in a generic collection can break. + +Before starting, determine the scope of the type variable: does it apply to the method or class? Generics are paired with a delegate. Bind the delegate as follows: + +.. code-block:: c + + typedef int (*foo_func)(void *a, void *b, void* context); + +.. code-block:: vala + + [CCode (cname = "foo_func", simple_generics = true)] + public delegate int FooFunc (T a, T b); + +Generic Methods +--------------- + +Frequently, a single method is the context for the generic type variable. Simply apply ``simple_generics`` to the ``CCode`` attribute: + +.. code-block:: c + + void sort(void **array, int array_length, foo_func compare, void *context); + +.. code-block:: vala + + [CCode (simple_generics = true)] + public void sort (T[] array, FooFunc compare); + +Occasionally, this is not a C function, but a function-like macro that takes the type name (e.g., ``va_arg``), in which case, set ``generic_type_pos`` to the position of the argument: + +.. code-block:: c + + #define sort(array, type, compare, context) ... + +.. code-block:: vala + + [CCode (generic_type_pos = 1.1)] + public void sort (T[] array, FooFunc compare); + +Generic Classes and Structs +--------------------------- + +If a data structure is container-like, then it may be possible to bind the structure using generics. However, Vala's assumptions about generic structures are rather rigid, so this may be impossible. + +* Create a type variable over the class. +* Decorate all methods that use the type variable with simple_generics. +* Constructors for classes are expected to take the destructor as an argument if ``simple_generics`` is supplied. If the constructor takes no arguments, convert all constructors to static methods with ``simple_generics``. +* Verify all ownership. When Vala emits ``simple_generics`` code of an ``owned`` variable, it always passes the destructor. Frequently, C programs are written where the destructor is passed once in the constructor. In this case, set the destructor to be null, and insist that all values be unowned. + + +The User Pointer Case +--------------------- + +Often, C libraries will have a pointer for some user data associated with an object that is left entirely in the hands of the user. This is easily bound. + +.. code-block:: c + + typedef struct foo Foo; + void *foo_get_userptr(Foo*); + void foo_set_userptr(Foo*,void*); + +.. code-block:: vala + + public class Foo { + public unowned T? user_data { + [CCode (cname = "foo_get_userptr", simple_generics = true)] get; + [CCode (cname = "foo_set_userptr", simple_generics = true)] set; + } + } + +The only caveat is this is rather infectious: the ``simple_generics`` attribute must be applied to all methods use of ``Foo`` in other contexts, including arrays of that object and other classes that contain that type. To avoid this, the alternate binding is: + +.. code-block:: vala + + public class Foo { + [CCode (simple_generics = true)] + public void set_user_ptr (T value); + [CCode (simple_generics = true)] + public T get_user_ptr (); + } + +However, this scheme is less type-safe. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-07-pointers.rst b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-07-pointers.rst new file mode 100644 index 0000000..b560d42 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/07-00-binding-a-c-function-s-parameter-and-return-types/07-07-pointers.rst @@ -0,0 +1,4 @@ +Pointers +======== + +If you've worked this far down the list and the thing still seems to need to be a pointer, then a pointer it is, but this is a badge of shame. \ No newline at end of file diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields.rst b/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields.rst new file mode 100644 index 0000000..44b59bb --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields.rst @@ -0,0 +1,10 @@ +Binding a C Struct's Fields +=========================== + +Compact classes, structs, and simple-type structs may have fields. Often, classes will be opaque; that is, there will be no information about the contents of the class. If so, skip this section. When binding fields, first check that there are no getter/setter functions of the same names (see :doc:`Properties <../06-00-adding-vala-friendly-semantics/properties>`). Often times, the details of the structure are in the header, but not intended for public consumption; avoid binding variables that should not be accessed. Consult the documentation. + +.. toctree:: + :maxdepth: 2 + :glob: + + 08-00-binding-a-c-struct-s-fields/* \ No newline at end of file diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-01-structs.rst b/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-01-structs.rst new file mode 100644 index 0000000..f127906 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-01-structs.rst @@ -0,0 +1,4 @@ +Structs +======= + +Any simple types (``int``\s, ``double``\s, ``enum``\s, or simple types found in the same binding) can simply be bound by preceding them with ``public``. This also applies to any parented structs that are not pointed to directly (i.e., they are ``foo f;`` not ``foo *f;``) diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-02-pointers-to-structs.rst b/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-02-pointers-to-structs.rst new file mode 100644 index 0000000..f3ca29f --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-02-pointers-to-structs.rst @@ -0,0 +1,26 @@ +Pointers to Structs +=================== + +Any field referenced as a pointer is slightly more complex. + +If the type is a parented struct or the field is possibly null, suffix the type with a question mark. + +.. code-block:: c + + foo_t *myfoo; + +.. code-block:: vala + + public foo? myfoo; + +The next question is: is the reference owned? If the value was overwritten, should the destructor be called? If the answer is no, then prefix with ``unowned``. This is often the case for a tree structure that has parent pointers. + +.. code-block:: c + + foo_t *parent; + +.. code-block:: vala + + public unowned Foo parent; + +If unowned is missing, a double-free event will occur when the field is overwritten. If it is included when not needed, there will be a memory leak. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-03-arrays.rst b/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-03-arrays.rst new file mode 100644 index 0000000..e31193c --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-03-arrays.rst @@ -0,0 +1,59 @@ +Arrays +====== + +Arrays come in two varieties in C: a pointer to allocated memory or included in the structure. Vala follows a similar convention: + +.. code-block:: c + + int foo[20]; + int *bar; + +.. code-block:: vala + + public int foo[20]; + public int[] bar; + +Note the position of the square brackets in the Vala versions. For fixed-length arrays Vala expects the square brackets (as well as the length) to follow the variable name, whereas for dynamically-sized arrays Vala expects the square brackets to follow the type (and not contain a length). + +Again, if the array may be null, suffix the type with a question mark. + +Vala arrays have lengths associated with them. Often, C programmers do this too: + +.. code-block:: c + + int *foo; + size_t foo_count; + +which is bound as: + +.. code-block:: vala + + [CCode (array_length_cname = "foo_count", array_length_type = "size_t")] + public int[] foo; + +Often, the size will not be included, by the array will be null-terminated: + +.. code-block:: c + + Foo **foos; + +.. code-block:: vala + + [CCode (array_null_terminated = true)] + public Foo[] foos; + +Occasionally, the length is not included, but defined elsewhere, such as a constant: + +.. code-block:: c + + /* Array length must be FOO_COUNT */ + Foo **foos; + +.. code-block:: vala + + [CCode (array_length_cexpr = "FOO_COUNT")] + public Foo[] foos; + +Since Vala will only allow a numeric value as an array length, using a ``array_length_cexpr`` may be convenient if the array length can vary as new releases of the library occur. + +Vala does not really do C-style stacked arrays (a.k.a. ragged multi-dimensional arrays), so binding them as arrays is nigh impossible without extra C code.Since Vala's pointer semantics are the same, they can be treated as pointers though. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-04-function-pointers.rst b/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-04-function-pointers.rst new file mode 100644 index 0000000..f8be6f5 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-04-function-pointers.rst @@ -0,0 +1,68 @@ +Function Pointers +================= + +Fields that are function pointers have more complexity depending on ownership and targeting. If a delegate is targetless then it can be treated as a simple type and no ownership considerations are needed. + +If a delegate has a target then the C structure must have an holder for the target: + +.. code-block:: c + + typedef void(*foo_func)(int a, void *userdata); + + typedef struct { + foo_func callback; + void *callback_context; + } foo; + +.. code-block:: vala + + [CCode (cname = "foo_func")] + public delegate void FooFunc(int a); + + public struct Foo { + [CCode (delegate_target_cname = "callback_context")] + public unowned FooFunc callback; + } + + +Check for nullability as per usual. + +Ownership is slightly more complex as there must be a field to hold a function that will free the context data. In GLib terminology, this is a destroy notification. + +.. code-block:: c + + typedef void(*foo_func)(int a, void *userdata); + + typedef struct { + foo_func callback; + void *callback_context; + void(*callback_free)(void*); + } foo; + +.. code-block:: vala + + [CCode (cname = "foo_func")] + public delegate void FooFunc(int a); + + public struct Foo { + [CCode (delegate_target_cname = "callback_context", delegate_target_destroy_notify_cname = "callback_free")] + public FooFunc callback; + } + +If the function pointer will be called exactly once and calling it should result in destruction of the context then use ``scope = "async"``. + +.. code-block:: c + + typedef void(*start_job)(int priority, void *context); + + void threadpool_queue_job(Pool *p, start_job j, void *context); + +.. code-block:: vala + + [CCode (scope = "async", cname = "start_job")] + public delegate void StartJob (int priority); + + public class ThreadPool { + public void queue_job (StartJob j); + } + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-05-unions.rst b/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-05-unions.rst new file mode 100644 index 0000000..9a208a0 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/08-00-binding-a-c-struct-s-fields/08-05-unions.rst @@ -0,0 +1,26 @@ +Unions +====== + +Vala doesn't understand unions, but the names within the union can be held as part of the cname. + +.. code-block:: c + + typedef struct { + bool which_one; + union { + double d; + int i; + } data; + } foo_t; + +.. code-block:: vala + + public struct Foo { + public bool which_one; + [CCode (cname = "data.d")] + public double data_d; + [CCode (cname = "data.i")] + public int data_i; + } + + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/09-00-extra-hints.rst b/source/developer-guides/bindings/writing-a-vapi-manually/09-00-extra-hints.rst new file mode 100644 index 0000000..863091b --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/09-00-extra-hints.rst @@ -0,0 +1,9 @@ +Extra Hints +=========== + +You can bind a method multiple times. In particular, constructors that take a parent object often make sense as both constructors in the child and methods of the parent instance. + +Sometimes, `cname = "void"` for a class can get around bad typedefs, but never for delegates as casting a void pointer to a function pointer is not legal C. + +Feel free to add useful methods to the class definition if they make something more Vala-like. + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations.rst b/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations.rst new file mode 100644 index 0000000..a41b98f --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations.rst @@ -0,0 +1,10 @@ +Awkward Situations +================== + +There are a number of awkward situations that come up frequently enough to deserve answers. + +.. toctree:: + :maxdepth: 2 + :glob: + + 10-00-awkward-situations/* \ No newline at end of file diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-01-array-lengths.rst b/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-01-array-lengths.rst new file mode 100644 index 0000000..b14c3b4 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-01-array-lengths.rst @@ -0,0 +1,42 @@ +Array Lengths +============= + +Sometimes functions which return an array include lengths, but not the way Vala expects. The two most common are: + +.. code-block:: c + + int get_array(foo**out_array_p); + + struct { + foo *data; + int size; + } array_with_length; + void get_data(array_with_length *output); + +which can be bound as: + +.. code-block:: vala + + [CCode (cname = "get_array")] + private int _get_array ([CCode (array_length = false)] out foo[] a); + [CCode (cname = "vala_get_array")] + public foo[] get_array () { + foo[] temp; + var len = _get_array (out temp); + temp.length = len; + return (owned) temp; + } + + [CCode (cname = "array_with_length", destroy_function = "")] + private struct array_with_length { + [CCode (array_length_name = "size")] + foo[] data; + } + [CCode (cname = "get_data")] + private void _get_data (out array_with_length a); + [CCode (cname = "vala_get_data")] + public foo[] get_data () { + array_with_length temp; + _get_data (out temp); + return (owned) a.data; + } diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-02-dependently-typed-ownership.rst b/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-02-dependently-typed-ownership.rst new file mode 100644 index 0000000..68328be --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-02-dependently-typed-ownership.rst @@ -0,0 +1,46 @@ +Dependently Typed Ownership +=========================== + +A function may take ownership of an object conditionally. This can be true depending on parameters or return value. In the case of parameters, the function can be bound as such: + +.. code-block:: c + + void somefunc(foo *data, bool free_when_done); + +.. code-block:: vala + + [CCode (cname = "somefunc")] + private _somefunc(Foo data, bool free_when_done); + [CCode (cname = "")] + private _sink_foo (owned Foo foo); + [CCode (cname = "vala_somefunc")] + public somefunc (Foo data) { + _somefunc(data, false); + } + [CCode (cname = "vala_somefunc_owned")] + public somefunc_owned (owned Foo data) { + _somefunc (data, true); + _sink_foo ((owned) foo); + } + +This is more awkward when the return code is source of the dependent typing. One option is as follows: + +.. code-block:: c + + /* foo is freed if return value is 3. */ + int awkward(foo*); + +.. code-block:: vala + + [CCode (cname = "")] + private void _sink_foo (owned Foo f); + [CCode (cname = "awkward")] + private int _awkward (Foo f); + [CCode (cname = "vala_awkward")] + public int awkward (ref Foo f) { + var ret = _awkward (f); + if (ret == 3) + _sink_foo ((owned)f); + return ret; + } + diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-03-member-length.rst b/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-03-member-length.rst new file mode 100644 index 0000000..f90daa1 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-03-member-length.rst @@ -0,0 +1,14 @@ +Member Length +============= + +When dealing with raw-ish memory access, there is a common pattern to have: + +.. code-block:: c + + void foo(void *data, size_t size, size_t nmemb); + +in these cases, it is generally best to simply fix the type of data to ``uint8`` and use the right size as a default parameter: + +.. code-block:: vala + + public void foo([CCode (array_length_pos = 2.1)] uint8[] data, size_t size = 1); diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-04-owned-array-of-unowned-objects.rst b/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-04-owned-array-of-unowned-objects.rst new file mode 100644 index 0000000..2ebe588 --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-04-owned-array-of-unowned-objects.rst @@ -0,0 +1,3 @@ +Owned Array of Unowned Objects +============================== +Vala does not have a convenient way to express the an owned array of unowned objects. See `bug 571486 `_. diff --git a/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-05-shared-context-delgates.rst b/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-05-shared-context-delgates.rst new file mode 100644 index 0000000..7ef14bb --- /dev/null +++ b/source/developer-guides/bindings/writing-a-vapi-manually/10-00-awkward-situations/10-05-shared-context-delgates.rst @@ -0,0 +1,22 @@ +Shared Context Delegates +======================== + +When multiple delegates are passed, they sometimes share a context pointer: + +.. code-block:: c + + void foo(void *context, void(*x)(int a, void *context), void(*y)(double a, void *context)); + +Here, `x` and `y` are meant to share context, but Vala's delegates do not have a way of expressing this. However, there is a work around: + +.. code-block:: vala + + [CCode (simple_generics = true, has_target = false)] + public void X (int a, T context); + [CCode (simple_generics = true, has_target = false)] + public void Y (double a, T context); + [CCode (simple_generics = true)] + public void foo (T context, X x, Y y); + + +This does not easily permit passing a lambda, but it does make passing a class or struct rather practical. diff --git a/source/developer-guides/index.rst b/source/developer-guides/index.rst new file mode 100644 index 0000000..90ec38d --- /dev/null +++ b/source/developer-guides/index.rst @@ -0,0 +1,8 @@ +Developer Guides +================ + +.. toctree:: + :glob: + :maxdepth: 2 + + * diff --git a/source/index.rst b/source/index.rst index 2ef87bb..d44e87e 100644 --- a/source/index.rst +++ b/source/index.rst @@ -7,6 +7,7 @@ Vala Documentation About Installation Guide Tutorials + Developer Guides Introduction ------------