Function: treesit--install-language-grammar-1

treesit--install-language-grammar-1 is a byte-compiled function defined in treesit.el.gz.

Signature

(treesit--install-language-grammar-1 OUT-DIR LANG URL &optional REVISION SOURCE-DIR CC C++)

Documentation

Install and compile a tree-sitter language grammar library.

OUT-DIR is the directory to put the compiled library file. If it is nil, the "tree-sitter" directory under user's Emacs configuration directory is used (and automatically created if it does not exist).

For LANG, URL, REVISION, SOURCE-DIR, GRAMMAR-DIR, CC, C++, see treesit-language-source-alist. If anything goes wrong, this function signals an error.

Source Code

;; Defined in /usr/src/emacs/lisp/treesit.el.gz
(defun treesit--install-language-grammar-1
    (out-dir lang url &optional revision source-dir cc c++)
  "Install and compile a tree-sitter language grammar library.

OUT-DIR is the directory to put the compiled library file.  If it
is nil, the \"tree-sitter\" directory under user's Emacs
configuration directory is used (and automatically created if it
does not exist).

For LANG, URL, REVISION, SOURCE-DIR, GRAMMAR-DIR, CC, C++, see
`treesit-language-source-alist'.  If anything goes wrong, this
function signals an error."
  (let* ((lang (symbol-name lang))
         (maybe-repo-dir (expand-file-name url))
         (url-is-dir (file-accessible-directory-p maybe-repo-dir))
         (default-directory (make-temp-file "treesit-workdir" t))
         (workdir (if url-is-dir
                      maybe-repo-dir
                    (expand-file-name "repo")))
         (source-dir (expand-file-name (or source-dir "src") workdir))
         (cc (or cc (seq-find #'executable-find '("cc" "gcc" "c99"))
                 ;; If no C compiler found, just use cc and let
                 ;; `call-process' signal the error.
                 "cc"))
         (c++ (or c++ (seq-find #'executable-find '("c++" "g++"))
                  "c++"))
         (soext (or (car dynamic-library-suffixes)
                    (signal 'treesit-error '("Emacs cannot figure out the file extension for dynamic libraries for this system, because `dynamic-library-suffixes' is nil"))))
         (out-dir (or (and out-dir (expand-file-name out-dir))
                      (locate-user-emacs-file "tree-sitter")))
         (lib-name (concat "libtree-sitter-" lang soext)))
    (unwind-protect
        (with-temp-buffer
          (if url-is-dir
              (when revision
                (treesit--git-checkout-branch workdir revision))
            (treesit--git-clone-repo url revision workdir))
          ;; We need to go into the source directory because some
          ;; header files use relative path (#include "../xxx").
          ;; cd "${sourcedir}"
          (setq default-directory source-dir)
          (message "Compiling library")
          ;; cc -fPIC -c -I. parser.c
          (treesit--call-process-signal
           cc nil t nil "-fPIC" "-c" "-I." "parser.c")
          ;; cc -fPIC -c -I. scanner.c
          (when (file-exists-p "scanner.c")
            (treesit--call-process-signal
             cc nil t nil "-fPIC" "-c" "-I." "scanner.c"))
          ;; c++ -fPIC -I. -c scanner.cc
          (when (file-exists-p "scanner.cc")
            (treesit--call-process-signal
             c++ nil t nil "-fPIC" "-c" "-I." "scanner.cc"))
          ;; cc/c++ -fPIC -shared *.o -o "libtree-sitter-${lang}.${soext}"
          (apply #'treesit--call-process-signal
                 (if (file-exists-p "scanner.cc") c++ cc)
                 nil t nil
                 (if (eq system-type 'cygwin)
                     `("-shared" "-Wl,-dynamicbase"
                       ,@(directory-files
                          default-directory nil
                          (rx bos (+ anychar) ".o" eos))
                       "-o" ,lib-name)
                   `("-fPIC" "-shared"
                     ,@(directory-files
                        default-directory nil
                        (rx bos (+ anychar) ".o" eos))
                     "-o" ,lib-name)))
          ;; Copy out.
          (unless (file-exists-p out-dir)
            (make-directory out-dir t))
          (let* ((library-fname (expand-file-name lib-name out-dir))
                 (old-fname (concat library-fname ".old")))
            ;; Rename the existing shared library, if any, then
            ;; install the new one, and try deleting the old one.
            ;; This is for Windows systems, where we cannot simply
            ;; overwrite a DLL that is being used.
            (if (file-exists-p library-fname)
                (rename-file library-fname old-fname t))
            (copy-file lib-name (file-name-as-directory out-dir) t t)
            ;; Ignore errors, in case the old version is still used.
            (ignore-errors (delete-file old-fname)))
          (message "Library installed to %s/%s" out-dir lib-name))
      ;; Remove workdir if it's not a repo owned by user and we
      ;; managed to create it in the first place.
      (when (and (not url-is-dir) (file-exists-p workdir))
        (delete-directory workdir t)))))