~ruther/guix-local

5f7a1a4def8494940a4a2bc3728fb9cd927a14f8 — Ricardo Wurmus 10 years ago 535e2a2
build: Add Ant build system.

* guix/build-system/ant.scm: New file.
* guix/build/ant-build-system: New file.
* Makefile.am (MODULES): Add new files.
* doc/guix.texi (Build Systems): Document ant-build-system.
4 files changed, 332 insertions(+), 0 deletions(-)

M Makefile.am
M doc/guix.texi
A guix/build-system/ant.scm
A guix/build/ant-build-system.scm
M Makefile.am => Makefile.am +2 -0
@@ 56,6 56,7 @@ MODULES =					\
  guix/graph.scm				\
  guix/cve.scm					\
  guix/build-system.scm				\
  guix/build-system/ant.scm			\
  guix/build-system/cmake.scm			\
  guix/build-system/emacs.scm			\
  guix/build-system/glib-or-gtk.scm		\


@@ 75,6 76,7 @@ MODULES =					\
  guix/cvs-download.scm				\
  guix/svn-download.scm				\
  guix/ui.scm					\
  guix/build/ant-build-system.scm		\
  guix/build/download.scm			\
  guix/build/cmake-build-system.scm		\
  guix/build/emacs-build-system.scm		\

M doc/guix.texi => doc/guix.texi +21 -0
@@ 2720,6 2720,27 @@ of @var{gnu-build-system}, and differ mainly in the set of inputs
implicitly added to the build process, and in the list of phases
executed.  Some of these build systems are listed below.

