Coding Rules

The coding principals for Batocera are as follows:

  • Keep it simple
  • Worse is better

In other words, don't try to handle all cases if it makes the software complicated and unmaintainable.

The batocera.linux git is based on a Buildroot tree. Ideally, a file is either owned by Batocera or by Buildroot. Buildroot files must not be modified. The following directories are owned by Batocera:

Located at https://github.com/batocera-linux/batocera.linux/tree/master/configs, these are the defconfig files required to build Batocera for a particular platform. These files must be kept as small as possible. Other necessary alterations can be handled by packages from https://github.com/batocera-linux/batocera.linux/blob/master/package/batocera/core/batocera-system/Config.in.

The only information that you should find in this file are the physical architecture and the packages it requires (when it is technically not possible to put them in the Config.in with KConfig).

Located at https://github.com/batocera-linux/batocera.linux/tree/master/board/batocera, this is the place where you can find files specific to each board. This directory must be kept as small as possible; ideally most files should be handled by packages.

Every platform has several key directories:

  • fsoverlay Files that will be globally copied over to the final Batocera image. This directory is ideally empty. Avoid adding files here, instead, add them in a package. The same folder exists for each board: <architecture>/fsoverlay.
  • patches Package patches. The same folder exists specific to each board: <architecture>/patches.
  • <architecture>/boot Files specific to the boot.
  • <architecture>/linux_patches Linux patches specific to the board.

Located at https://github.com/batocera-linux/batocera.linux/tree/master/package/batocera, these are the packages executable after Batocera has booted. Essentially, the “main part” of Batocera. Try to organize most auxiliary packages required for booting up successfully here.

Packages should be independent (executable outside of Config.in dependencies, accessible to any platform) and contained entirely within their own sub-folder. The idea is to keep these modular, so no one package is dependent on the other.

When you've become more familiar with the basics, you can refer to the notable files/folders page as a cheatsheet!

