From 5f7a1a4def8494940a4a2bc3728fb9cd927a14f8 Mon Sep 17 00:00:00 2001 From: Ricardo Wurmus Date: Tue, 29 Dec 2015 16:56:49 +0100 Subject: [PATCH] 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. --- Makefile.am | 2 + doc/guix.texi | 21 +++++ guix/build-system/ant.scm | 149 +++++++++++++++++++++++++++++ guix/build/ant-build-system.scm | 160 ++++++++++++++++++++++++++++++++ 4 files changed, 332 insertions(+) create mode 100644 guix/build-system/ant.scm create mode 100644 guix/build/ant-build-system.scm diff --git a/Makefile.am b/Makefile.am index f67de43f48..92a3bc5f82 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ diff --git a/doc/guix.texi b/doc/guix.texi index f7deafa516..7509ea9dc2 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -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 diff --git a/guix/build-system/ant.scm b/guix/build-system/ant.scm new file mode 100644 index 0000000000..d3054e5ffa --- /dev/null +++ b/guix/build-system/ant.scm @@ -0,0 +1,149 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2016 Ricardo Wurmus +;;; +;;; 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-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 diff --git a/guix/build/ant-build-system.scm b/guix/build/ant-build-system.scm new file mode 100644 index 0000000000..d302b948b5 --- /dev/null +++ b/guix/build/ant-build-system.scm @@ -0,0 +1,160 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2016 Ricardo Wurmus +;;; +;;; 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 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