Custom core files compiling

Hi,

I am trying to create a custom platform/core (actually it is a fake core, since I want to target my PC).
So I have created the dir structure, and the required files.
Unfortunately it does not work. More precisely, I want to compile with the sketch all the
cpp files that I put into my core specific dir (cores/native) and into the variant dir
(variants/default), since they are the actual base implementation of my custom core.

I think they should be automatically considered by the compiling process, but it is not the case...
What am I missing? Must I specify them somewhere?

Thank you,
regards.

sounds like you want to simulate you Arduino code on your PC. this is a common practice because it is so much easier and faster to build/test on a laptop

i use the following with a bunch of sub arduino functions.

readInput() reads a command file that specifies changes to inputs and simulating the results from digitalRead()

#ifndef SIM_H
# define SIM_H

# include <stdio.h>
# include <stdint.h>
# include <unistd.h>
# include <stdlib.h>
# include <string.h>
# include <math.h>

# include "Arduino.h"

# define PROGMEM

#define TWO_PI  (3.14159265358979323846*2)

const char *Normal    = "\033[0m";
const char *Black     = "\033[30m";
const char *Red       = "\033[31m";
const char *Green     = "\033[32m";
const char *Yellow    = "\033[33m";
const char *Blue      = "\033[34m";
const char *Magenta   = "\033[35m";
const char *Cyan      = "\033[36m";
const char *White     = "\033[37m";

unsigned int debug = 0;
unsigned int dbg   = 0;

char s [100];

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
long
map (
    long    val,
    long    fromLow,
    long    fromHigh,
    long    toLow,
    long    toHigh )
{
    return toLow + (toHigh - toLow) * (val - fromLow) / (fromHigh - fromLow);
}

// -----------------------------------------------------------------------------
class SoftwareSerial {
  public:
    SoftwareSerial  (int txPin, int rxPin)  {};
    ~SoftwareSerial (void)  {};

    void begin (int bps) {};
};

// -----------------------------------------------------------------------------
class Servo {
  public:
    Servo (void)  {};
    ~Servo (void)  {};

    void attach (int pin) {printf ("    Servo: pin %d\n",   pin); };
    void write (int val)  {printf ("    Servo: write %d\n", val); };
};

// -----------------------------------------------------------------------------
void
readInput (
    char* filename)
{
    static FILE *fp = NULL;
    char         p [80];
    char        *s = p;

    if (NULL == fp)  {
        fp = fopen (filename, "r");
        if (0 > fp)  {
            perror ("fopen");
            exit (1);
        }
    }

    while ((char *)NULL != fgets (p, sizeof(p), fp))  {
#if 0
        if (1 >= strlen (p))
            return;
#endif

        if (3 <= dbg)   printf (" %s: %d %s", __func__, strlen (p), p);

        if (strstr (p, "pin"))  {
            int   pn;
            int   val;
            sscanf (p, "%*s %d %d", &pn, &val);
            if (debug)
                printf ("      set pin %d to %d\n", pn, val);

            pinVal [pn] = val;
        }
        else if (strstr (p, "anlg"))  {
            int   pn;
            int   val;
            sscanf (p, "%*s %d %d", &pn, &val);
            if (debug)
                printf ("      set pin %d to %d\n", pn, val);

            anlgVal [pn] = val;
        }


        else if (strstr (p, "loop"))  {
            int nLoop;
            sscanf (p, "%*s %d", &nLoop);
            while (nLoop--)
                loop ();
        }
    }

    printf (" %s: EOF\n", __func__);
    exit (0);
}

// -------------------------------------
char *progname;

int main (int argc, char **argv)  {
    int   c;

    progname = *argv;

    while ((c = getopt(argc, argv, "D:o")) != -1)  {
        printf (" %s: c %c\n", __func__, c);
        switch (c)  {
        case 'D':
            dbg = atoi (optarg);
            printf ("%s:  dbg %d\n", __func__, dbg);
            break;

        case 'o':
            break;

        default:
            printf ("Error: unknown option '%c'\n", optopt);
            break;
        };

    }

#define READ_INPUT
#ifdef READ_INPUT
    if (optind == argc)  {
        printf ("Usage: %s filename\n", progname);
        exit (1);
    }
#endif

    setup();

#ifdef READ_INPUT
    readInput (argv [optind]);
#endif
}
#endif

