diff --git a/source/tutorials/programming-language/main/06-00-libraries/06-02-creating-a-library.rst b/source/tutorials/programming-language/main/06-00-libraries/06-02-creating-a-library.rst index 2e1682f..02bae02 100644 --- a/source/tutorials/programming-language/main/06-00-libraries/06-02-creating-a-library.rst +++ b/source/tutorials/programming-language/main/06-00-libraries/06-02-creating-a-library.rst @@ -1,145 +1,6 @@ Creating a Library ================== -Using Autotools ---------------- - -It is possible to use Autotools to create a library written in Vala. A library is created by using C code generated by Vala compiler, linked and installed as any other library. Then you need tell which C files must be used to create the library and which of them must be distributable, allowing others to compile a tarball without Vala using standard Autotools commands: *configure*, *make* and *make install*. - -Example -~~~~~~~ - -This example was taken from GXml recent additions. GXmlDom is a library aimed to have a GObject based libxml2 replacement; is written in Vala and originally used to use WAF to build. - -* **valac** can be used to generate C code and headers from Vala sources. At this time is possible to generate a GObjectIntrospection and the VAPI file from the vala sources too. -* **gxml.vala.stamp** is used as the code sources for our library. - -It's important to add --pkg switches in order to valac to success and set all CFLAGS and LIBS required by the C library to compile and link against. - -.. code-block:: shell - - NULL = - - - AM_CPPFLAGS = \ - -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ - -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \ - -DPACKAGE_DATA_DIR=\""$(datadir)"\" - - BUILT_SOURCES = gxml.vala.stamp - CLEANFILES = gxml.vala.stamp - - AM_CFLAGS =\ - -Wall\ - -g \ - $(GLIB_CFLAGS) \ - $(LIBXML_CFLAGS) \ - $(GIO_CFLAGS) \ - $(GEE_CFLAGS) \ - $(VALA_CFLAGS) \ - $(NULL) - - lib_LTLIBRARIES = libgxml.la - - VALAFLAGS = \ - $(top_srcdir)/vapi/config.vapi \ - --vapidir=$(top_srcdir)/vapi \ - --pkg libxml-2.0 \ - --pkg gee-1.0 \ - --pkg gobject-2.0 \ - --pkg gio-2.0 \ - $(NULL) - - libgxml_la_VALASOURCES = \ - Attr.vala \ - BackedNode.vala \ - CDATASection.vala \ - CharacterData.vala \ - Comment.vala \ - Document.vala \ - DocumentFragment.vala \ - DocumentType.vala \ - DomError.vala \ - Element.vala \ - Entity.vala \ - EntityReference.vala \ - Implementation.vala \ - NamespaceAttr.vala \ - NodeList.vala \ - NodeType.vala \ - Notation.vala \ - ProcessingInstruction.vala \ - Text.vala \ - XNode.vala \ - $(NULL) - - libgxml_la_SOURCES = \ - gxml.vala.stamp \ - $(libgxml_la_VALASOURCES:.vala=.c) \ - $(NULL) - - # Generate C code and headers, including GObject Introspection GIR files and VAPI file - gxml-1.0.vapi gxml.vala.stamp GXml-1.0.gir: $(libgxml_la_VALASOURCES) - $(VALA_COMPILER) $(VALAFLAGS) -C -H $(top_builddir)/gxml/gxml-dom.h --gir=GXmlDom-1.0.gir --library gxmldom-1.0 $^ - @touch $@ - - - # Library configuration - libgxml_la_LDFLAGS = - - libgxml_la_LIBADD = \ - $(GLIB_LIBS) \ - $(LIBXML_LIBS) \ - $(GIO_LIBS) \ - $(GEE_LIBS) \ - $(VALA_LIBS) \ - $(NULL) - - include_HEADERS = \ - gxml.h \ - $(NULL) - - pkgconfigdir = $(libdir)/pkgconfig - pkgconfig_DATA = libgxml-1.0.pc - - gxmlincludedir=$(includedir)/libgxml-1.0/gxml - gxmlinclude_HEADERS= gxml-dom.h - - # GObject Introspection - - if ENABLE_GI_SYSTEM_INSTALL - girdir = $(INTROSPECTION_GIRDIR) - typelibsdir = $(INTROSPECTION_TYPELIBDIR) - else - girdir = $(datadir)/gir-1.0 - typelibsdir = $(libdir)/girepository-1.0 - endif - - # GIR files are generated automatically by Valac so is not necessary to scan source code to generate it - INTROSPECTION_GIRS = - INTROSPECTION_GIRS += GXmlDom-1.0.gir - INTROSPECTION_COMPILER_ARGS = \ - --includedir=. \ - --includedir=$(top_builddir)/gxml - - GXmlDom-1.0.typelib: $(INTROSPECTION_GIRS) - $(INTROSPECTION_COMPILER) $(INTROSPECTION_COMPILER_ARGS) $< -o $@ - - gir_DATA = $(INTROSPECTION_GIRS) - typelibs_DATA = GXmlDom-1.0.typelib - - vapidir = $(VALA_VAPIDIR) - vapi_DATA=gxmldom-1.0.vapi - - CLEANFILES += $(INTROSPECTION_GIRS) $(typelibs_DATA) gxml-1.0.vapi - - EXTRA_DIST = \ - libgxml-1.0.pc.in \ - $(libgxml_la_VALASOURCES) \ - $(typelibs_DATA) \ - $(INTROSPECTION_GIRS) \ - gxml.vala.stamp - Compilation and linking using Command Line ------------------------------------------ @@ -150,7 +11,7 @@ Vala is not yet capable of directly creating dynamic or static libraries. To cre $ valac -c ...(source files) $ ar cx ...(object files) -or by compiling the intermediate C code with *gcc* +or by compiling the intermediate C code in the compiler of you choice. We'll be using *gcc* in these examples. .. code-block:: console @@ -228,3 +89,16 @@ You can also create a GObjectIntrospection GIR file for your library with the `` GIR files are XML descriptions of the API. +This will generate a GIR file named ``Test-1.0.gir``. The name of the GIR file should follow the GObject Introspection +naming conventions and include an API version number. + +A typelib file can then be generated from the GIR using g-ir-compiler: + +.. code-block:: console + + g-ir-compiler --output MyLibrary-1.0.typelib MyLibrary-1.0.gir + +GIR files are typically used to generate compile time bindings. +Typelib files are used to create runtime bindings and a binding generator +will read them using ``libgirepository``. + diff --git a/source/tutorials/programming-language/main/06-00-libraries/06-04-abi-and-api-design-choices.rst b/source/tutorials/programming-language/main/06-00-libraries/06-04-abi-and-api-design-choices.rst new file mode 100644 index 0000000..ab30af8 --- /dev/null +++ b/source/tutorials/programming-language/main/06-00-libraries/06-04-abi-and-api-design-choices.rst @@ -0,0 +1,102 @@ +ABI and API Design Choices +========================== + +ABI +--- + +``abit-compliance-checker`` is a cross-platform tool for checcking the stability +of an ABI. Supported platforms are GNU/Linux, FreeBSD, Mac OS X and MS Windows. +See `ABI Compliance Checker `_ for +more details. + +The tool uses debug symbols to generate an ABI profile of a shared library: + +.. code-block:: console + + abi-dumper my_library.so -o ABI-0.dump -lver 0 + +This is then repeated for the new version of the library: + +.. code-block:: console + + abi-dumper my_library.so -o ABI-1.dump -lver 1 + +A report is then generated with: + +.. code-block:: console + + abi-compliance-checker -l my_library -old ABI-0.dump -new ABI-1.dump + +The report is an HTML file showing changes in the ABI. +An `example report for Vala `_ is available online. + +API Design +---------- + +Avoid Custom Constructors +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following example contains a custom constructors: + +.. code-block:: vala + + public class MyClass : Object { + private string value; + + public MyClass (string contents) { + value = contents; + } + } + + +This will be translated to C as the function name ``my_class_new`` and can be called with a string argument to create the object. + +The problem is GObject has an alternative way of creating an object. In Vala this is of the form: + +.. code-block:: vala + + void main () { + Object.new (typeof(MyClass)); + } + +The Vala ``Object.new`` method is bound to GObject `g_object_new `_ function in C and is often used to instantiate GObjects. +This can be from C, but also from languages using GObject introspection bindings. The problem is the construction defined Vala is not called. + +Vala does have a way to run a function at instantiation time that is the use of the construct {} in the class. +See :doc:`GObject Style Construction page ` +in the :doc:`Vala Main Tutorial ` in the Vala tutorial. + +Avoid Using varargs +~~~~~~~~~~~~~~~~~~~ + +A function with a variable number of arguments is not introspectable. +Although the GObject Introspection Repository will contain a method or function that can be called with a variable +number of arguments, the method or function will be marked as ``introspectable="0"``. This causes binding generators to +ignore the method or function. In Vala this can be overridden using ``skip = false`` in the metadata, but such +techniques are not available in all bindings. + +Avoid Using Generics +~~~~~~~~~~~~~~~~~~~~ + +Since GObject Introspection does not handle generics, using them in APIs is harmful, since GI will generate 3 new +parameters in the constructors of each generic class: one for the GType function, one for the duplication function and +another for the destruction. These parameters are quite complicated to handle in languages like Python or Javascript. + +In addition to this, the properties that expose the generic type parameter will be exposed as ``gpointer``s, which makes it +even more complicated. Even generic methods like Gee's ``add ()`` will expect a ``gpointer`` in GI, so doing something like +this in Python will result in an error, contrary to what you expect. + +.. code-block:: python + + list = get_a_list_of_strings () + list.add ('Hi') + +Further Reading +--------------- + +- `APIs, like diamonds, are forever `_ - some criteria for good API design +- `Libraries in Vala - ABI compatibility - part I `_ +- `Libraries in Vala - ABI compatibility - part II `_ +- `Writing Bindable APIs (GObject Intropsection) `_ +- `Minimalistic example of the GLib's GBoxedType usage `_ - explanation of basic types when used with GObject Introspection + and how to bind structs diff --git a/source/tutorials/programming-language/main/06-00-libraries/06-05-binding-to-vala-libraries-from-other-languages.rst b/source/tutorials/programming-language/main/06-00-libraries/06-05-binding-to-vala-libraries-from-other-languages.rst new file mode 100644 index 0000000..c36043e --- /dev/null +++ b/source/tutorials/programming-language/main/06-00-libraries/06-05-binding-to-vala-libraries-from-other-languages.rst @@ -0,0 +1,73 @@ +Binding to Vala Libraries from Other Languages +============================================== + +Vala produces C code and also produces C headers. Binding from C is relatively easy, although the library may make use +of a lot of GObject boiler plate code. + +For Vala based projects, using either the Vala or Genie syntax, a VAPI can be produced that makes bindings easy. + +The Vala compiler can also produce a GObject Introspection Repository (GIR) file. This makes bindings from languages +that support GObject Introspection very easy. Often the binding is at runtime so a typelib file +also needs to be produced and libgirepository and libffi are used at runtime for the binding. + +Haskell +------- + +As of January 2017 the Haskell generator from GObject introspection repositories, haskell-gi, is described as complete. +The Haskell wiki page on GObject Introspection advises "The Haskell code generator at haskell-gi is now essentially +complete: all the information exposed in the bindings should now be available from the autogenerated bindings. +This includes: ordinary functions, signals, virtual functions, structure fields, object properties, etc." + +`haskell-gi `_ - Generate Haskell bindings for GObject-Introspection capable libraries + +JavaScript +---------- + +`node-gtk `_ - "uses the GObject Introspection library (as PyGObject, for example), so any gobject-introspectable library is supported" + +`node-gir `_ - "Node-gir is Node.js bindings to GObject Introspection making it +possible to make automatic and dynamic calls to any library that has GI annotations installed...With it you can also +write the performance-intensive parts of your applications in Vala and call them from Node.js and other languages." + +Lua +--- + +`LGI `_ provides runtime bindings for Lua 5.1+ and LuaJIT2. It uses libgirepository to read typelib files. + +There are alternative binding generators: lgob and LuiGI. `lgob `_ parses +GIR files to generate Lua modules. LuiGI was an experimental dynamic binding generator. LGI should be used instead of LuiGI. + +- `LGI `_ - "LGI is gobject-introspection based dynamic Lua binding to GObject based libraries...LGI is tested and + compatible with standard Lua 5.1, Lua 5.2, Lua 5.3 and LuaJIT2." +- `lgob `_ - "lgob provides bindings of GObject-based libraries (like GTK+ and WebKitGTK+), for Lua 5.1 / 5.2 / LuaJIT. + It consists of a compiler that parses GObject-Instrospection gir files and generates Lua modules. lgob ships with + bindings for GTK+, pango, cairo, vte, WebKitGtk, GtkTextView, and others" +- `Some thoughts (and code) around GObject-Introspection `_- blog post + from 2010 about the origins of LuiGI, "the kind people there made me note about LGI, which is also a dynamic GI binding + for Lua...but looking at its code I can tell that it is more complete than my own, so I will be probably contributing + to it instead of duplicating efforts" + +Perl +---- + +`perl-Glib-Object-Introspection `_ creates Perl bindings at runtime from a typelib file. + +- `Glib::Object::Introspection `_ - CPAN module + of `perl-Glib-Object-Introspection `_. The CPAN page includes examples. + +Python +------ + +`PyGObject `_ is a Python package providing bindings using GObject introspection. + +- `PyGObject Documentation `_ - "PyGObject provides full support of GObject Introspection and all of its features (callbacks, GVariant support, closures, sub-classing, etc.)" +- `PyGObject source repository at GNOME GitLab `_ +- `pgi-docgen `_ - GitHub repository of the API Documentation Generator for PyGObject +- `PyGObject API Reference `_ - pre-built API documentation for numerous libraries available through PyGObject + +Rust +---- + +The `gtk-rs `_ project has developed the ``gir`` tool to generate Rust bindings from a GIR file. + +- `gtk-rs/gir `_ - GitHub repository for the ``gir`` tool. A GIR file is needed and an additional TOML file is used to pass binding metadata to the tool diff --git a/source/tutorials/programming-language/main/06-00-libraries/06-06-using-autotools.rst b/source/tutorials/programming-language/main/06-00-libraries/06-06-using-autotools.rst new file mode 100644 index 0000000..59b3621 --- /dev/null +++ b/source/tutorials/programming-language/main/06-00-libraries/06-06-using-autotools.rst @@ -0,0 +1,145 @@ +Using Autotools +--------------- + +.. note:: + + There are multiple :doc:`build systems ` you could use create a library in Vala + (Meson is the recommended one right now). + + This page is remains here for legacy purposes. + +It is possible to use Autotools to create a library written in Vala. A library is created by using C code generated by Vala compiler, linked and installed as any other library. Then you need tell which C files must be used to create the library and which of them must be distributable, allowing others to compile a tarball without Vala using standard Autotools commands: *configure*, *make* and *make install*. + +Example +~~~~~~~ + +This example was taken from GXml recent additions. GXmlDom is a library aimed to have a GObject based libxml2 replacement; is written in Vala and originally used to use WAF to build. + +* **valac** can be used to generate C code and headers from Vala sources. At this time is possible to generate a GObjectIntrospection and the VAPI file from the vala sources too. +* **gxml.vala.stamp** is used as the code sources for our library. + +It's important to add --pkg switches in order to valac to success and set all CFLAGS and LIBS required by the C library to compile and link against. + +.. code-block:: shell + + NULL = + + + AM_CPPFLAGS = \ + -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ + -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \ + -DPACKAGE_DATA_DIR=\""$(datadir)"\" + + BUILT_SOURCES = gxml.vala.stamp + CLEANFILES = gxml.vala.stamp + + AM_CFLAGS =\ + -Wall\ + -g \ + $(GLIB_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(GIO_CFLAGS) \ + $(GEE_CFLAGS) \ + $(VALA_CFLAGS) \ + $(NULL) + + lib_LTLIBRARIES = libgxml.la + + VALAFLAGS = \ + $(top_srcdir)/vapi/config.vapi \ + --vapidir=$(top_srcdir)/vapi \ + --pkg libxml-2.0 \ + --pkg gee-1.0 \ + --pkg gobject-2.0 \ + --pkg gio-2.0 \ + $(NULL) + + libgxml_la_VALASOURCES = \ + Attr.vala \ + BackedNode.vala \ + CDATASection.vala \ + CharacterData.vala \ + Comment.vala \ + Document.vala \ + DocumentFragment.vala \ + DocumentType.vala \ + DomError.vala \ + Element.vala \ + Entity.vala \ + EntityReference.vala \ + Implementation.vala \ + NamespaceAttr.vala \ + NodeList.vala \ + NodeType.vala \ + Notation.vala \ + ProcessingInstruction.vala \ + Text.vala \ + XNode.vala \ + $(NULL) + + libgxml_la_SOURCES = \ + gxml.vala.stamp \ + $(libgxml_la_VALASOURCES:.vala=.c) \ + $(NULL) + + # Generate C code and headers, including GObject Introspection GIR files and VAPI file + gxml-1.0.vapi gxml.vala.stamp GXml-1.0.gir: $(libgxml_la_VALASOURCES) + $(VALA_COMPILER) $(VALAFLAGS) -C -H $(top_builddir)/gxml/gxml-dom.h --gir=GXmlDom-1.0.gir --library gxmldom-1.0 $^ + @touch $@ + + + # Library configuration + libgxml_la_LDFLAGS = + + libgxml_la_LIBADD = \ + $(GLIB_LIBS) \ + $(LIBXML_LIBS) \ + $(GIO_LIBS) \ + $(GEE_LIBS) \ + $(VALA_LIBS) \ + $(NULL) + + include_HEADERS = \ + gxml.h \ + $(NULL) + + pkgconfigdir = $(libdir)/pkgconfig + pkgconfig_DATA = libgxml-1.0.pc + + gxmlincludedir=$(includedir)/libgxml-1.0/gxml + gxmlinclude_HEADERS= gxml-dom.h + + # GObject Introspection + + if ENABLE_GI_SYSTEM_INSTALL + girdir = $(INTROSPECTION_GIRDIR) + typelibsdir = $(INTROSPECTION_TYPELIBDIR) + else + girdir = $(datadir)/gir-1.0 + typelibsdir = $(libdir)/girepository-1.0 + endif + + # GIR files are generated automatically by Valac so is not necessary to scan source code to generate it + INTROSPECTION_GIRS = + INTROSPECTION_GIRS += GXmlDom-1.0.gir + INTROSPECTION_COMPILER_ARGS = \ + --includedir=. \ + --includedir=$(top_builddir)/gxml + + GXmlDom-1.0.typelib: $(INTROSPECTION_GIRS) + $(INTROSPECTION_COMPILER) $(INTROSPECTION_COMPILER_ARGS) $< -o $@ + + gir_DATA = $(INTROSPECTION_GIRS) + typelibs_DATA = GXmlDom-1.0.typelib + + vapidir = $(VALA_VAPIDIR) + vapi_DATA=gxmldom-1.0.vapi + + CLEANFILES += $(INTROSPECTION_GIRS) $(typelibs_DATA) gxml-1.0.vapi + + EXTRA_DIST = \ + libgxml-1.0.pc.in \ + $(libgxml_la_VALASOURCES) \ + $(typelibs_DATA) \ + $(INTROSPECTION_GIRS) \ + gxml.vala.stamp