homebrew-emacs-plus icon indicating copy to clipboard operation
homebrew-emacs-plus copied to clipboard

[General]: libgccjit.so error invoking gcc driver

Open elondres-mim opened this issue 1 year ago • 12 comments

Issue description

After updating to Sequoia I get the titular error every time I launch Emacs Plus from the applications folder or a saved-to-dock Emacs Plus and then run M-x.

I do not get the error in question when launching Emacs Plus from the command line, interestingly enough.

elondres-mim avatar Sep 23 '24 15:09 elondres-mim

Pretty sure it's related to https://github.com/d12frosted/homebrew-emacs-plus/issues/720

Env injection is broken for whatever reason. Frankly, I will not have any time soon to investigate, so hopefuly as more people upgrade, someone will be able to spend some time investigating.

I wonder if using exce-path-from-shell solves the issue.

d12frosted avatar Sep 23 '24 15:09 d12frosted

Pretty sure it's related to #720

This is the exact problem I ran into which led me to looking into the paths thing, so I'd assume the same.

Prior to relying on emacs-plus' automatic path stuff I was using exec-path-from-shell so I'd imagine that could be a good fallback here too.

Though in my case I'm just explicitly setting the value from the Info.plist via a few lines at the top of my .emacs so that I theoretically get exactly what emacs-plus would be giving me:

;; Temp: Explicitly set PATH environment variable and update exec-path to match it.
;; (the string here should be copied from the PATH in Emacs.app/Contents/Info.plist)
(setenv "PATH" "/opt/homebrew/bin:/opt/homebrew/sbin:...etc etc...")
(setq exec-path (split-string (getenv "PATH") path-separator))

efroemling avatar Sep 23 '24 16:09 efroemling

;; Temp: Explicitly set PATH environment variable and update exec-path to match it.
;; (the string here should be copied from the PATH in Emacs.app/Contents/Info.plist)
(setenv "PATH" "/opt/homebrew/bin:/opt/homebrew/sbin:...etc etc...")
(setq exec-path (split-string (getenv "PATH") path-separator))

@efroemling Thanks, this solution worked for me as well. Which kinda surprised me because the native compilation log was saying the libgccjit library emutls_w wasn't found. And only when compiling a handful of my packages. Sent me into the depths of the gcc directory...this solution is...much simpler 😅

citizensn1ps avatar Oct 01 '24 22:10 citizensn1ps

Pretty sure it's related to #720

This is the exact problem I ran into which led me to looking into the paths thing, so I'd assume the same.

Prior to relying on emacs-plus' automatic path stuff I was using exec-path-from-shell so I'd imagine that could be a good fallback here too.

Though in my case I'm just explicitly setting the value from the Info.plist via a few lines at the top of my .emacs so that I theoretically get exactly what emacs-plus would be giving me:

;; Temp: Explicitly set PATH environment variable and update exec-path to match it.
;; (the string here should be copied from the PATH in Emacs.app/Contents/Info.plist)
(setenv "PATH" "/opt/homebrew/bin:/opt/homebrew/sbin:...etc etc...")
(setq exec-path (split-string (getenv "PATH") path-separator))

Can confirm this works for me as well. Thank you, kind internet stranger!

EXT-OWL avatar Oct 08 '24 04:10 EXT-OWL

In my environment, setting the PATH as per efroemling's instructions did not work. I got the impression that it worked, but then noticed again the exact same error.

M-x getenv PATH: ~/bin:~/go/bin:~/.pyenv/plugins/pyenv-virtualenv/shims/:~/.pyenv/syms/:~/.sdkman/candidates/java/current/bin:opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

On the other hand, now looking for libgccjit.so I don't seem to find it anywhere. What package is it coming with and where is it supposed to be?

Update: I see libgccjit being installed, but there's no .so (only .dylibs)

al3xandru avatar Oct 10 '24 09:10 al3xandru

Decided to try enabling native compilation and got the libgccjit library emutls_w error other folk have encountered. It sent me down a right rabbit hole but setting the path like @efroemling said worked a treat.

One quick extra bit info, @EXT-OWL mentioned exec-path-from-shell, I am using that still but was still encountering the issue. I set the path manually within my early-init.el, that's what fixed this. Perhaps shifting exec-path-from-shell to earlier in the process would've worked, I may try that, but it would've meant extra work to get it going before my package manager etc.

rosstimson avatar Feb 20 '25 21:02 rosstimson