Hi @gcjr,

thank you for the reply.
Yes, I want exactly to simulate my sketch on the PC.
Thank you for sharing your code, I'll use it for inspiration.

I personally prefer to create an actual platform/core, to be able to re-use the same tools infrastructure to build the code (and in general, learning how to do could be useful in my future).
The point is that I am not currently able to let the Arduino infrastructure (both IDE and CLI)
compile my custom files inside the "cores/native" and "variants/default" directory.
So in the end, the sketch is compiled, but the linking fails (the references to my implemented methods and classes are obviously missing, since their files are not compiled).
For sure there must be a way... so I am wondering what I am doing wrong.

Any suggestion?

Regards.

sounds like you would like to add a simulation platform in addition to the other processors the IDE supports

The selected 'board' determines the core used. Do you have a 'boards.txt' file in your core?

Where is your 'boards.txt' file? "hardware/arduino/native/boards.txt"? "packages/arduino/hardware/native/boards.txt"?

What is in your boards.txt file?

Hi @johnwasser,

the boards.txt file is in: ~/.arduino15/packages/native/hardware/native/0.0.0/
(I have followed the structure of other cores, as ESP32 for example)
I am compiling with: arduino-cli compile --verbose -b native:native:default sketch_aug10a.ino
The contento of boards.txt is:

default.name=Default

default.build.mcu=native
default.build.core=native
default.build.variant=default
default.build.board=DEFAULT_NATIVE_BOARD

default.build.defines=

The content of platform is:

name=Native
version=0.0.0

runtime.tools.gcc.path=
runtime.tools.gcc.path=

compiler.path=
compiler.sdk.path=
compiler.prefix=

#
# Native Support Start
#
compiler.cpreprocessor.flags.native=
compiler.c.elf.libs.native=
compiler.c.flags.native=
compiler.cpp.flags.native=
compiler.S.flags.native=
compiler.c.elf.flags.native=
compiler.ar.flags.native=
build.extra_flags.native=
#
# Native Support End
#


# Compile Flags
compiler.cpreprocessor.flags={compiler.cpreprocessor.flags.{build.mcu}}
compiler.c.flags={compiler.c.flags.{build.mcu}}
compiler.cpp.flags={compiler.cpp.flags.{build.mcu}}
compiler.S.flags={compiler.S.flags.{build.mcu}}
compiler.c.elf.flags={compiler.c.elf.flags.{build.mcu}}
compiler.c.elf.libs={compiler.c.elf.libs.{build.mcu}}
compiler.ar.flags={compiler.ar.flags.{build.mcu}}

# Compilers
compiler.c.cmd={compiler.prefix}gcc
compiler.cpp.cmd={compiler.prefix}g++
compiler.S.cmd={compiler.prefix}gcc
compiler.c.elf.cmd={compiler.prefix}g++
compiler.as.cmd={compiler.prefix}as
compiler.ar.cmd={compiler.prefix}ar
compiler.size.cmd={compiler.prefix}size

# Arduino Compile Warning Levels
compiler.warning_flags=-Wall -Wextra -pedantic
compiler.warning_flags.none=-w
compiler.warning_flags.default=-Wall -Wextra -pedantic
compiler.warning_flags.more=-Wall -Wextra -pedantic -Werror
compiler.warning_flags.all=-Wall -Wextra -pedantic -Werror

# These can be overridden in platform.local.txt
compiler.c.extra_flags=
compiler.c.elf.extra_flags=
compiler.S.extra_flags=
compiler.cpp.extra_flags=
compiler.ar.extra_flags=
compiler.objcopy.eep.extra_flags=
compiler.elf2hex.extra_flags=
compiler.libraries.ldflags=

