Ada on a Raspberry Pi 4B - seem to be missing libaraies

I’m a retired programmer. I’ve used many languages throughout my career, but most of the time I was a C/C++ coder. I am creating an interactive tool using Google Gemini’s A.I. By this I mean going beyond a simple Alexa/Siri question/answer system to actually keeping an open dialogue going with Gemini. I have a client system working great written in Pure Ada and taking advantage of the real-time kernel I’m using on Linux CNC. The server part - I call a relay -is written in Python because I cannot get a pure Ada server written on the Pi because certain libraries are missing or don’t work. These libraries are: GNAT Components Collection (GNATcoll) and GNATCOLL.HTTP.Clients. I even tried AWS, but that was a disaster. I’ll give the python code that works really well. If anyone can point me in the right direction - it would be greatly appreciated.

``
#!/home/frank/mirror_brain/venv/bin/python3
import asyncio
import websockets
import json
import base64
import os
from pathlib import Path

— Configuration —

MODEL = “models/gemini-2.5-flash-native-audio-latest”
API_KEY = “My Key”
URI = f"wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContent?key={API_KEY}"

Path to the Magic Mirror trigger

TRIGGER_FILE = Path(“/home/frank/MagicMirror/modules/trigger.json”)

def update_trigger(status):
“”“Explicitly writes JSON status to the trigger file.”“”
try:
with open(TRIGGER_FILE, ‘w’) as f:
json.dump({“status”: status}, f)
except Exception as e:
print(f"[ERROR] Failed to write trigger: {e}")

async def bridge():

SET DEFAULT STATE: Webcam on, Professor hidden

update_trigger(“idle”)

print(f"Connecting to Gemini ({MODEL})...")
try:
    async with websockets.connect(
        URI,
        ping_interval=None,
        ping_timeout=None
    ) as google_ws:

        # --- Step 1: Load Context ---
        context_path = '/home/frank/mirror_brain/professor_context.json'
        try:
            with open(context_path, 'r') as f:
                memories = json.load(f)
                instr_text = (
                   "You are the Professor. Speak with a deep, resonant baritone voice. "
                   "While your voice is low-pitched, your speech must be articulate, "
                   "crisp, and intellectually alert. Avoid a slow drawl or dragging "
                   "your words; maintain a steady, professorial pace that reflects "
                   "clear thinking and authority."
                   "Speak with the cadence of a lively lecture"
                )
            print(f"[RELAY] Academic Context loaded.")
        except Exception as e:
            instr_text = "You are 'The Professor', a distinguished Oxford academic."

        # --- Step 2: Gemini Handshake ---
        setup_msg = {
            "setup": {
                "model": MODEL,
                "generationConfig": {
                    "responseModalities": ["AUDIO"],
                    "speechConfig": {
                        "voiceConfig": { "prebuiltVoiceConfig": { "voiceName": "Charon" } }
                    }
                },
                "systemInstruction": { "parts": [{"text": instr_text}] }
            }
        }

        await google_ws.send(json.dumps(setup_msg))
        await google_ws.recv()
        print("Gemini Handshake Complete. The Professor is in his study.")

        async def handle_ada(reader, writer):
            print("\n[RELAY] Ada Linked. Waiting for Professor to speak...")

            update_trigger("off");  #make sure the Professor is initially off.
            async def google_to_ada_loop():
                try:
                    async for message in google_ws:
                        msg = json.loads(message)
                        if "serverContent" in msg:
                            server_content = msg["serverContent"]
                            model_turn = server_content.get("modelTurn", {})


                            for part in model_turn.get("parts", []):
                                if "text" in part:
                                    print(f"\033[96m[PROFESSOR]: {part['text']}\033[0m")

                                if "inlineData" in part:
                                    # PROFESSOR IS TALKING: Show face, hide webcam
                                    update_trigger("talking")

                                    audio_bytes = base64.b64decode(part["inlineData"]["data"])
                                    writer.write(audio_bytes)
                                    await writer.drain()

                            # Check if the specific turn/response is finished
                            if server_content.get("turnComplete"):
                                # TURN COMPLETE: Hide face, show webcam
                                update_trigger("idle")
                                print("[RELAY] Turn Complete. Mouth closed.")

                except Exception as e:
                    if "BrokenPipeError" not in str(e):
                        print(f"Downlink Error: {e}")
                    update_trigger("idle")

            receiver_task = asyncio.create_task(google_to_ada_loop())

            try:
                while True:
                    try:
                        data = await asyncio.wait_for(reader.readexactly(1536), timeout=5.0)
                        if not data: break
                        payload = {
                            "realtimeInput": {
                                "mediaChunks": [{
                                    "data": base64.b64encode(data).decode('utf-8'),
                                    "mimeType": "audio/pcm;rate=16000"
                                }]
                            }
                        }
                        await google_ws.send(json.dumps(payload))
                    except asyncio.IncompleteReadError: break
                    except asyncio.TimeoutError: continue
            except Exception as e:
                print(f"Uplink Error: {e}")
            finally:
                print("[RELAY] The Professor has stepped out.")
                update_trigger("idle")

                receiver_task.cancel()
                writer.close()
                await writer.wait_closed()

        server = await asyncio.start_server(handle_ada, '127.0.0.1', 8081)
        async with server:
            await server.serve_forever()

