platform-native icon indicating copy to clipboard operation
platform-native copied to clipboard

Feature Request: native development on macOS using clang and lldb

Open marcelloDC opened this issue 2 years ago • 12 comments

Feature request

As far as I am aware PlatformIO only supports native development on macOS using gcc and gdb. This is problematic. First, because installing gdb on Intel based macs is not straightforward because of the need to code-sign the application, but secondly and more importantly, because gdb is not even supported on M1/M2 macs and apparently (link) won’t be in the near future.

Being able to code, test and debug natively greatly speeds up development. It would therefore be great if support were available to compile and debug code using macOS’s compiler (clang) and debugger (lldb). Would it be possible to provide that support?

marcelloDC avatar Nov 25 '22 21:11 marcelloDC

Compiling with clang seems to work, but debugging ability is really missing

Inviz avatar Jan 02 '23 08:01 Inviz

Actually gcc is… Apple's Clang by default. At least on my (Intel) Mac:

➜  ~ gcc -v
Apple clang version 14.0.0 (clang-1400.0.29.202)
Target: x86_64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
➜  ~ sw_vers -productVersion 
12.6.3
➜  ~ system_profiler SPSoftwareDataType
Software:

    System Software Overview:

      System Version: macOS 12.6.3 (21G419)
      Kernel Version: Darwin 21.6.0

So, the funny thing is, it could also be useful to me – as I want to to switch to the "generic" Clang, instead of using Apple's Clang.

