;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2022 Pierre Langlois ;;; ;;; This file is part of GNU Guix. ;;; ;;; GNU Guix is free software; you can redistribute it and/or modify it ;;; under the terms of the GNU General Public License as published by ;;; the Free Software Foundation; either version 3 of the License, or (at ;;; your option) any later version. ;;; ;;; GNU Guix is distributed in the hope that it will be useful, but ;;; WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;;; GNU General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with GNU Guix. If not, see . (define-module (guix build tree-sitter-build-system) #:use-module ((guix build node-build-system) #:prefix node:) #:use-module (guix build json) #:use-module (guix build utils) #:use-module (ice-9 match) #:use-module (ice-9 regex) #:use-module (srfi srfi-1) #:export (%standard-phases tree-sitter-build)) (define (tree-sitter-node-inputs inputs) "" (alist-delete "node" (alist-delete "source" (filter (match-lambda ((label . directory) (directory-exists? (string-append directory "/lib/node_modules"))) (_ #f)) inputs)))) ;;; ;;; Phases. ;;; (define* (adjust-dependencies #:key inputs #:allow-other-keys) "" (node:with-atomic-json-file-replacement "package.json" (match-lambda (('@ . pkg-meta-alist) (cons '@ (map (match-lambda (("dependencies" @ . deps) '("dependencies" @)) (("devDependencies" @ . deps) `("devDependencies" @ ,@(map (lambda (input) `(,(car input) . "latest")) (tree-sitter-node-inputs inputs)))) (other other)) pkg-meta-alist)))))) (define (build . _) (invoke "tree-sitter" "generate" "--no-bindings") #t) (define (check . _) (invoke "tree-sitter" "test") #t) (define* (install #:key outputs #:allow-other-keys) (use-modules (guix build json) (ice-9 regex)) (let* ((name (assoc-ref (call-with-input-file "package.json" read-json) "name")) (lang (cond ((string-match "^(@.*/)?tree-sitter-(.*)$" name) => (lambda (m) (match:substring m 2))) (else #f))) (lib (string-append (assoc-ref outputs "out") "/lib/tree-sitter"))) (mkdir-p lib) (define (source-file path) (if (file-exists? path) path #f)) (apply invoke `("g++" "-shared" "-fPIC" "-fno-exceptions" "-O2" "-g" "-o" ,(string-append lib "/" lang ".so") ,@(cond ((source-file "src/scanner.c") => (lambda (file) (list "-xc" "-std=c99" file))) ((source-file "src/scanner.cc") => (lambda (file) (list file))) (else '())) "-xc" "src/parser.c")))) (define* (install-js #:key inputs outputs #:allow-other-keys) (invoke (search-input-file inputs "/bin/npm") "--prefix" (assoc-ref outputs "js") "--global" "--offline" "--loglevel" "info" "--production" ;; Skip scripts to prevent building bindings via GYP. "--ignore-scripts" "install" "../package.tgz")) (define %standard-phases (modify-phases node:%standard-phases (add-before 'patch-dependencies 'adjust-dependencies adjust-dependencies) (replace 'build build) (replace 'check check) (replace 'install install) (add-after 'install 'install-js install-js))) (define* (tree-sitter-build #:key inputs (phases %standard-phases) #:allow-other-keys #:rest args) (apply node:node-build #:inputs inputs #:phases phases args))