emacs 系统环境变量问题

我启动Emacs的方式是在iterm2中,nohup emacs --debug-init > ~/.emacs.d/log.log 2>&1

在iterm2中的可以找到npm,以及 yaml-lanuage-server 这些

怎么在emacs中就找不到了呢?

emacs使用的是哪个系统环境?怎么会找不到呢?

有一个插件 exec-path-from-shell 可以让你 Emacs 中的环境变量和终端保持一致

1 个赞

exec-path-from-shell 的原理是启动一个 shell 子进程获取环境变量,而且理论上每次 exec-path-from-shell-initialize 的时候都会执行一次。如果很在乎 Emacs 的启动时间,可以考虑以下方案:

  1. macOS上,你可以安装 homebrew-emacs-plus,这里提供的 Ruby 脚本在编译 Emacs 后会进行环境变量注入,具体来说,就是往 Info.plist 里面写一些键值对。这样,每次打开 Emacs.app 的时候,系统会自动完成环境变量注入。不过,homebrew-emacs-plus 只能帮你注入 PATH 环境变量,当然你可以自己修改 Info.plist。
  2. Linux 上你可以修改 systemd 配置实现环境变量注入。这部分我很久以前配的,已经印象不深了,如果需要的话可以谷歌看看,资料会比 macOS Info.plist 多。
  3. 我之前写过一个 cache 的 hack:
;; Cache mechanism for `exec-path-from-shell'.
(defvar exec-path-from-shell-cache-file (concat user-emacs-directory "shell-env"))
(defvar exec-path-from-shell-no-cache nil)

(defun +exec-path-from-shell-write-cache (env-list)
  "Write ENV-LIST to cache.

ENV-LIST is a list of (NAME . VALUE)."
  (with-temp-file exec-path-from-shell-cache-file
    (point-min)
    (insert (format ";;; shell-env -- Cache file for exec-path-from-shell. -*- lexical-binding: t -*-
;;; Commentary:

;; DO NOT EDIT! Auto-generated by `+exec-path-from-shell-write-cache' in [%s]

;;; Code:

" (current-time-string)))
    (mapc (lambda (pair)
            (let ((name (car pair))
                  (value (cdr pair)))
              (insert (format "(setenv \"%s\" \"%s\")\n" name value))
              ;; Handle PATH specially.
              (when (string-equal "PATH" name)
                (insert (format "(setq exec-path '(%s))\n"
                                (string-join (mapcar (lambda (string-var) (format "\"%s\"" string-var))
                                                     (append (parse-colon-path value) (list exec-directory)))
                                             " ")))
                (insert (format "(setq-default eshell-path-env \"%s\")\n" value)))))
          env-list)
    (insert ";;; shell-env ends here\n")))

(defun +exec-path-from-shell-invalidate-cache ()
  "Invalidate the cache for envs.

This must be called manually after the shell environment
variables are changed."
  (interactive)
  (delete-file exec-path-from-shell-cache-file))

(advice-add 'exec-path-from-shell-initialize :around
            (defun +exec-path-from-shell-respect-cache-a (old-function)
              (if exec-path-from-shell-no-cache
                  (funcall old-function)
                (let ((cache-file exec-path-from-shell-cache-file))
                  (if (file-exists-p exec-path-from-shell-cache-file)
                      (progn
                        (message "[exec-path-from-shell] read envs from cache")
                        (load exec-path-from-shell-cache-file))
                    (let ((env-list (funcall old-function)))
                      (unless exec-path-from-shell-no-cache
                        (+exec-path-from-shell-write-cache env-list))))))))

这个 hack 可以使得 exec-path-from-shell-initialize 优先尝试读取 Emacs 配置目录下的 shell-env 文件,如果找到了就直接从中读取环境变量,否则建立新的 cache。这样免去了启用 shell 的耗时,尤其是当你的 shell 如果很 fancy,有很多启动脚本时,cache 作用比较显著。我使用这个 cache 可以使得 Emacs 的启动时间减少 0.15s 左右。

1 个赞