So, is it possible to use "generic" Clang within native platform (which uses GCC and therefore Apple's Clang by default)?

MacDada avatar Feb 16 '23 21:02 MacDada

OK, so I've got the (generic) Clang working, instead of the native using "fake GCC" being Apple's Clang.

  1. I have an Intel MBP early 2015 with Monterey macOS 12.6.3 (21G419)
  2. I installed Clang with Homebrew: brew install llvm.
  3. I've put it to my $PATH so simple clang in cmd would run it:
    # ~/.zshrc
    # clang from Homebrew
    export PATH="$(brew --prefix llvm)/bin:$PATH"
    # I'm not sure if the lines below are necessary
    export LDFLAGS="-L$(brew --prefix llvm)/lib"
    export CPPFLAGS="-I$(brew --prefix llvm)/include"
    
    As the result, I can use the "real" Clang, not the Apple's one:
    ✗ clang -v
    Homebrew clang version 15.0.7
    Target: x86_64-apple-darwin21.6.0
    Thread model: posix
    InstalledDir: /usr/local/opt/llvm/bin
    
  4. I've added a Python script that replaces the default native toolchain to clang:
    # Switches PlatformIO to be using Clang instead of the default toolchain (most likely GCC).
    # Activate it with `extra_scripts = post:pio_use_clang.py` in `platformio.ini` config.
    
    Import("env")
    Import("projenv")
    
    verbose = True
    veryVerbose = False
    
    if veryVerbose:
        print(env.Dump())
        print(projenv.Dump())
    
    print("\nReplacing the default toolchain with Clang…\n")
    
    for theEnvName, theEnv in {"env": env, "projenv": projenv}.items():
        if verbose or veryVerbose:
            print(f"Default CC ({theEnvName}): {theEnv.get('CC')}")
            print(f"Default CXX ({theEnvName}): {theEnv.get('CXX')}")
    
        # Preserve C and C++ build flags
        cflagsBackup = theEnv.get("CFLAGS", [])
        cxxflagsBackup = theEnv.get("CXXFLAGS", [])
    
        theEnv.Tool("clang")
        theEnv.Tool("clang++")
    
        # Restore C/C++ build flags as they were overridden by env.Tool
        theEnv.Append(
            CFLAGS=cflagsBackup,
            CXXFLAGS=cxxflagsBackup
        )
    
        if verbose or veryVerbose:
            print(f"\nReplaced CC ({theEnvName}): {theEnv.get('CC')}")
            print(f"Replaced CXX ({theEnvName}): {theEnv.get('CXX')}\n")
    
    if veryVerbose:
        print(env.Dump())
        print(projenv.Dump())
    
  5. I've registerd this as a post extra script in platformio.ini for my native env:
    [env:native]
    platform = native
    build_flags =
        -std=gnu++20
        -Wall
    build_src_filter = "+<native.cpp>"
    extra_scripts = post:pio_use_clang.py
    

To test it, my src/native.cpp:

#include <iostream>

int main() {
    std::cout << __cplusplus << std::endl;

#ifdef __clang__
    std::cout << "CLANG" << std::endl;
#else
    std::cout << "GCC" << std::endl;
#endif

#ifdef __clang__
    std::cout
        << __clang_major__
        << "."
        << __clang_minor__
        << "."
        << __clang_patchlevel__
        << std::endl;
#else
    std::cout
        << __GNUC__
        << "."
        << __GNUC_MINOR__
        << "."
        << __GNUC_PATCHLEVEL__
        << std::endl;
#endif

    return 0;
}

The result:

➜  DnWiFiDoorLock git:(master) ✗ rm -rf .pio              
➜  DnWiFiDoorLock git:(master) ✗ pio run -e native -t exec -vvv
Processing native (platform: native; build_flags: -std=gnu++20, -Wall; build_src_filter: "+<native.cpp>"; test_filter: native/*; extra_scripts: post:pio_use_clang.py; lib_ldf_mode: chain; test_framework: unity)
-------------------------------------------------------------------------------------------------------------------------------------------------------------
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 9 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode

Replacing the default toolchain with Clang…

clang++ -o .pio/build/native/src/native.o -c -Wall -DPLATFORMIO=60106 -Iinclude -Isrc src/native.cpp
clang++ -o .pio/build/native/program .pio/build/native/src/native.o -L.pio/build/native
.pio/build/native/program
201402
CLANG
15.0.7

MacDada avatar Feb 17 '23 19:02 MacDada

As you can see, it can be quite easily done – the only problem is the knowledge (how to do it).

Question: how can we improve PlatformIO to support this out of the box?

I can try to make a PR. Maybe an option for the native platform, that would force native to be using clang (or any other toolchain)? Or maybe just an example in the docs, on how to achieve it "manually", the way I did it?

MacDada avatar Feb 17 '23 19:02 MacDada

There is a problem with my solution.

For some reason -std=gnu++20 is missing WHILE TESTING (pio test -e native -vvv).

When building (pio run -e native -t exec -vvv) it is there.

Without my script, it is also there. So, WTH?

The flag is specified by build_flags = -std=gnu++20 in platformio.ini.


EDIT: I added -Wextra to build_flags – it IS passed in. So only -std is removed for some reason while testing…


EDIT: fixed

MacDada avatar Feb 18 '23 00:02 MacDada

Does debugging work?

On Sat, Feb 18, 2023 at 8:16 AM Dawid Nowak @.***> wrote:

There is a problem with my solution https://github.com/platformio/platform-native/issues/22#issuecomment-1435140844 .

For some reason -std=gnu++20 is missing WHILE TESTING (pio test -e native -vvv).

When building (pio run -e native -t exec -vvv) it is there.

Without my script, it is also there. So, WTH?

The flag is declared as build_flags = -std=gnu++20 in platformio.ini.

— Reply to this email directly, view it on GitHub https://github.com/platformio/platform-native/issues/22#issuecomment-1435415352, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAAVFEOQ2FSVGLR6XDKSITWYAIE5ANCNFSM6AAAAAASLULKWA . You are receiving this because you commented.Message ID: @.***>

Inviz avatar Feb 18 '23 03:02 Inviz

Does debugging work?

IDK, it has never worked for me before: https://community.platformio.org/t/clion-native-debugging-not-working/30796?u=dvdnwk

MacDada avatar Feb 18 '23 06:02 MacDada

There is a problem with my solution.

Fixed this with a "backup" that native does as well.

Edited original comment to include it.

MacDada avatar Feb 19 '23 20:02 MacDada

Any update on OSX lldb support?

pharapeti avatar Nov 01 '23 09:11 pharapeti

Is there a chance to possibly get this to work in platformio-core somehow?

I am not really happy with gcc, especially seeing as bugs such as this one are not fixed for years (other compilers do not have this particular issue) and especially because I am using Clang-Tidy in CLion, yet gcc does something different than what Clang-Tidy / Clang in CLion finds...

divStar avatar Nov 30 '23 21:11 divStar

I just tried the suggested python script but get error

Default CC (env): gcc
Default CXX (env): g++
ModuleNotFoundError: No module named 'SCons.Tool.MSCommon':
  File "/usr/local/Cellar/platformio/6.1.13/libexec/lib/python3.12/site-packages/platformio/builder/main.py", line 180:

nilo85 avatar Mar 06 '24 21:03 nilo85

Found a nice workaround, VSCode supports something called devcontainers and now I can run a proper gnu toolchain via docker. https://github.com/prenone/platformio-vscode-devcontainer Used this to kickstart it!

nilo85 avatar Mar 07 '24 20:03 nilo85