except Exception as e:
    print(f"Global Error: {e}")
    update_trigger("idle")

if name == “main”:
async def main():
await bridge()

try:
    asyncio.run(main())
except KeyboardInterrupt:
    update_trigger("idle")

``

Frank

Hi,

IIRC, GNAT and its different components can be installed in the RPi (64-bit) ecosystem using the official ARM build of Alire Releases · alire-project/alire · GitHub. @Max, maintained an old index for aarch64, but I don’t think it is necessary anymore (GitHub - reznikmm/aarch64-alire-index: Alire port to aarch64 · GitHub). I hope this helps.

Best regards,
Fer

I’ll git it a try. I did try alire, but had many dependency issues. When I got them resolved, “alr” worked well for a while, but then I kept getting a persistent “Unexpected symbol: e” at character 1 error whenever I tried to run alr.

Frank

Could you give me the output of alr -vv?

I have never seen such an issue

I’m sorry I uninstalled it all. But, I was using “alr” fine for quite a while. I’m not sure what I did, but when “whatever” happened I got that error no matter what command I gave to “alr.” I even did a hexdump on the alire.toml to see if some hidden character was at the 1st position of the file, but the file was clean. I just assumed at that time that the “alr” executable became corrupted. So, I uninstalled everything.

No worries! But if you get another alire error, make sure to report it to Issues · alire-project/alire · GitHub

Funny you mentioned that because it just happened. Just FYI - I am using Google Gemini and so what you are about to see is what it is reporting of the steps we took to eventually get the error. I’ll post it here and on the issues page.

Here is the exact technical summary of the “loop” we encountered, formatted for a technical report:


Environment Details

  • Hardware: Raspberry Pi (aarch64)

  • OS: Raspberry Pi OS (64-bit)

  • Compiler: GNAT 14.2.0 (System installed)

  • Build Tool: Alire 2.1.0 / GPRbuild 2025.0.0

  • Target Library: AWS (Ada Web Server)

The Technical “Loop” Summary

1. The Core Compilation Failure

While attempting to build a project with aws as a dependency, the build fails consistently during the compilation of libgpr (a sub-dependency fetched by Alire).

  • Error: error: "Timeval" not declared in "Thin_Common"

  • Location: gpr-util-put_resource_usage__unix.adb

  • Observation: This appears to be a mismatch between the Alire-sourced libgpr code and the aarch64 Linux kernel headers regarding the time.h structures.

2. Failed Mitigation: Using System Utils

We attempted to force Alire to use the system-installed gprbuild and make to avoid compiling the broken infrastructure code.

  • Commands: alr settings --set --global system.utils.gprbuild true

  • Result: Alire continued to reach for its own internal version of libgpr regardless of the global setting.

3. Failed Mitigation: Marking Dependencies as External

We attempted to tell Alire that the low-level infrastructure (gpr, gnatcoll, xmlada) was already satisfied by the system.

  • Command Line: alr with gpr --external

  • Result: Error: Unrecognized option '--external'. (Note: This flag appears removed/changed in Alire 2.1.0).

4. Failed Mitigation: Manual Manifest Editing

We attempted to manually define the dependencies as external in the alire.toml.

  • Syntax Trials: We tried both the inline table format { version = "*", external = true } and the array of tables format [[depends-on]].

  • Parser Errors: Alire 2.1.0 returned contradictory errors:

    • “dependency version must be a string” (even when quoted).

    • “dependencies must be specified as array of tables”.

    • “Unexpected symbol: a (at char 1)” (even after confirming UTF-8 encoding without BOM).

5. Current Impasse

The system has a perfectly functional, patched version of libgnatcoll-dev (24.1) and gprbuild (2025) installed via apt, but Alire 2.1.0’s manifest parser and dependency solver provide no stable way to link against them while still using Alire to manage higher-level crates like aws.

I would suggest to delete gnat, gprbuild and other Ada stuff from system manager and let Alire install everything required.