ASDF system definition files for Fortran 77 codes

One of the Common Lisp packages that I find very useful is f2cl, originally written by Kevin A. Broughan and Diane M. K. Willcock [1], with recent contributions by Richard J. Fateman and Raymond Toy [2]. It can convert a lot of the Fortran 77 codes out there fairly reliably into quite fast Common Lisp code. The lack of a fancy home page or even a separate project (it is currently part of CLOCC) makes it somewhat hard to find, but should not be taken as a sign of abandon. A more prominent project that uses f2cl is the open source CAS system Maxima.

The advantages of using f2cl over a foreign function interface are, among other things, that the generated Common Lisp code has far better error handling, and is much more convenient to use (for a Common Lisp programmer, at least).

I think it would be nice to have ASDF system definitions for the Fortran 77 packages bundled with f2cl. This would complement the mk:defsystem definitions already available. A small difficulty is that the f2cl compiler has a lot of options, and it is desirable to want to set them globally, eventually overriding them on a file by file basis. At least, this is what is done in some of the .system files. I managed to convince ASDF to do this, but I am not sure if the way i did it is the best solution. From the point of view of OOP this can be (and will be) improved, of course. I’m referring more to the need of things like accessing ASDF symbols that are not exported. In any case, having global options that can be overriden on a component basis looks like a feature one would like to have every now and then.

A typical f2cl .system file looks like this (for example):

(mk:define-language :f2cl
    :compiler #'f2cl:f2cl-compile
    :source-extension "f")

(mk:defsystem minpack
    :source-pathname "clocc:src;f2cl;packages;minpack"
    :components
    ((:file "minpack"
		      :language :lisp)
     (:module "minpack"
	      :source-pathname ""
	      :source-extension "f"
	      :package :minpack
	      :language :f2cl
	      :compiler-options (:include-comments t
				 :keep-lisp-file t
				 :relaxed-array-decls nil
				 :array-type :array
				 :array-slicing t
				 :package :minpack)
;; etc

Note that :file components can also have a :compiler-options, although I don’t know how the overriding behavior really is.

To convince ASDF to behave in a similar way, I subclassed the asdf:module class, adding an f2cl-options slot.

(defclass f2cl-module (module)
  ((f2cl-options :initform nil
		 :initarg :f2cl-options
		 :accessor f2cl-options)))

To have an f2cl source file type with corresponding compilation, one does

(defclass f77-source-file (cl-source-file)
  ((f2cl-options :initform nil
		 :initarg :f2cl-options)))

(defmethod source-file-type ((c f77-source-file) (s module)) "f")

(defmethod perform ((o compile-op) (f f77-source-file))
  (apply #'f2cl:f2cl-compile
	 (cons (make-pathname :name (component-name f)
			      :type "f"
			      :defaults (component-pathname f))
	       (compiler-options f))))

But here is the catch. Compiler options have to be computed from the module *and* the file. I did it like this

(defmethod f2cl-options ((c f77-source-file))
  (let* ((c-c-o (slot-value c 'f2cl-options))
	 (p-c-o (when (typep (parent c) 'f2cl-module)
		  (f2cl-options (parent c)))))

    ;; override global options.
    (append c-c-o p-c-o)))

where

(defmethod parent ((c f77-source-file))
  (slot-value c 'asdf::parent)) ;; Oops

Anyway, it works. Now I am wondering if I overlooked the apropriate feature in ASDF, or another way of doing this. Accessing ‘asdf::parent is good enough for me, but before attempting to contribute .asd files to f2cl, I would prefer to have a more solid solution.

P.S: The rest of the .asd file looks like this

(defsystem minpack
  :components
  ((:f2cl-module :minpack
	    :f2cl-options (:include-comments t
			       :keep-lisp-file t
			       :relaxed-array-decls nil
			       :array-type :array
			       :array-slicing t
			       :package :minpack)
	    :components
	    ((:file "minpack")
	     (:f77-source-file "dpmpar" :depends-on ("minpack"))
	     (:f77-source-file "enorm" :depends-on ("minpack"))
	     (:f77-source-file "fdjac1" :depends-on ("dpmpar"))
	     (:f77-source-file "fdjac2" :depends-on ("dpmpar"))
	     (:f77-source-file "qrsolv" :depends-on ("minpack"))
	     (:f77-source-file "lmpar" :depends-on ("dpmpar" "enorm" "qrsolv"))
	     (:f77-source-file "qrfac" :depends-on ("dpmpar" "enorm"))
	     (:f77-source-file "lmdif" :depends-on ("dpmpar" "enorm" "fdjac2" "lmpar" "qrfac"))
	     (:f77-source-file "lmdif1" :depends-on ("lmdif"))
	     (:f77-source-file "lmder" :depends-on ("dpmpar" "enorm" "lmpar" "qrfac"))
	     (:f77-source-file "lmder1" :depends-on ("lmder"))
	     (:f77-source-file "dogleg" :depends-on ("dpmpar" "enorm"))
	     (:f77-source-file "qform" :depends-on ("minpack"))
	     (:f77-source-file "r1mpyq" :depends-on ("minpack"))
	     (:f77-source-file "r1updt" :depends-on ("dpmpar"))
	     (:f77-source-file "hybrd" :depends-on ("dogleg" "dpmpar" "enorm" "fdjac1"
						  "qform" "qrfac" "r1mpyq" "r1updt"))
	     (:f77-source-file "hybrd1" :depends-on ("hybrd"))
	     (:f77-source-file "hybrj" :depends-on ("dogleg" "dpmpar" "enorm" "qform" "qrfac"
						  "r1mpyq" "r1updt"))
	     (:f77-source-file "hybrj1" :depends-on ("hybrj"))
	     ))))

Footnotes

[1] K. A. Broughan and D. M. K. Willcock, Fortran to Lisp translation using f2cl, Software Practice & Experience, 26(10) pp. 1127 – 1139 (October 1996)

[2] R. J. Fateman and R. Toy, Converting call-by-reference to call-by-value: Fortran and Lisp coexisting, Proceedings of the 2003 international symposium on Symbolic and algebraic computation, pp. 95 – 102, 2003.

Note: If you want to comment, please take into account that the wordpress comment box is not friendly to code.

Advertisements
  1. #1 by Richard Kreuter on May 6, 2007 - 11:46 pm

    asdf exports a reader function for the ASDF::PARENT slot, COMPONENT-PARENT. Does that not do the trick?

    Also, an asdf module class can specify a default class for its components, which might be handy in this case. Add a slot declaration to the defclass for f2cl-module that goes like this

    …(default-component-class :initform ‘f2cl-source-file)

    and then you can declare the Fortran components in a f2cl-module instance merely using :file, rather than :f2cl-source-file (you will have to declare CL source files as cl-source-file instances, however).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: