godotengine / godot-cpp-template

Quickstart template for GDExtension development with Godot
https://docs.godotengine.org/en/stable/tutorials/scripting/gdextension/what_is_gdextension.html
The Unlicense
145 stars 55 forks source link
gdextension godot godot-engine

godot-cpp template

This repository serves as a quickstart template for GDExtension development with Godot 4.0+.

Contents

Usage - Template

To use this template, log in to GitHub and click the green "Use this template" button at the top of the repository page. This will let you create a copy of this repository with a clean git history. Make sure you clone the correct branch as these are configured for development of their respective Godot development branches and differ from each other. Refer to the docs to see what changed between the versions.

For getting started after cloning your own copy to your local machine, you should:

Usage - Actions

The actions builds godot-cpp at a specified location, and then builds the gdextension at a configurable location. It builds for desktop, mobile and web and allows for configuration on what platforms you need. It also supports configuration for debug and release builds, and for double builds.

The action uses SConstruct for both godot-cpp and the GDExtension that is built.

To reuse the build actions, in a github actions yml file, do the following:

name: Build GDExtension
on:
  workflow_call:
  push:

jobs:
  build:
    strategy:
      fail-fast: false
      matrix:
        include:
          - platform: linux
            arch: x86_64
            os: ubuntu-20.04
          - platform: windows
            arch: x86_32
            os: windows-latest
          - platform: windows
            arch: x86_64
            os: windows-latest
          - platform: macos
            arch: universal
            os: macos-latest
          - platform: android
            arch: arm64
            os: ubuntu-20.04
          - platform: android
            arch: arm32
            os: ubuntu-20.04
          - platform: android
            arch: x86_64
            os: ubuntu-20.04
          - platform: android
            arch: x86_32
            os: ubuntu-20.04
          - platform: ios
            arch: arm64
            os: macos-latest
          - platform: web
            arch: wasm32
            os: ubuntu-20.04

    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          submodules: true
      - name: ๐Ÿ”— GDExtension Build
        uses: godotengine/godot-cpp-template/.github/actions/build@main
        with:
          platform: ${{ matrix.platform }}
          arch: ${{ matrix.arch }}
          float-precision: single
          build-target-type: template_release
      - name: ๐Ÿ”— GDExtension Build
        uses: ./.github/actions/build
        with:
          platform: ${{ matrix.platform }}
          arch: ${{ matrix.arch }}
          float-precision: ${{ matrix.float-precision }}
          build-target-type: template_debug
      - name: Mac Sign
        if: ${{ matrix.platform == 'macos' && env.APPLE_CERT_BASE64 }}
        env:
          APPLE_CERT_BASE64: ${{ secrets.APPLE_CERT_BASE64 }}
        uses: godotengine/godot-cpp-template/.github/actions/sign@main
        with:
          FRAMEWORK_PATH: bin/macos/macos.framework
          APPLE_CERT_BASE64: ${{ secrets.APPLE_CERT_BASE64 }}
          APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }}
          APPLE_DEV_PASSWORD: ${{ secrets.APPLE_DEV_PASSWORD }}
          APPLE_DEV_ID: ${{ secrets.APPLE_DEV_ID }}
          APPLE_DEV_TEAM_ID: ${{ secrets.APPLE_DEV_TEAM_ID }}
          APPLE_DEV_APP_ID: ${{ secrets.APPLE_DEV_APP_ID }}
      - name: Upload Artifact
        uses: actions/upload-artifact@v4
        with:
          name: GDExtension-${{ matrix.platform }}-${{ matrix.arch }}
          path: |
            ${{ github.workspace }}/bin/**
  merge:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Merge Artifacts
        uses: actions/upload-artifact/merge@v4
        with:
          name: GDExtension-all
          pattern: GDExtension-*
          delete-merged: true

The above example is a lengthy one, so we will go through it action by action to see what is going on.

In the Checkout step, we checkout the code. In the ๐Ÿ”— GDExtension Build step, we are using the reusable action:

uses: godotengine/godot-cpp-template/.github/actions/build@main
with:
  platform: ${{ matrix.platform }}
  arch: ${{ matrix.arch }}
  float-precision: single
  build-target-type: template_release

with the parameters from the matrix.

As a result of this step, the binaries will be built in the bin folder (as specified in the SConstruct file). After all builds are completed, all individual builds will be merged into one common GDExtension-all zip that you can download.

Note: for macos, you will have to build the binary as a .dylib in a EXTENSION-NAME.framework folder. The framework folder should also have a Resources folder with a file called Info.plist. Without this file, signing will fail.

Note: for iOS, the same should be as for MacOS, however the Info.plist file needs to be close to the .dylib, instead of in a Resources folder (If this is not done, the build will fail to upload to the App Store).

So, in our case, the builds should be:

bin/EXTENSION-NAME.macos.template_debug.framework/EXTENSION-NAME.macos.template_release
bin/EXTENSION-NAME.ios.template_debug.framework/EXTENSION-NAME.ios.template_release.arm64.dylib

Afterwards, you want to set in the `.gdextension` file the paths to the `.framework` folder, instead of the `.dylib` file (Note that for the `.dylib` binary, the extension is not needed, you could have a file without any extension and it would still work).

In the `name: Mac Sign` step, we are signing the generated mac binaries.
We are reusing the following action:
```yml
uses: godotengine/godot-cpp-template/.github/actions/sign@main
with:
  FRAMEWORK_PATH: bin/macos/macos.framework
  APPLE_CERT_BASE64: ${{ secrets.APPLE_CERT_BASE64 }}
  APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }}
  APPLE_DEV_PASSWORD: ${{ secrets.APPLE_DEV_PASSWORD }}
  APPLE_DEV_ID: ${{ secrets.APPLE_DEV_ID }}
  APPLE_DEV_TEAM_ID: ${{ secrets.APPLE_DEV_TEAM_ID }}
  APPLE_DEV_APP_ID: ${{ secrets.APPLE_DEV_APP_ID }}

As you can see, this action requires some secrets to be configured in order to run. Also, you need to tell it the path to the .framework folder, where you have both the binary (.dylib file) and the Resources folder with the Info.plist file.

Configuration - Mac Signing Secrets

In order to sign the Mac binary, you need to configure the following secrets: APPLE_CERT_BASE64, APPLE_CERT_PASSWORD, APPLE_DEV_PASSWORD, APPLE_DEV_ID, APPLE_DEV_TEAM_ID, APPLE_DEV_APP_ID. These secrets are stored in the example above in the Github secrets for repositories. The names of the secrets have to match the names of the secrets you use for your action. For more on this, read the Creating secrets for a repository article from Github.

These secrets are then passed down to the godotengine/godot-cpp-template/.github/actions/sign@main action that signs the binary.

In order to configure these secrets, you will need:

For the actions you will need to set the following inputs. Store them as secrets in GitHub:

You will find here a guide on how to create all of them. Go to developer.apple.com:

APPLE_DEV_ID - Apple ID

APPLE_DEV_TEAM_ID - Apple Team ID

APPLE_DEV_PASSWORD - Apple App-Specific Password

APPLE_CERT_BASE64 and APPLE_CERT_PASSWORD and APPLE_DEV_APP_ID

Eg.

After these secrets are obtained, all that remains is to set them in Github secrets and then use them in the Github action, eg. in the above Github action usage example, this part:

- name: Mac Sign
  if: ${{ matrix.platform == 'macos' && env.APPLE_CERT_BASE64 }}
  env:
    APPLE_CERT_BASE64: ${{ secrets.APPLE_CERT_BASE64 }}
  uses: godotengine/godot-cpp-template/.github/actions/sign@main
  with:
    FRAMEWORK_PATH: bin/macos/macos.framework
    APPLE_CERT_BASE64: ${{ secrets.APPLE_CERT_BASE64 }}
    APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }}
    APPLE_DEV_PASSWORD: ${{ secrets.APPLE_DEV_PASSWORD }}
    APPLE_DEV_ID: ${{ secrets.APPLE_DEV_ID }}
    APPLE_DEV_TEAM_ID: ${{ secrets.APPLE_DEV_TEAM_ID }}