guix-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Add ant-build-system.


From: Ricardo Wurmus
Subject: [PATCH] Add ant-build-system.
Date: Wed, 6 Jan 2016 12:38:09 +0100

Hi Guix,

this patch adds a new build system for Java projects: the
“ant-build-system”.

I’ve used it successfully to package the Java projects hamcrest-core,
junit, osgi-annotation, osgi-core, log4j-api, and javax-mail.

It’s especially useful in cases where a project does *not* use Ant and
would otherwise require building with Maven or recursively calling javac
on all source files (as currently done for swt), because it can generate
a simple Ant build file with all the right targets.  This cuts a lot of
boilerplate from Java packages.

The build.xml it generates contains a target “touch” which is run before
wrapping up the compiled .class files in a jar archive; this target
ensures that the timestamps of all archived files are reset, so the
produced jars can be (and in case of the above-mentioned packages)
deterministic.

Of course the build.xml is generated using sxml.

I’m in no hurry to get this merged (it just isn’t very important to me
at this pont where I’m still trying to figure out how to best deal with
Java libraries) and I welcome comments, bike shedding, and alternative
solutions.

~~ Ricardo

>From 284f79ae6ba584603e58228c7c9ee73ac135912d Mon Sep 17 00:00:00 2001
From: Ricardo Wurmus <address@hidden>
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       | 148 ++++++++++++++++++++++++++++++++++++++++
 guix/build/ant-build-system.scm | 136 ++++++++++++++++++++++++++++++++++++
 4 files changed, 307 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 760caed..145ac5f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -53,6 +53,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            \
@@ -72,6 +73,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 33debe6..327f512 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -2593,6 +2593,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.
 
address@hidden {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
address@hidden://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.
+
address@hidden 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 0000000..5240ff6
--- /dev/null
+++ b/guix/build-system/ant.scm
@@ -0,0 +1,148 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2016 Ricardo Wurmus <address@hidden>
+;;;
+;;; 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)
+    ,@%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 #: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 0000000..9a7f886
--- /dev/null
+++ b/guix/build/ant-build-system.scm
@@ -0,0 +1,136 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2016 Ricardo Wurmus <address@hidden>
+;;;
+;;; 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 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."
+  (let ((file (open-output-file "build.xml")))
+    (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"))))))
+
+               ;; Reset the ctime/mtime on all files to ensure that the
+               ;; jar archive for the same class files is bit-identical.
+               (target (@ (name "touch"))
+                       (exec (@ (executable "find"))
+                             (arg (@ (line "${classes.dir} -exec touch -d @0 
{} ;")))))
+
+               (target (@ (name "jar")
+                          (depends "compile,touch"))
+                       (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")))))))
+     file)
+    (close-output-port file)
+    (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* (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)))
+
+(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
-- 
2.1.0


reply via email to

[Prev in Thread] Current Thread [Next in Thread]