Windows Vista and above support symlinks, but this is not built-in by default. Here's an unofficial extension to explorer.exe that adds such functionality: https://schinagl.priv.at/nt/hardlinkshellext/linkshellextension.html

  1. Install (its initial configuration script in its package at https://github.com/batocera-linux/batocera.linux/blob/master/package/batocera/emulators/<new emulator>/Config.in is called by https://github.com/batocera-linux/batocera.linux/blob/master/Config.in) and compile (make file for the new emulator at https://github.com/batocera-linux/batocera.linux/blob/master/package/batocera/emulators/<new emulator>/<new emulator>.mk and its build configuration at https://github.com/batocera-linux/batocera.linux/blob/master/package/batocera/emulators/<new emulator>/Config.in) your emulator with Batocera. Ensure that there are no valid build errors with it.
  2. Add your system/emulator to the EmulationStation system configuration at https://github.com/batocera-linux/batocera.linux/blob/master/package/batocera/emulationstation/batocera-es-system/es_systems.yml (if you're adding an emulator to an already existing system and don't need it to be the default, you can leave this alone).
  3. Add your system/emulator to the features list (https://github.com/batocera-linux/batocera.linux/blob/master/package/batocera/emulationstation/batocera-es-system/es_features.yml) and any advanced system settings if necessary.
    1. Define the generator (syntax: from generators.<shortname>.<shortname>Generator import <CamelCased shortname>Generator, shortname is the system name) with its system shortname here: https://github.com/batocera-linux/batocera.linux/blob/master/package/batocera/core/batocera-configgen/configgen/configgen/emulatorlauncher.py (you can test this locally with /usr/lib/python3.9/site-packages/configgen/emulatorlauncher.py).
    2. Include it in the packages list (syntax: configgen.generators.<shortname>) here: https://github.com/batocera-linux/batocera.linux/blob/master/package/batocera/core/batocera-configgen/configgen/setup.py.
    3. Create the “main” configuration generator Python script here: https://github.com/batocera-linux/batocera.linux/blob/master/package/batocera/core/batocera-configgen/configgen/configgen/generators/ followed by <shortname>/<shortname>Generator.py.
    4. If appropriate, split the file into multiple Python scripts called by <shortname>Generator.py in the generators/<shortname>/ folder.
  4. Configure the default settings for particular architectures (such as if your emulator requires certain settings to function on a particular architecture) at https://github.com/batocera-linux/batocera.linux/blob/master/package/batocera/core/batocera-configgen/configs/.
  5. Limit your emulator to particular platforms (most typically, most complex standalone emulators are x86/x86_64 only) with https://github.com/batocera-linux/batocera.linux/blob/master/package/batocera/core/batocera-system/Config.in.

If you'd like an example of a recent pull request that adds a whole new emulator: https://github.com/batocera-linux/batocera.linux/pull/4742/files

Define advanced system options (outside of the usual video mode, aspect ratio, etc. available to all systems) in the es_features.yml file (available on the Github here). This is a human-readable file containing all the advanced settings.

Syntax (replace everything including less-than and greater-than symbols (<>)):

<emulator shortname>:
  features: [<common feature 1>, <common feature 2>, <...>]
  cfeatures:
          <batocera.conf key name 1>:
            archs_include: [<archs to limit this option to, if applicable>]
            prompt:      <ALL CAPS OPTION NAME>
            description: <Explanation of the sentence that doesn't exceed 1000px across.>
            choices:
                "<Option 1 name>":    <batocera.conf value 1>
                "<Option 2 name>":    <batocera.conf value 2>
                "<...>":              <...>
           <batocera.conf key name 2>:
             <...>
  systems:
    <system shortname>:
          <options that only apply to a specific system>:
            <...>
<emulator 2 shortname>:
  <...>

Here's an example:

dolphin:
  features: [ratio]
  cfeatures:
        gfxbackend:
            archs_include: [x86, x86_64, rpi4, odroidgoa, gameforce]
            prompt:      GRAPHICS BACKEND
            description: Choose your graphics rendering
            choices:
                "OpenGL": OGL
                "Vulkan": Vulkan
        perf_hacks:
            prompt:      PERFORMANCE HACKS
            description: Increase emulator performance, at the cost of accuracy/stability
            choices:
                "Off": 0
                "On":  1
  systems:
    wii:
        cfeatures:
            emulatedwiimotes:
                prompt:      EMULATE WIIMOTE
                description: Use your gamepad like a vertical Wiimote in game
                choices:
                    "Off":                       0
                    "On":                        1

Spacing is everything here. Triple-check that you have used the correct amount of indentation. If your build fails to compile because of errors related to es_features.yml after you have made modifications to it then this is likely the culprit.

General practice isn't to be a one-for-one representation of the settings available to the emulator, that would defy the point of Batocera. Important settings that may need to be changed frequently/per game should be represented as is, but generally the more advanced settings should be simplified (with the help of the config generator setting all the correct values) and clearly explained in the advanced system settings. For example, the above PERFORMANCE HACKS setting actually changes a bunch of settings within Dolphin all at once:

        # Various performance hacks - Default Off
        if system.isOptSet('perf_hacks') and system.getOptBoolean('perf_hacks'):
            dolphinGFXSettings.set("Hacks", "BBoxEnable", '"False"')
            dolphinGFXSettings.set("Hacks", "DeferEFBCopies", '"True"')
            dolphinGFXSettings.set("Hacks", "EFBEmulateFormatChanges", '"False"')
            dolphinGFXSettings.set("Hacks", "EFBScaledCopy", '"True"')
            dolphinGFXSettings.set("Hacks", "EFBToTextureEnable", '"True"')
            dolphinGFXSettings.set("Hacks", "SkipDuplicateXFBs", '"True"')
            dolphinGFXSettings.set("Hacks", "XFBToTextureEnable", '"True"')
            dolphinGFXSettings.set("Enhancements", "ForceFiltering", '"True"')
            dolphinGFXSettings.set("Enhancements", "ArbitraryMipmapDetection", '"True"')
            dolphinGFXSettings.set("Enhancements", "DisableCopyFilter", '"True"')
            dolphinGFXSettings.set("Enhancements", "ForceTrueColor", '"True"')            
        else:
            if dolphinGFXSettings.has_section("Hacks"):
                dolphinGFXSettings.remove_option("Hacks", "BBoxEnable")
                dolphinGFXSettings.remove_option("Hacks", "DeferEFBCopies")
                dolphinGFXSettings.remove_option("Hacks", "EFBEmulateFormatChanges")
                dolphinGFXSettings.remove_option("Hacks", "EFBScaledCopy")
                dolphinGFXSettings.remove_option("Hacks", "EFBToTextureEnable")
                dolphinGFXSettings.remove_option("Hacks", "SkipDuplicateXFBs")
                dolphinGFXSettings.remove_option("Hacks", "XFBToTextureEnable")
            if dolphinGFXSettings.has_section("Enhancements"):
                dolphinGFXSettings.remove_option("Enhancements", "ForceFiltering")
                dolphinGFXSettings.remove_option("Enhancements", "ArbitraryMipmapDetection")
                dolphinGFXSettings.remove_option("Enhancements", "DisableCopyFilter")
                dolphinGFXSettings.remove_option("Enhancements", "ForceTrueColor")  

For each emulator, a config generator plugin must be written to update the emulator's config files before the emulator launches. There are two kinds of configuration: The one handled by Batocera and static, user-editable files. To let the user modify static configuration files:

  • Don't base the configuration on templates (a.k.a. “magic” values, hard-coded values, etc.)
  • Only update values controlled by Batocera

Configuration handled by Batocera comes from three places:

  • the configgen plugin. hardcoded or dependant on non user values (the number of plugged pads for example)
  • configgen-defaults.yml the default configuration
  • configgen-defaults-arch.yml the configuration that overrides configgen-defaults.yml defaults for a given architecture
  • batocera.conf The settings file saved to by EmulationStation or manually edited by the user. Contains keys such as global.<setting>=<value> or <system>.<emulator>.<setting>=<value>

Note: ideally, batocera.conf must be installed empty and keep only user-changed settings. Default system configurations must be only in YML files. EmulationStation is capable of editing the batocera.conf file.

Buildroot utilizes a great feature: patching programs.

Patches are separate files that will modify a program at compilation time. There are three locations where you can put patches:

  • In the package/batocera/<package_name> directory. This is the preferred place for Batocera packages when the patch is required for all architectures. It is very visible for the package maintainer.
  • In the board/batocera/patches/<package_name> directory. This is the preferred place when patching a Buildroot package that affects all architectures.
  • In the board/batocera/<architecture>/patches/<package_name> directory. This is the preferred place when patch a package having an issue with a specific board. If the patch is not related to the board or has no impact for other boards (like adding a choice entry in a Makefile for a board), the preferred place is not this one. It is preferred to reduce the number of entries in this place to reduce the differences between boards.

Avoid modifying Buildroot's files. This makes upgrading Buildroot more difficult. The following script: https://github.com/batocera-linux/batocera.linux/blob/master/scripts/linux/buildrootdiff.sh may help you to find altered Buildroot files. The number of files found using this must be reduced to the minimum amount required.

In case a modification to a Buildroot file is absolutely necessary, prefix each paragraph by '# batocera' to help during the merges.

  • coding_rules.txt
  • Last modified: 5 hours ago
  • by atari