LibreElec Kodi + Lakka RetroArch

  • I have been a fan of both distros, LibreElec and Lakka, it's time to have the best of both worlds in one place, I want to have my cake and eat it too.
    Teorically, this should work for all architectures, I focused on my rpi4 aarch64.
    It totally can be an addon with a helper, I spent a whole day making it work this way described below, right now, I just want to enjoy it. =D

    UPDATE: I realized that all tools needed were present ar LibreElec image so I wrote the script below to get it working easily.

    NOTE: Keep a keyboard at hand to configure joystick first time you run it.

    NOTE: Share a download directory with zachmorrris IAGL addon to get games.


    Option 1: Automagic Script for a Running LibreElec

    NOTE: Published at: https://github.com/basilean/retroarch_install

    One line install:

    wget -q -O - https://raw.githubusercontent.com/basilean/retroarch_install/refs/heads/main/retroarch_install.sh | bash


    Option 2: Manual Procedure Using a GNU/Linux PC

    DISCLAIMER: Take a time to read and understand each step, most of the commands used needs to run as root, that means you can criple your PC if done wrong.

    1. Download LibreElec image and install it on an SD as usual.
    NOTE: Change the image version to your like.
    wget https://releases.libreelec.tv/LibreELEC-RPi4.aarch64-12.0.2.img.gz
    gunzip LibreELEC-RPi4.aarch64-12.0.2.img.gz

    WARNING: Make sure "/dev/mmcblk0" is the SD target. Change it yo suit you.
    dd if=LibreELEC-RPi4.aarch64-12.0.2.img of=/dev/mmcblk0 bs=4M

    WARNING: Be sure IO transfer is done, await for "sync" command to return.
    sync

    2. Boot new sd card in the target device. Once Kodi is up, just power it off, remove the card and insert it back in the PC.
    NOTE: This is needed to get "storage" resized in the first boot.

    3. Download Lakka image and mount it
    NOTE: Change the image version to your like, just match architecture with LibeElec and try to be close on release dates.
    https://nightly.builds.lakka.tv/6.x/2025-02-07/RPi4.aarch64/Lakka-RPi4.aarch64-6.x-20250207-0af7dae.img.gz
    gunzip Lakka-RPi4.aarch64-6.x-20250207-0af7dae.img.gz

    Create mount points.
    mkdir /media/flash
    mkdir /media/root

    WARNING: Make sure /dev/loop0 and /dev/loop1 are the targets or change them. Command "losetup" will return assigned loop for each file.
    Mount "Lakka" source (flash),
    losetup --show -P -f Lakka-RPi4.aarch64-6.x-20250207-0af7dae.img
    mount /dev/loop0p1 /media/flash

    From there, mount "SYSTEM" source (rootfs)
    losetup --show -f /media/flash/SYSTEM
    mount /dev/loop1 /media/root

    4. Copy retroarch Lakka components into kodi LibreElec "/storage" filesystem.
    Create a mount point.
    mkdir /media/storage

    WARNING: Make sure "/dev/mmcblk0p2" is the SD target partition. Change it to suit you.
    Mount SD card "storage" partition target.
    mount /dev/mmcblk0p2 /media/storage

    Copy binary (72M).
    cp -a /media/root/usr/bin/retroarch /media/storage/retroarch

    Copy assets (806M).
    cp -a /media/root/usr/share/retroarch /media/storage/.config/retroarch

    Copy cores (4.9G).
    cp -a /media/root/usr/lib/libretro /media/storage/.config/retroarch/cores

    LibRetro Database (684M).
    cp -a /media/root/usr/share/libretro-database /media/storage/.config/retroarch/database

    Filters (3M)
    mkdir /media/storage/.config/retroarch/filters
    cp -a /media/root/usr/share/video_filters /media/storage/.config/retroarch/filters/video
    cp -a /media/root/usr/share/audio_filters /media/storage/.config/retroarch/filters/audio

    WARNING: Be sure IO transfer is done, await for "sync" command to return.
    sync

    5. Create a retroarch systemd unit.
    NOTE: kodi.conf has HOME definition used by retroarch.

    vi /media/storage/.config/system.d/retroarch.service

    Reload systemd and disable retroarch service. It only is going to run when swaps with kodi.
    systemctl daemon-reload
    systemctl disable retroarch

    6. Create a wrapper script.

    vi /media/storage/retroarch.py

    Python: retroarch.py
    from xbmc import executebuiltin
    from subprocess import run
    
    executebuiltin('Notification(Retroarch, Loading..., 5000, /storage/.config/retroarch/assets/xmb/monochrome/png/retroarch.png)')
    run(["/usr/bin/systemctl", "start", "retroarch"])

    7. Create a shortcut in favourites

    vi /media/storage/.kodi/userdata/favourites.xml

    Code
    <favourites>
       <favourite name="RetroArch" thumb="/storage/.config/retroarch/assets/xmb/monochrome/png/retroarch.png">RunScript(/storage/retroarch.py)</favourite>
    </favourites>


    8. Clear all mounted filesystems and used devices.
    umount /media/storage
    umount /media/root/
    losetup -d /dev/loop1
    umount /media/flash/
    losetup -d /dev/loop0

    Edited 7 times, last by basilean: Added filters on step 4. Added script. Moved script to GitHub so it can be a one line execution. Fixed step 5. Thanks Marxon. (February 15, 2025 at 10:42 AM).

  • Hi basilean,

    nice to see someone working on more emulation features for libreelec. :thumbup:
    I tried your script, first it did not complete because lack of free space. Requirements should be extended.
    The next run of the install script finished sucsessfull.
    Unfortunately if i try to start retroarch via systemctl start retroarch it just quits kodi and starts again.
    Did i miss something or what's going wrong?


    Best regards
    Marxon

  • Update
    I found the problem:
    Somehow the retroarch.service file was not generated correctly.

    Line 10 was split into
    ExecStart=/storage/retroarch
    /retroarch

    But it should be one single line
    ExecStart=/storage/retroarch/retroarch

    Step 5 of the manual procedure guide contains a similar error.
    It points just to the /storage/retroarch directory.

    Edited once, last by Marxon (February 15, 2025 at 8:47 AM).

  • Hello Marxon,

    Thank you very much for your feedback. I just fixed step 5 on procedure but I didn't find the same issue on the script. What is killing me is that it should have checked that you had 9G of free space, not sure why it failed..

    Besides that, let me tell you there is some extra work in progress for some cores (ie: scummvm) that needs shared libraries not present in LibreElec, I already found a way to make it work, just need to put all together.

    Cores Shared Libraries Dependencies · Issue #1 · basilean/retroarch_install
    I found out that few cores needs extra libraries. I need to track them down and include them in the copy. dolphin_libretro.so libzstd.so.1 => not found…
    github.com

    Andres.-

  • I already tried using a separate script containing only the part which creates the retroarch.service file:

    But i get the same wrong result:
    ExecStart=/storage/retroarch
    /retroarch
    Strange...:-/

    What is killing me is that it should have checked that you had 9G of free space, not sure why it failed..

    I needed about 9.3Gb otherwise i got errors while copying the database files.

  • I got it now, I will update script to 10G, thank you. One question regarding this, are you using rpi4 or another hardware?

    I just tried copying and pasting your script above and it worked fine for me, weird indeed.

  • Brilliant way to get RetroArch working under Libreelec! I can launch RetroArch by clicking on the Kodi favorite that launches the Python wrapper that launches the RetroArch service... and RetroArch works! It feels like a breakthrough. So here's my question: Using your approach, is there a way to pass a core name and game name to Retroarch (to launch a specific game)? I'm asking because, ultimately, I want to take this one step further and launch Retroarch directly from IAGL (i.e. use Retroarch as an external launcher). I'm using LibreElec 12.0.2/Kodi 21.2 Omega, on a Pi 4.

  • Hello there!.. Yeah, I would think so, the difference with others approaches is the use of systemd service, you could use environment variables to feed retroarch exec arguments. I preferred way I did because I could use all available emulators without need to create a new addon for missing ones.

  • Running the latest IAGL (4.03) on the latest LibreElec (21.2) on a Raspberry Pi 4. I can *almost* use RetroArch as an external launcher in a game list. Here's what I've done so far:

    OUTSIDE OF IAGL: Installed Retroarch on LibreElec 21.2 following your instructions and confirmed I can launch Retroarch (as a system.d service) from LibreElec. I can even launch Retroarch with hard-coded arguments (i.e. I can specify a core name and rom name in a conf file that the service will use). My system.d service "retroarch.service" looks like this:

    [Unit]
    Description=Retroarch
    After=network-online.target graphical.target
    Requires=graphical.target
    Wants=network-online.target

    [Service]
    EnvironmentFile=/storage/retroarch/retro.conf
    ExecStartPre=systemctl stop kodi
    ExecStart=/storage/retroarch/retroarch ${ARG1} ${ARG2} ${ARG3}
    ExecStopPost=systemctl start kodi
    TimeoutStopSec=10
    Restart=no
    StartLimitInterval=0
    LimitNOFILE=16384

    [Install]
    WantedBy=kodi.target

    The arguments above (ARG1, ARG2, and ARG3) are populated from "retro.conf" which looks like this:

    KODI_AUDIO_ARGS=--audio-backend=alsa+pulseaudio
    HOME=/storage
    KODI_TEMP=/storage/.kodi/temp
    KODI_HOME=/usr/share/kodi/
    ARG1=-L
    ARG2=/storage/retroarch/cores/cap32_libretro.so
    ARG3=/storage/.kodi/userdata/addon_data/plugin.program.iagl/game_cache/Amstrad CPC/2 Player Soccer Squad (1986)(Cult Games).dsk

    In the above conf file, I specified the Caprice core in ARG2 and a soccer game in ARG3.

    INSIDE OF IAGL: If I go into a list and manually specify an external launch command (systemctl start retroarch), then launch a game, retroarch starts and runs the core/game that are hard-coded in ARG2 and ARG3 (Caprice and the soccer game).

    That's where I'm stuck. Instead of hard-coded ARG1 and ARG2, I can't figure out how to pass the core name and rom name from IAGL to the retroarch "service". Any ideas?

  • Try something like this, it worked for me.


    Create a wrapper script to handle environment variables for service.

    vi  /storage/retroex.sh 

    Bash
    echo "SYSTEM=${1}" > /tmp/iagl.conf # Manual for list.
    echo "ROM=${2}" >> /tmp/iagl.conf # XXROM_PATHXX
    
    systemctl start retroarch

    Make it executable.

    chmod 755 /storage/retroex.sh


    Change service

    vi /storage/.config/system.d/retroarch.service

    Code
    # Comment old exec line.
    # ExecStart=/storage/retroarch/retroarch
    
    # Add script output file with vars.
    EnvironmentFile=/tmp/iagl.conf
    
    # Customize retroarch init flags to your like!
    ExecStart=/storage/retroarch/retroarch -L ${SYSTEM} ${ROM}

    Remember to reload systemd

    systemctl daemon-reload


    When set external command for a list at IAGL, follow this pattern:

    /storage/retroex.sh SYSTEM "ROM"

    SYSTEM -> Whatever goes with -L indicating core to use, set it manually for that list.

    ROM -> It is replaced by iagl with rom path of your choice. Note that is important to use quotes to avoid issues with white spaces.

    /storage/retroex.sh fbneo "XXROM_PATHXX"

    Edited 2 times, last by basilean: Added some details to make it easy for copy and paste. (February 26, 2025 at 11:41 AM).

  • That works, thanks! Now I can select and launch a game in an IAGL list using RetroArch instead of Retroplayer! Of course, at the moment, when I exit RetroArch it dumps me into Kodi's main menu instead of taking me back to the IAGL list. So, not totally seamless. I wonder if I can fix that via IAGL Settings->Kodi launch options...

    :)

  • basilean Thanks for sharing your script!

    I've been running it on Libreelec 12.0.2 (generic x86_64). When trying to start retroarch I get the following error message:

    Code
    Mar 03 22:16:48 libreelec retroarch[1150]: /storage/retroarch/retroarch: error while loading shared libraries: libGL.so.1: cannot open shared object file: No such file or directory
    Mar 03 22:16:48 libreelec systemd[1]: retroarch.service: Main process exited, code=exited, status=127/n/a

    Do you have any hints for me?

    Did I get it right, that I need LE generic-legacy (with opengl)?


    Edit:

    BTW, I'm running an i5-4570T with iGPU HD Graphics 4600.

    Edited once, last by schmecks (March 3, 2025 at 10:16 PM).

  • Hello schmecks, give it a try copying needed libraries from Lakka image.

    Check what library is needed:

    ldd /storage/retroarch/retroarch | grep "not found"

    Get Lakka image and mount it as step 3 on manual procedure.

    Create a place to put them:

    mkdir /storage/retroarch/lib

    Copy them.

    Add extra library path in systemd service.

    vi .config/system.d/retroarch.service

    Environment="LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/storage/retroarch/lib"

    systemctl daemon-reload


    Here I found a similar issue for some cores and fix them by this way.

    Cores Shared Libraries Dependencies · Issue #1 · basilean/retroarch_install
    I found out that few cores needs extra libraries. I need to track them down and include them in the copy. dolphin_libretro.so libzstd.so.1 => not found…
    github.com
  • Ah, I accidentally copied /media/root/lib (which is linked to /usr/lib) and not /media/root/usr/lib...

    So, I copied all libraries from Lakka to /storage/retroarch/lib, now it can find the libs. First I got the error message:

    I then deleted /storage/retroarch/lib/libc.so.6 (so it now uses /usr/lib/libc.so.6 from Libreelec).

    Now, journalctl says:

    Do you have any other hints?

    BTW, ldd still complains about missing libGL.

    Code
    libreelec:~ # ldd /storage/retroarch/retroarch | grep "not found"
    	libGL.so.1 => not found