{"id":13411398,"url":"https://github.com/Componolit/Cappulada","last_synced_at":"2025-03-14T17:30:46.675Z","repository":{"id":87047498,"uuid":"136463244","full_name":"Componolit/Cappulada","owner":"Componolit","description":"[DEPRECATED] Generate Ada bindings to C++ code","archived":false,"fork":false,"pushed_at":"2019-12-09T12:02:37.000Z","size":535,"stargazers_count":15,"open_issues_count":32,"forks_count":3,"subscribers_count":5,"default_branch":"staging","last_synced_at":"2024-07-31T20:45:46.980Z","etag":null,"topics":["ada","binding-generator","bindings","cpp"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Componolit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-06-07T10:47:52.000Z","updated_at":"2024-01-14T12:16:29.000Z","dependencies_parsed_at":"2023-11-29T17:49:22.052Z","dependency_job_id":null,"html_url":"https://github.com/Componolit/Cappulada","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Componolit%2FCappulada","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Componolit%2FCappulada/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Componolit%2FCappulada/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Componolit%2FCappulada/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Componolit","download_url":"https://codeload.github.com/Componolit/Cappulada/tar.gz/refs/heads/staging","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243618604,"owners_count":20320265,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ada","binding-generator","bindings","cpp"],"created_at":"2024-07-30T20:01:13.407Z","updated_at":"2025-03-14T17:30:46.039Z","avatar_url":"https://github.com/Componolit.png","language":"Python","readme":"# Cappulada\n\n[![Build Status](https://travis-ci.org/Componolit/Cappulada.svg?branch=master)](https://travis-ci.org/Componolit/Cappulada)\n\nCappulada is a tool to generate Ada bindings for C++. It aims to support complex features such as object orientation and templates while keeping a semantically appropriate mapping of namespaces and classes in C++ to packages and types in Ada.\n\n## Function and Features\n\nCappulada uses libclang to parse C++ headers. It converts clangs abstract syntax tree into a custom intermediate representation. While this is still a tree based structure it gets enriched with further information:\n\n- C++ linker symbols\n- Instances of C++ templates\n- Parent relations in the tree\n\nThe intermediate representation is a tree of classes, functions, types, etc. Each of these entities own a function to generate Ada specification snippets. When Ada code is generated the generator traverses the tree and combines those snippets into complete specification files. The specifications are aimed to be SPARK compatible where possible.\n\nThe generated Ada code resides in child packages of a single project package. This project package provides basic builtin types and hosts C++ code that resides in the `::` namespace. To provide a type mapping between C++ and Ada it depends on Ada's `Interfaces.C` package.\n\nThe currently supported C++ features include\n\n- Namespaces and Class\n- Class functions, static functions, member variables\n- Class inheritance with and without virtual functions\n- Function pointers\n- Templates\n\nThis list is not exhaustive. There are various corner cases that still need improvement. Array support has not been implemented, yet, but it is on our TODO list among other features:\n\n- Array support\n- properly handling all clang AST types\n- Crashes on specific template usages\n- visibility issues\n\nTo get a more detailed view check out the [Version 1.0 Project](https://github.com/Componolit/Cappulada/projects/1).\n\n## Installation\n\nInstall dependencies via\n\n- `apt install python-clang-3.8 libclang-3.8-dev`\n- `pip install -r requirements.txt`\n\n\n\n## Tests\n\nSince the tests include validation tests to check if the generated code compiles the [GNAT Toolchain](https://www.adacore.com/download/) is required to run the tests.\n\nRun the tests via `python -m unittest discover tests`.\n\n\n\n## Usage\n\nThe `cappulada` tool takes C++ headers as arguments. Furthermore a project name and a output path can be given. If arguments need to be passed to clang a `--` can be appended as an argument. Anything after that will be directly passed to clang.\n\n```\nusage:\n\tcappulada [-h] [-o OUTDIR] [-p PROJECT] headers [headers ...]\n\nflags:\n\t-h\t\t\tshow help\n\noptions:\n\t-o\t\t\tOutput directory for Ada specs\n\t-p\t\t\tProject name, also the name of the base package in Ada\n```\n\n### Example\n\nThe `example` directory contains an example using a C++ template in Ada. It consists of a C++ class that represents a number and implements methods to add another number and to get its value:\n\n```C++\n//number.h\ntemplate \u003ctypename T\u003e\nclass Number\n{\n    private:\n        T _value;\n    public:\n        Number(T v) : _value(v)\n        { }\n\n        void add(T n)\n        {\n            _value += n;\n        }\n\n        T value()\n        {\n            return _value;\n        }\n};\n```\n\nCappulada currently only creates templates instances for templates that are used in C++ itself as it cannot collect them from Ada. Since this template is never used a dummy class has been added that uses the template.\n\n```C++\nclass Dummy{\n    public:\n        Dummy(Number\u003cint\u003e n)\n        {\n            n.add(1);\n            n.value();\n        }\n};\n```\n\nNow Cappulada recognizes an instance of `Number` that uses `int` and creates an according template instance. Since GCC only exports symbols of functions that are actually used into the binary each class method is called once. Otherwise the linker won't find them when linking against the Ada object.\n\nTo trigger GCC to create an object file a compilation unit is required. This is done via `number.cc` which needs to create an instance of `Dummy`:\n\n````C++\n//number.cc\n#include \u003cnumber.h\u003e\n\nDummy d = Dummy(Number\u003cint\u003e(5));\n````\n\nTo create an Ada binding for this small library Cappulada is called (in this case with the project name `Example`):\n\n```\n$ cappulada -P Example number.h\n```\n\nThis creates a file called `example.ads`. It contains type definitions for standard C types and contains the two classes. The interesting part is the instantiated `Number` class that looks as follows in Ada:\n\n```Ada\npackage Example is\n   ...\n   package Number_T_Int\n      with SPARK_Mode =\u003e On\n   is\n      type Private_Int is limited private;\n      type Private_Int_Address is limited private;\n\n      type Class is\n      limited record\n         Private_X_Value : Private_Int;\n      end record\n      with Import, Convention =\u003e CPP;\n\n      type Class_Address is private;\n\n      function Constructor (V : Example.Int) return Class\n      with Global =\u003e null;\n      pragma Cpp_Constructor (Constructor, \"_ZN6NumberIiEC1Ei\");\n\n      procedure Add (This : Class; N : Example.Int)\n      with Global =\u003e null, Import, Convention =\u003e CPP, External_Name =\u003e \"_ZN6NumberIiE3addEi\";\n\n      function Value (This : Class) return Example.Int\n      with Global =\u003e null, Import, Convention =\u003e CPP, External_Name =\u003e \"_ZN6NumberIiE5valueEv\";\n\n   private\n      pragma SPARK_Mode (Off);\n\n      type Class_Address is access Class;\n      type Private_Int is new Example.Int;\n      type Private_Int_Address is access Private_Int;\n   end Number_T_Int;\n   ...\nend Example;\n```\n\nSince Ada does not support compile time templates the class name is mangled. I contains a `_T` to show that it is a template instance and a `_Int` to show its instantiation type. To keep the memory layout all class members, public, protected and private are included in the class record. Yet only public members are given their original type. All others get a private type which cannot be assigned directly.\n\nThe class functions are imported into the package. Since those are member functions their first argument is the object (which is invisible in C++).\n\nThe example program that uses this library only adds two command line arguments and prints the output:\n\n```Ada\nwith Ada.Command_Line;\nwith Ada.Text_Io;\nwith Example;\n   \nprocedure Add is\n   \n   function Number_Add (X : Integer; Y : Integer) return Integer is\n      A : Example.Number_T_Int.Class :=\n         Example.Number_T_Int.Constructor (Example.Int(X));\n   begin\n      Example.Number_T_Int.Add (A, Example.Int (Y));\n      return Integer(Example.Number_T_Int.Value (A));\n   end Number_Add;\n         \nbegin \n   if Ada.Command_Line.Argument_Count = 2 then\n      Ada.Text_Io.Put_Line (Integer'Image (Number_Add (\n         Integer'Value (Ada.Command_Line.Argument(1)),\n         Integer'Value (Ada.Command_Line.Argument(2))\n         )));\n   end if; \nend Add;\n```\n\nIt imports the Example package and can use the `Number` class natively in Ada. The interesting part happens in `Number_Add`. Since encapsulation and storage are different in Ada from C++ each package that resembles a C++ class has a Class type that stores the data. So an instance of number is of the type `Number_T_Int.Class` and the classes constructor is called via the package function `Number_T_Int.Constructor`. Since the same applies to class methods the first argument here needs to be the object itself. So a call to value (which has no arguments in C++) is transformed to `Number_T_Int.Value (A)` with `A` being the class object.\n\nTo try the example in this repository run:\n\n```\n$ cd example\n$ ../cappulada -p Example number.h\n$ make\n$ ./add 1 1\n```\n\n","funding_links":[],"categories":["Applications"],"sub_categories":["Generators and Translators"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FComponolit%2FCappulada","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FComponolit%2FCappulada","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FComponolit%2FCappulada/lists"}