@rosstimson that's basically why I strive to have injected PATH. It doesn't work for whatever reasons in the latest version of macos (see #720). But that's the thing - PATH and other env variables must be set before Emacs attempts to use libgccjit.

d12frosted avatar Feb 23 '25 11:02 d12frosted

Same issue.. MacOS 15.4.1 (24E263)

mateialexandru avatar May 11 '25 22:05 mateialexandru

⛔ Error (use-package): emacs/:config: Native compiler error: (lambda (arg3 &optional) (let ((f #'yes-or-no-p)) (funcall f arg3))), "Compiling /Users/x/.emacs.d/eln-cache/30.1-cf025b42/subr--trampoline-7965732d6f722d6e6f2d70_yes_or_no_p_0.eln... ld: library 'emutls_w' not found libgccjit.so: error: error invoking gcc driver Internal native compiler error: "failed to compile", "/Users/x/.emacs.d/eln-cache/30.1-cf025b42/subr--trampoline-7965732d6f722d6e6f2d70_yes_or_no_p_0.eln", "error invoking gcc driver"

It's a bit disappointing that from the start, this Emacs distribution introduces friction on a brand new MacBook :( Is there something that we can do to anticipate the path?

Here is how I extracted the path in my case: cat $(brew --cellar emacs-plus@30)/30.1/Emacs.app/Contents/Info.plist Manually look for <key>PATH</key>, and then apply suggestions from @efroemling

mateialexandru avatar May 11 '25 22:05 mateialexandru

Hack that helped me overcome this temporarily has been to set PATH within .emacs.d/early-init.el explicitly. I took the PATH variable value from the /opt/homebrew/opt/emacs-plus@30/Emacs.app/Contents/Info.plist and just set it like so:

;; TEMP: Explicitly set PATH environment variable and update exec-path to match it
;; otherwise emacs throws jit compilation errors
(setenv "PATH" "VALUEOFTHEPATH")
(setq exec-path (split-string (getenv "PATH") path-separator))

For some reason, without this explicit setenv, PATH within emacs was quite barebones for me.

EDIT: and I'm still subscribed to this issue so I can see if there's any alternative way to properly fix it :-D

ivantomica avatar May 14 '25 18:05 ivantomica

I'm getting the same error, and the problem persists after trying most of the workarounds described above. I can help providing details if someone is actively working on this.

ajarmst avatar May 22 '25 16:05 ajarmst

@d12frosted Hi, think I found a solution to fix this in general. I'm not a brew expert, but after a session with an LLM this was the output and it seems somewhat reasonable to me. Any thoughts on this? I imagine this will also fix https://github.com/d12frosted/homebrew-emacs-plus/issues/720

Alright, this is excellent! We have the exact code.

You've correctly identified that inject_path in EmacsBase.rb is the culprit, directly modifying the Info.plist with PlistBuddy. To fix this, we need to:

  1. Remove the inject_path call from the [email protected] formula (and potentially other formula files if they exist for different Emacs versions).
  2. Remove the inject_path definition from EmacsBase.rb (as it's no longer needed).
  3. Modify the Emacs.app/Contents/MacOS/Emacs wrapper script to source the user's shell environment.

This is a BREAKING CHANGE in philosophy for the emacs-plus formula, so be prepared to explain the rationale in your PR. The current Info.plist injection is indeed outdated and brittle on modern macOS.

Here's how to structure your PR:


Step 1: Modify homebrew-emacs-plus/Formula/[email protected]

Find the install method. Locate and remove the line:

      # inject PATH to Info.plist
      inject_path

After removing that line, find the section where bin/emacs is created (around line 143 in your provided code):

      # Replace the symlink with one that avoids starting Cocoa.
      (bin/"emacs").unlink # Kill the existing symlink
      (bin/"emacs").write <<~EOS
        #!/bin/bash
        exec #{prefix}/Emacs.app/Contents/MacOS/Emacs "$@"
      EOS

This section is for the emacs command-line alias. We're interested in the Emacs.app/Contents/MacOS/Emacs itself.

Further down, where prefix.install "nextstep/Emacs.app" occurs, is where the .app bundle is put in place. After this, we need to modify the internal wrapper script.

Add the following code right after prefix.install "nextstep/Emacs.app" and (prefix/"Emacs.app/Contents").install "native-lisp" in [email protected]:

      prefix.install "nextstep/Emacs.app"
      (prefix/"Emacs.app/Contents").install "native-lisp"

      # Patch the Emacs.app/Contents/MacOS/Emacs wrapper script to load the user's shell environment
      # This addresses the issue of GUI apps not inheriting PATH from the shell.
      # This replaces the brittle LSEnvironment injection.
      emacs_wrapper_script = "#{prefix}/Emacs.app/Contents/MacOS/Emacs"
      inreplace emacs_wrapper_script, /^#!/bin\/bash/, <<~EOS
        #!/bin/bash
        # Load user's shell profile to ensure correct PATH and other environment variables
        # This fixes issues with GUI Emacs.app not finding command-line tools.

        # Check for zsh profiles (common on macOS)
        if [ -f "$HOME/.zprofile" ]; then
            source "$HOME/.zprofile"
        elif [ -f "$HOME/.bash_profile" ]; then
            source "$HOME/.bash_profile"
        elif [ -f "$HOME/.zshrc" ]; then
            source "$HOME/.zshrc"
        elif [ -f "$HOME/.bashrc" ]; then
            source "$HOME/.bashrc"
        elif [ -f "$HOME/.profile" ]; then
            source "$HOME/.profile"
        fi

        # Ensure Homebrew's default paths are in PATH, as a fallback or for consistency.
        # This is especially important if user's shell profile doesn't correctly set Homebrew paths.
        if [ "$(uname -m)" = "arm64" ]; then
          export PATH="/opt/homebrew/bin:/opt/homebrew/sbin:$PATH"
        else
          export PATH="/usr/local/bin:/usr/local/sbin:$PATH"
        fi
        # The original shebang line follows (now redundant but kept for clarity in the patch)
      EOS

      # Ensure the wrapper script is executable
      chmod 0755, emacs_wrapper_script

Explanation of the Ruby inreplace:

  • emacs_wrapper_script = "#{prefix}/Emacs.app/Contents/MacOS/Emacs": Defines the path to the wrapper script we want to modify.
  • inreplace emacs_wrapper_script, /^#!/bin\/bash/, <<~EOS ... EOS: This is Homebrew's helper to perform an in-place replacement.
    • The first argument (emacs_wrapper_script) is the file to modify.
    • The second argument (/^#!/bin\/bash/) is a regular expression matching the line to replace (the initial shebang #!/bin/bash).
    • The <<~EOS ... EOS block is a "heredoc" in Ruby, which allows you to define a multi-line string. This entire block will replace the matched shebang line.
    • Inside the heredoc, we put the bash script logic to source the user's environment and explicitly add Homebrew paths.

Step 2: Modify homebrew-emacs-plus/Library/EmacsBase.rb

Locate the inject_path method (around line 38 in your provided code) and delete the entire method:

  def inject_path
    ohai "Injecting PATH value to Emacs.app/Contents/Info.plist"
    app = "#{prefix}/Emacs.app"
    plist = "#{app}/Contents/Info.plist"
    path = PATH.new(ORIGINAL_PATHS)

    puts "Patching plist at #{plist} with following PATH value:"
    path.each_entry { |x|
      puts x
    }

    system "/usr/libexec/PlistBuddy -c 'Add :LSEnvironment dict' '#{plist}'"
    system "/usr/libexec/PlistBuddy -c 'Add :LSEnvironment:PATH string' '#{plist}'"
    system "/usr/libexec/PlistBuddy -c 'Set :LSEnvironment:PATH #{path}' '#{plist}'"
    system "/usr/libexec/PlistBuddy -c 'Print :LSEnvironment' '#{plist}'"
    system "touch '#{app}'"
  end

Also, update the caveats method to reflect the change:

  def caveats
    <<~EOS
      Emacs.app was installed to:
        #{prefix}

      To link the application to default Homebrew App location:
        osascript -e 'tell application "Finder" to make alias file to posix file "#{prefix}/Emacs.app" at posix file "/Applications" with properties {name:"Emacs.app"}'

      # Remove this line: Your PATH value was injected into Emacs.app/Contents/Info.plist
      # Replace it with something like:
      Your PATH is now loaded from your shell profile (~/.zprofile, ~/.bash_profile, etc.) when launching Emacs.app from Finder/Spotlight.

      Report any issues to https://github.com/d12frosted/homebrew-emacs-plus
    EOS
  end

daninus14 avatar Jun 10 '25 09:06 daninus14

Also something I've been facing, using the Doom Emacs distribution for what that's worth.

I've added the path from /opt/homebrew/opt/emacs-plus@30/Emacs.app/Contents/Info.plist to the top of my .config/emacs/early-init.el:

(setenv "PATH" "VALUEOFTHEPATH")
(setq exec-path (split-string (getenv "PATH") path-separator))

I thought it wasn't working, but I grep'd my .doom.d and found I'd been setting PATH in another way from an earlier fix attempt. All seems to work now

Wheest avatar Jul 11 '25 10:07 Wheest

;; Temp: Explicitly set PATH environment variable and update exec-path to match it. ;; (the string here should be copied from the PATH in Emacs.app/Contents/Info.plist) (setenv "PATH" "/opt/homebrew/bin:/opt/homebrew/sbin:...etc etc...") (setq exec-path (split-string (getenv "PATH") path-separator))

@efroemling Thanks, this solution worked for me.

StepaniaH avatar Jul 28 '25 08:07 StepaniaH

Some issue. have to disable native comp

(setq native-comp-deferred-compilation t)
(setq native-comp-async-report-warnings-errors nil)

wwulfric avatar Aug 09 '25 14:08 wwulfric

can you try building from this branch - https://github.com/d12frosted/homebrew-emacs-plus/pull/841?

d12frosted avatar Oct 17 '25 17:10 d12frosted

should be fixed with #841. let me know if the issue persists.

d12frosted avatar Nov 01 '25 15:11 d12frosted