Native Development for KOS

Some times there are tasks that are best suited for native programs, such as interacting with hardware. This document will cover the native development workflow. 

Firstly install an image with the developer tools flag check in your selected kos release. This will install developer specific tools onto the kos device, git, gcc, make, nano, and many other tools. 

The next configuration you’ll want to add is samba, this will allow you to have a shared drive with your KOS device. To enable samba, in your image configuration, navigate to developer flags, (hardware settings → developer flags). From there you can enable samba, and provide a hostname and password. Now you should install the image onto the target device. You install instead of run, because installing will let your image persist between reboots.

Now on the device you need to run samba-enable this can be done by ssh’ing into the device via ssh root@<device_ip>, after running samba-enable reboot your device and samba should now be accessible on the network. You can verify that samba is active by executing this command netstat -tulnp | grep smbd on the KOS device. 

To connect to samba on Mac you can open finder and press cmd+k to connect to a server where you can enter smb://hostname.local where hostname is the name you specified in your image configuration and you will now have a shared drive with your KOS device, allowing you to use your existing toolset to develop your programs.

To use libraries that KOS doesn’t have installed already you’ll have to build them and include them on device. The libraries will also have to be packaged with your program in a KAB so that it can be included in an image in KOS studio. 

Packaging native programs into a KAB

There are two ways to include your program in your image, you can create the KAB locally and include in your image as a local artifact. Or you can setup build automation and have it published and accessible via the published tab in KOS Studio.

Local artifact

To use your program in KOS you will need to package it as a kab. You can do so by using kabtool, a utility to build, and interact with kabs. To package a program and have it be executable place the compiled binary in a directory along with a file named .perm in the file you describe the unix file permissions the file should posses. Heres an example file 

755:1:1:MyProgram