@defvr {Scheme Variable} ant-build-system
This variable is exported by @code{(guix build-system ant)}.  It
implements the build procedure for Java packages that can be built with
@url{http://ant.apache.org/, Ant build tool}.

It adds both @code{ant} and the @dfn{Java Development Kit} (JDK) as
provided by the @code{icedtea} package to the set of inputs.  Different
packages can be specified with the @code{#:ant} and @code{#:jdk}
parameters, respectively.

When the original package does not provide a suitable Ant build file,
the parameter @code{#:jar-name} can be used to generate a minimal Ant
build file @file{build.xml} with tasks to build the specified jar
archive.

The parameter @code{#:build-target} can be used to specify the Ant task
that should be run during the @code{build} phase.  By default the
``jar'' task will be run.

@end defvr

@defvr {Scheme Variable} cmake-build-system
This variable is exported by @code{(guix build-system cmake)}.  It
implements the build procedure for packages using the

A guix/build-system/ant.scm => guix/build-system/ant.scm +149 -0
@@ 0,0 1,149 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2016 Ricardo Wurmus <rekado@elephly.net>
;;;
;;; 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 <http://www.gnu.org/licenses/>.

(define-module (guix build-system ant)
  #:use-module (guix store)
  #:use-module (guix utils)
  #:use-module (guix packages)
  #:use-module (guix derivations)
  #:use-module (guix search-paths)
  #:use-module (guix build-system)
  #:use-module (guix build-system gnu)
  #:use-module (ice-9 match)
  #:use-module (srfi srfi-26)
  #:export (%ant-build-system-modules
            ant-build
            ant-build-system))

;; Commentary:
;;
;; Standard build procedure for Java packages using Ant.
;;
;; Code:

(define %ant-build-system-modules
  ;; Build-side modules imported by default.
  `((guix build ant-build-system)
    (guix build syscalls)
    ,@%gnu-build-system-modules))

(define (default-jdk)
  "Return the default JDK package."
  ;; Lazily resolve the binding to avoid a circular dependency.
  (let ((jdk-mod (resolve-interface '(gnu packages java))))
    (module-ref jdk-mod 'icedtea)))

(define (default-ant)
  "Return the default Ant package."
  ;; Lazily resolve the binding to avoid a circular dependency.
  (let ((jdk-mod (resolve-interface '(gnu packages java))))
    (module-ref jdk-mod 'ant)))

(define* (lower name
                #:key source inputs native-inputs outputs system target
                (jdk (default-jdk))
                (ant (default-ant))
                #:allow-other-keys
                #:rest arguments)
  "Return a bag for NAME."
  (define private-keywords
    '(#:source #:target #:jdk #:ant #:inputs #:native-inputs))

  (and (not target)                               ;XXX: no cross-compilation
       (bag
         (name name)
         (system system)
         (host-inputs `(,@(if source
                              `(("source" ,source))
                              '())
                        ,@inputs

                        ;; Keep the standard inputs of 'gnu-build-system'.
                        ,@(standard-packages)))
         (build-inputs `(("jdk" ,jdk "jdk")
                         ("ant" ,ant)
                         ,@native-inputs))
         (outputs outputs)
         (build ant-build)
         (arguments (strip-keyword-arguments private-keywords arguments)))))

(define* (ant-build store name inputs
                    #:key
                    (tests? #t)
                    (test-target "tests")
                    (configure-flags ''())
                    (make-flags ''())
                    (build-target "jar")
                    (jar-name #f)
                    (phases '(@ (guix build ant-build-system)
                                %standard-phases))
                    (outputs '("out"))
                    (search-paths '())
                    (system (%current-system))
                    (guile #f)p
                    (imported-modules %ant-build-system-modules)
                    (modules '((guix build ant-build-system)
                               (guix build utils))))
  "Build SOURCE with INPUTS."
  (define builder
    `(begin
       (use-modules ,@modules)
       (ant-build #:name ,name
                  #:source ,(match (assoc-ref inputs "source")
                              (((? derivation? source))
                               (derivation->output-path source))
                              ((source)
                               source)
                              (source
                               source))
                  #:make-flags ,make-flags
                  #:configure-flags ,configure-flags
                  #:system ,system
                  #:tests? ,tests?
                  #:test-target ,test-target
                  #:build-target ,build-target
                  #:jar-name ,jar-name
                  #:phases ,phases
                  #:outputs %outputs
                  #:search-paths ',(map search-path-specification->sexp
                                        search-paths)
                  #:inputs %build-inputs)))

  (define guile-for-build
    (match guile
      ((? package?)
       (package-derivation store guile system #:graft? #f))
      (#f                               ; the default
       (let* ((distro (resolve-interface '(gnu packages commencement)))
              (guile  (module-ref distro 'guile-final)))
         (package-derivation store guile system #:graft? #f)))))

  (build-expression->derivation store name builder
                                #:inputs inputs
                                #:system system
                                #:modules imported-modules
                                #:outputs outputs
                                #:guile-for-build guile-for-build))

(define ant-build-system
  (build-system
    (name 'ant)
    (description "The standard Ant build system")
    (lower lower)))

;;; ant.scm ends here

A guix/build/ant-build-system.scm => guix/build/ant-build-system.scm +160 -0
@@ 0,0 1,160 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2016 Ricardo Wurmus <rekado@elephly.net>
;;;
;;; 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 <http://www.gnu.org/licenses/>.

(define-module (guix build ant-build-system)
  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
  #:use-module (guix build syscalls)
  #:use-module (guix build utils)
  #:use-module (sxml simple)
  #:use-module (ice-9 match)
  #:use-module (ice-9 ftw)
  #:use-module (srfi srfi-1)
  #:use-module (srfi srfi-26)
  #:export (%standard-phases
            ant-build))

;; Commentary:
;;
;; Builder-side code of the standard build procedure for Java packages using
;; Ant.
;;
;; Code:

(define (default-build.xml jar-name prefix)
  "Create a simple build.xml with standard targets for Ant."
  (call-with-output-file "build.xml"
    (lambda (port)
      (sxml->xml
       `(project (@ (basedir "."))
                 (property (@ (name "classes.dir")
                              (value "${basedir}/build/classes")))
                 (property (@ (name "jar.dir")
                              (value "${basedir}/build/jar")))
                 (property (@ (name "dist.dir")
                              (value ,prefix)))

                 ;; respect the CLASSPATH environment variable
                 (property (@ (name "build.sysclasspath")
                              (value "first")))
                 (property (@ (environment "env")))
                 (path (@ (id "classpath"))
                       (pathelement (@ (location "${env.CLASSPATH}"))))

                 (target (@ (name "compile"))
                         (mkdir (@ (dir "${classes.dir}")))
                         (javac (@ (includeantruntime "false")
                                   (srcdir "src")
                                   (destdir "${classes.dir}")
                                   (classpath (@ (refid "classpath"))))))

                 (target (@ (name "jar")
                            (depends "compile"))
                         (mkdir (@ (dir "${jar.dir}")))
                         ;; We cannot use the simpler "jar" task here, because
                         ;; there is no way to disable generation of a
                         ;; manifest.  We do not include a generated manifest
                         ;; to ensure determinism, because we cannot easily
                         ;; reset the ctime/mtime before creating the archive.
                         (exec (@ (executable "jar"))
                               (arg (@ (line ,(string-append "-Mcf ${jar.dir}/" jar-name
                                                             " -C ${classes.dir} ."))))))

                 (target (@ (name "install"))
                         (copy (@ (todir "${dist.dir}"))
                               (fileset (@ (dir "${jar.dir}"))
                                        (include (@ (name "**/*.jar")))))))
       port)))
  (utime "build.xml" 0 0)
  #t)

(define (generate-classpath inputs)
  "Return a colon-separated string of full paths to jar files found among the
INPUTS."
  (string-join
   (apply append (map (match-lambda
                        ((_ . dir)
                         (find-files dir "\\.*jar$")))
                      inputs)) ":"))

(define* (configure #:key inputs outputs (jar-name #f)
                    #:allow-other-keys)
  (when jar-name
    (default-build.xml jar-name
                       (string-append (assoc-ref outputs "out")
                                      "/share/java")))
  (setenv "JAVA_HOME" (assoc-ref inputs "jdk"))
  (setenv "CLASSPATH" (generate-classpath inputs)))

(define* (build #:key (make-flags '()) (build-target "jar")
                #:allow-other-keys)
  (zero? (apply system* `("ant" ,build-target ,@make-flags))))

(define* (strip-jar-timestamps #:key outputs
                 #:allow-other-keys)
  "Unpack all jar archives, reset the timestamp of all contained files, and
repack them.  This is necessary to ensure that archives are reproducible."
  (define (repack-archive jar)
    (format #t "repacking ~a\n" jar)
    (let ((dir (mkdtemp! "jar-contents.XXXXXX")))
      (and (with-directory-excursion dir
             (zero? (system* "jar" "xf" jar)))
           ;; The manifest file contains timestamps
           (for-each delete-file (find-files dir "MANIFEST.MF"))
           (delete-file jar)
           ;; XXX: copied from (gnu build install)
           (for-each (lambda (file)
                       (let ((s (lstat file)))
                         (unless (eq? (stat:type s) 'symlink)
                           (utime file 0 0 0 0))))
                     (find-files dir #:directories? #t))
           (unless (zero? (system* "jar" "-Mcf" jar "-C" dir "."))
             (error "'jar' failed"))
           (utime jar 0 0)
           #t)))

  (every (match-lambda
           ((output . directory)
            (every repack-archive (find-files directory "\\.jar$"))))
         outputs))

(define* (check #:key target (make-flags '()) (tests? (not target))
                (test-target "check")
                #:allow-other-keys)
  (if tests?
      (zero? (apply system* `("ant" ,test-target ,@make-flags)))
      (begin
        (format #t "test suite not run~%")
        #t)))

(define* (install #:key (make-flags '()) #:allow-other-keys)
  (zero? (apply system* `("ant" "install" ,@make-flags))))

(define %standard-phases
  (modify-phases gnu:%standard-phases
    (replace 'configure configure)
    (replace 'build build)
    (replace 'check check)
    (replace 'install install)
    (add-after 'install 'strip-jar-timestamps strip-jar-timestamps)))

(define* (ant-build #:key inputs (phases %standard-phases)
                    #:allow-other-keys #:rest args)
  "Build the given Java package, applying all of PHASES in order."
  (apply gnu:gnu-build #:inputs inputs #:phases phases args))

;;; ant-build-system.scm ends here