# This can be overriden in boards.txt
build.flash_size=4MB
build.flash_mode=dio
build.boot=bootloader
build.code_debug=0
build.defines=
build.loop_core=
build.event_core=
build.extra_flags=

## Compile c files
recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" -DARDUINO_VARIANT="{build.variant}" {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"

## Compile c++ files
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpreprocessor.flags} {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" -DARDUINO_VARIANT="{build.variant}" {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"

## Compile S files
recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.cpreprocessor.flags} {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} -DARDUINO_BOARD="{build.board}" -DARDUINO_VARIANT="{build.variant}" {compiler.S.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}"

## Create archives
recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}"

## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} {build.extra_flags} {object_files} "{archive_file_path}" -o "{build.path}/{build.project_name}.elf"

## Create bin
recipe.objcopy.bin.pattern="{tools.esptool_py.path}/{tools.esptool_py.cmd}" --chip {build.mcu} elf2image --flash_mode "{build.flash_mode}" --flash_freq "{build.flash_freq}" --flash_size "{build.flash_size}" -o "{build.path}/{build.project_name}.bin" "{build.path}/{build.project_name}.elf"
recipe.objcopy.bin.pattern.linux=python "{tools.esptool_py.path}/{tools.esptool_py.cmd}" --chip {build.mcu} elf2image --flash_mode "{build.flash_mode}" --flash_freq "{build.flash_freq}" --flash_size "{build.flash_size}" -o "{build.path}/{build.project_name}.bin" "{build.path}/{build.project_name}.elf"

## Save bin
recipe.output.tmp_file={build.project_name}.{build.mcu}.bin
recipe.output.save_file={build.project_name}.{build.mcu}.{build.variant}.bin

## Compute size
recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf"
recipe.size.regex=^(?:\.iram0\.text|\.iram0\.vectors|\.dram0\.data|\.flash\.text|\.flash\.rodata|)\s+([0-9]+).*
recipe.size.regex.data=^(?:\.dram0\.data|\.dram0\.bss|\.noinit)\s+([0-9]+).*

Thank you,
regards.

I put the platform.txt and boards.txt into packages/native/hardware/native/0.0.0/ and re-started the IDE. No 'native' boards show up. I don't know what has to be included next. I tried putting a copy of packages/arduino/hardware/avr/1.8.3/cores/arduino into packages/native/hardware/native/0.0.0/cores/native but that didn't help.

The Arduino boards platforms installed in the Arduino15 folder will only be recognized by the Arduino IDE if you have an "Additional Boards Manager URL" for the package index file in your preferences. That is a very nice thing if you want to share your platform with others and make it easy for them to install and update, but for experimentation and development it's overkill. For this purpose, I recommend instead to install the platform to the sketchbook folder, which does not impose this Boards Manager requirement.

The folder structure should look like this:

<sketchbook folder>
|_ hardware
   |_ native
      |_native
         |_ boards.txt
         |_ etc....

The first native folder level is the "vendor" folder. The second is the architecture (e.g., avr, samd). They don't need to match each other, but there's no problem if you do use the same name for both the vendor and architecture.

Hi,

thank you all for the answers.
I did not know the "sketchbook folder" trick, but it is not a problem for me: I am able to
use my custom core both with the IDE and with the CLI.
I did it in this way:

  • IDE: I put a reference to a local package json, by using the "file:////path-to/package_native_index.json".
  • CLI: I just added a line into arduino-cli.yaml (with "file:///path-to/package_native_index.json")

In both cases, I also put a copy of "package_native_index.json" in ".arduino15" dir.
Then I can select the board in the IDE, or just run arduino-cli board listall to see my board as listed. I also tested the sketchbook trick, with the same result of the other two methods.

My issue is still the same, board/core recognized, since the compiling starts and I can select it, but the linking fails, since my files inside the "cores/native" and "variants/default" folders are not compiled.

Regards.

The folder should be named cores

Yes, it was just a typo. I mean "cores/native".
I fixed the prev post. Thank you.

Hi,

just to post the solution in case someone in the future will have the same issue...
I was just missing the "-c" flag in the compiler directives in platform.txt.

Regards

1 Like