The first 3 digits are the UNIX octal permissions. After the colon the number specifies owning user, after the next colon it specifies the owning group. The last part is the file pattern, which can be the exact name of the file or can use wild cards like *.sh for all shell files or **/*.sh for all shell files in this directory and in all subdirectories. You can specify the different permissions of different files in new lines of the .perm file 

You should have a directory structure like so 

program
├── .perm
└── MyProgram

Now you can build a kab using kabtool like so. 

kabtool -b -t org.native -n myProgram -dir Program program.kab

The first argument passed to kabtool defines the high level operation which in this case is -b to build a kab. The -targument specifies the kab type, which we recommend to be namespaces by your organization. The -n argument specifies the name of the kab. The -dir argument takes in the path to a directory, which contains the contents you want to be in the kab. The last argument is the final file name you want for the kab and must have the .kab specifier. Kabtool has even more features that you can explore with kabtool -h. 

Kabtool can also be integrated into your build system, to build the automatically. Here is an example Makefile 

CC ?= gcc
CFLAGS = -Wall
OUTDIR ?= program
TARGET = $(OUTDIR)/MyProgram
OBJS = MyProgram.o
KAB_VERSION ?= 0.0.0
$(TARGET): $(OBJS) | $(OUTDIR)
	$(CC) $(CFLAGS) -o $(TARGET) $(OBJS) -lkos
$(OUTDIR):
	mkdir -p $(OUTDIR)
%.o: %.c
	$(CC) -c -o $@ $< $(CFLAGS)
clean:
	rm -f *.o $(TARGET)
	rm -f *.kab
debug: CFLAGS += -g
debug: $(TARGET)
package: $(TARGET)
	kabtool -b -t myOrg.native -dir program -v "${KAB_VERSION}" my-program-${ARCH}.kab
.PHONY: package clean debug

This Makefile uses an output directory where you can include your .perm file to specify the file permissions.

Now you can include this kab as a local artifact in your image. You can mount this kab into the filesystem by using fuse mounter, and use Java’s ProcessBuilder to execute it. Below is an example of how to mount the program into the file system and how to get its path using FuseService.

    @Autowired
    private FuseService fuseService;
    @Override
    public void load() throws Exception {
        //load and mount the native program
            KabFile kab = getKabByType("myOrg.native");
            if (kab != null) {
                FuseMount mount = fuseService.mount(kab);
                log.info("Mounted kab file at {}", mount.getRootDir());
            } else {
                log.error("Kab file for adapter not found in system section");
            }

   }

Publishing KAB with GitHub Actions

Local artifacts are good for development but when you want to start sharing the kab with others it is best to publish the kab. This way you know exactly which version of the kab is being used, and there’s no question of which kab to use.

There are a few steps to setting up the automated publishing, and you will need admin access in your organization.

For this to work you need to ensure that the default_artifact_store is setup. Navigate to artifact store settings from the gear icon → select Artifact Store Settings. The resulting window should look something like this. If the default store is not present please reach out to the KOS team. Alternatively if you want to manage the artifacts yourself it can be done by following the guide in the readme, https://github.com/kosdev-code/kos-buildpublish/tree/main. 

  1. The first thing you need to do is have an artifact to publish against, this is where you set the name of the artifact.
    1. To create an artifact navigate to Artifact management and click on Add Artifact
    2. Add the name of your artifact and click create
  2. You need an API key from studio, this will be set as an environment variable in your GitHub repo.
    1. Gear icon-> Create API Keys → new window click create API key

b. In your repo set the repository secret STUDIO_APIKEY with the value of the api key obtained from KOS studio 

  1. In your repo you will need to add the .github directory and with that a workflows directory.
    1. In the work flows directory you can add this workflow file template. 
    2. This template uses arm64 as the architecture but can be set to x64 instead
name: Native ARM64 build environment
o
n:
  push:
    branches:
      - main
    paths:
      - "native/**"
  workflow_dispatch:
env:
  KOS_VERSION: 0.1.1
  ARCH: arm64
jobs:
  set-image-name:
    runs-on: ubuntu-latest
    outputs:
      image_to_use: ${{ steps.set_image.outputs.image_name }}
    steps:
      - id: set_image
        run: echo image_name=ghcr.io/kosdev-code/kos-buildpublish/kos_builder-native:${{env.ARCH}}_${{ env.KOS_VERSION }} >> $GITHUB_OUTPUT
  kos_native_build:
    runs-on: ubuntu-latest
    needs: set-image-name
    container:
      image: ${{ needs.set-image-name.outputs.image_to_use }}
      credentials:
        username: ${{ github.actor }}
        password: ${{ secrets.github_token }}
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4
        with:
          repository: ${{ github.repository }}
          token: ${{ secrets.GITHUB_TOKEN }}
          path: ${{ github.event.repository.name }}
          lfs: true
      - name: Build and Publish
        env:
          KOSBUILD_SECRET_URL: ${{ secrets.KOSBUILD_SECRET_URL }}
          KOSBUILD_SECRET_PASSWORD: ${{ secrets.KOSBUILD_SECRET_PASSWORD }}
        working-directory: ./${{ github.event.repository.name }}
        run: |
          kos_build_handler.sh automation .github/kosbuild-native-${{ env.ARCH }}.json
  1. Next a build.json file will be necessary, this gives information to the automation tooling as to how to build and publish the artifact. In the workflow template the file is named kosbuild-native-${{ env.ARCH }}.json so then in the .github directory create a file named kosbuild-native-arm64.json. Here’s an an example of the contents, comments cannot be present for 
{
  "default_keyset": "test.myOrg", // currently supports only test keysets
  "build_cmd": "./build_native.sh", // path to a script to build your program
  "artifacts": [
    {
      "id": "my-artifact", // name of the artifact created in Studio
      "filename": "native/myProgram-arm64.kab", // path to the output kab from the build script
      "artifactstore": "default_artifact_store", // needs to be default artifact store
      "qualifier": "arm64" // will only allow this artifact to be used on a hardware profile that arm64 based
    }
  ]
}

The default_keyset uses the test keyset for your organization, which is accessed using the studio API key. The value is not dependent on exact match with your org as long as its named test.something. 

This configuration expects that the build script is in the root of the repository. 

Now build automation is setup and your artifact should be publishing, and can be used by anyone on the team without have to build it locally. For more information refer to the readme located in this repo https://github.com/kosdev-code/kos-buildpublish/tree/main, this has more information on how the build automation system works and walks through how to manage your own artifact store using azure.