How to define env:native in platformio.ini for a MacOS command line tool that uses the Cocoa framework

The C code at the end of this message allows me to simulate button presses with the modifier keys on MacOS. The code allows me to develop and test embedded modules in the Mac’s native environment. The code builds fine if I use:
gcc -g -o0 -Wall src/main.c -I./ -framework Cocoa -o clt
in the Mac’s terminal (note that the -framework flag is unrelated to a framework in PlatformIO). What I cannot figure out however is how to define a [env:native] in platformio.ini that will build the code too. The following did not work:

[env:native]
platform = native
build_flags =
    -g
    -framework Cocoa
;    -Wl,-framework Cocoa ; tried this too, did not work

A Verbose build shows that the -framework Cocoa flag is ignored in the compilation step:

Processing native (platform: native; build_flags: -g, -o0, -framework Cocoa; monitor_speed: 115200)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 1 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
gcc -o .pio/build/native/src/main.o -c -g -o0 -DPLATFORMIO=60115 -Iinclude -Isrc src/main.c
gcc -o .pio/build/native/program .pio/build/native/src/main.o -L.pio/build/native
clang: error: no such file or directory: '.pio/build/native/src/main.o'
clang: error: no input files
*** [.pio/build/native/program] Error 1

Can somebody help me to properly define the [env:native] ?

Below is the c code that simulates button presses on MacOS.

#include <stdio.h>
#include <ApplicationServices/ApplicationServices.h>
#include <unistd.h> // For usleep function
#define CMD_KEY   (CGKeyCode) 55U
int main() {
    while (1)
    {
        uint8_t btn_state = (CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, CMD_KEY)) ? 1 : 0;
        if (btn_state)
        {
            printf("1");
        }
        fflush(stdout);
        usleep(1000 * 100);
    }
    return 0;
}
1 Like

Hi @karamiller7890, my apologies in case you’re not a bot, but this: board = native sounds like ChatGPT hallucinating. There is no board named “native”.

Your other suggestions don’t work either. I still get linker errors no matter what -I paths i include.

Processing native (platform: native; build_flags: -g, -framework Cocoa, -I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks; lib_ldf_mode: deep+; monitor_speed: 115200)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ deep+, Compatibility ~ soft
Found 1 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
gcc -o .pio/build/native/src/main.o -c -g -DPLATFORMIO=60115 -Iinclude -Isrc -I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks src/main.c
gcc -o .pio/build/native/program .pio/build/native/src/main.o -L.pio/build/native
ld: Undefined symbols:
  _CGEventSourceKeyState, referenced from:
      _main in main.o
clang: error: linker command failed with exit code 1 (use -v to see invocation)
*** [.pio/build/native/program] Error 1

Yep, I don’t think that’s needed.

I’ve tried to use the “real” CLang (instead of the Apple’s “built-in” CLang impersonating GCC) → platform was native, board was not specified:

I figured it out. The flag '-framework Cocoa` is a flag for the linker. To get it passed to the linker one has to append LINKFLAGS to the SCons environment. For this I created an extra_script (saved in the same folder as platform.ini):

file: pre_extra_script.py

Import("env")
env.Append(LINKFLAGS=['-framework', 'Cocoa'])

and make sure it gets executed before the build starts by adding it to the platform.ini file.

file: platform.ini

[env:native]
platform = native
extra_scripts = pre:pre_extra_script.py

No additional build_flags are necessary.

2 Likes