platformio / platform-native

Native: development platform for PlatformIO
https://registry.platformio.org/platforms/platformio/native
Apache License 2.0
21 stars 27 forks source link

Feature Request: native development on macOS using clang and lldb #22

Open marcelloDC opened 2 years ago

marcelloDC commented 2 years ago

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?

Inviz commented 1 year ago

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

MacDada commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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

Inviz commented 1 year ago

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: @.***>

MacDada commented 1 year ago

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 commented 1 year ago

There is a problem with my solution.

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

Edited original comment to include it.

pharapeti commented 1 year ago

Any update on OSX lldb support?

divStar commented 1 year ago

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...

nilo85 commented 9 months ago

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 commented 9 months ago

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!