[Ecls-list] Cross compiling with asdf
Sylvain Ageneau
ageneau at gmail.com
Fri Apr 8 22:19:31 UTC 2011
Hello,
As part of the android port, I wanted to add some existing external
libraries to the cross-compiled ecl. I needed to add them as static
libraries directly linked in with ECL.
My cross compiled ecl doesn't have a compiler or asdf. I looked at the
build-modules function from the "compile.lsp" file which almost did what
I needed except it doesn't allow compiling directly from an asdf system
definition which would be much easier.
I first tried to add a new "cross-compile-op" operation to asdf but I
ran into the problem that the c::builder function insists on creating
and loading fasl files which is a problem because in this case it's
trying to load arm code into a x86 ecl.
I ended up with a solution that works well but is not very elegant.
Still mentioning it in case someone wants to add this functionality
properly (see attached script):
The basic idea is to modify compiler::builder and asdf::compile-file* in
such a way that they create both object files for the host and for the
target platform. FASL are still created and loaded but only for the
host. The resulting cross-compiled library is just a by-product of the
build.
Usage:
(load "cross_compile")
(asdf:make-build :ironclad
:type :static-library
:move-here t
:prologue-code '(provide :ironclad))
Sylvain
-------------- next part --------------
(require 'asdf)
;; (setq *asdf-verbose* t)
;; (setf *load-verbose* t)
;; (setf *compile-verbose* t)
(ext:package-lock "COMMON-LISP" nil)
(ext:package-lock "C" nil)
;; (trace c::builder)
;; (trace c::compile)
;; (trace c::compile-file)
;; (trace c::build-fasl)
(push :cross *features*)
(defpackage :util
(:use :cl)
(:export
:join))
(in-package :util)
(defun join (seq sep)
"Concatenate the strings in `seq' delimited by the separator `sep'."
(format nil (concatenate 'string "~{~a~^" sep "~}") seq))
(in-package "COMPILER")
(defmacro with-android-env (body)
`(let* ((sdk "/opt/android/android-ndk-r5")
(sdk-ver "android-9")
(toolchain (format nil "~a/toolchains/~a" "/opt/android/android-ndk-r5" "arm-linux-androideabi-4.4.3/prebuilt/linux-x86"))
(sysroot (format nil "~a/platforms/~a" "/opt/android/android-ndk-r5" sdk-ver))
(compiler::*ecl-include-directory* "/opt/ecl/android/include/")
(compiler::*ecl-library-directory* "/opt/ecl/android/lib/")
(compiler::*cc* (format nil "~a/bin/arm-linux-androideabi-gcc" toolchain))
(compiler::*ld* (format nil "~a/bin/arm-linux-androideabi-gcc" toolchain))
(compiler::*ar* (format nil "~a/bin/arm-linux-androideabi-ar" toolchain))
(compiler::*ranlib* (format nil "~a/bin/arm-linux-androideabi-ranlib" toolchain))
(compiler::*cc-flags* (util:join (list "-g"
(format nil "--sysroot=~a" sysroot)
"-DANDROID -DPLATFORM_ANDROID"
"-O2 -fPIC -fno-common -D_THREAD_SAFE"
"-I/opt/android/android-ndk-r5/platforms/android-9/arch-arm/usr/include"
"-I/opt/gmp/android/include")
" "))
(compiler::*ld-flags* (util:join (list "-g"
(format nil "--sysroot=~a" sysroot))
" ")))
(, at body)))
(setf (symbol-function 'builder-orig) (symbol-function 'builder))
(defun builder (target output-name &rest args &key lisp-files &allow-other-keys)
(case target
((:library :static-library :lib)
(let ((lisp-files-cross (mapcar #'(lambda (x) (merge-pathnames (format nil "~a-cross" (pathname-name x)) x)) lisp-files))
(output-name-cross (merge-pathnames (format nil "~a-cross" (pathname-name output-name)) output-name)))
(with-android-env
(apply #'builder-orig target output-name :lisp-files lisp-files-cross args))
(rename-file output-name output-name-cross))
(apply #'builder-orig target output-name :lisp-files lisp-files args))
(otherwise
(apply #'builder-orig target output-name args))))
(in-package :asdf)
(require 'cmp)
(defun* compile-file* (input-file &rest keys &key output-file &allow-other-keys)
(let* ((output-file (or output-file (apply 'compile-file-pathname* input-file keys)))
(output-file-cross (merge-pathnames (format nil "~a-cross" (pathname-name output-file)) output-file))
(tmp-file (tmpize-pathname output-file))
(tmp-file-cross (tmpize-pathname output-file-cross))
(status :error))
(multiple-value-bind (output-truename warnings-p failure-p)
(compiler::with-android-env
(apply 'compiler::compile-file input-file :output-file tmp-file-cross :c-file t keys))
(cond
(failure-p
(setf status *compile-file-failure-behaviour*))
(warnings-p
(setf status *compile-file-warnings-behaviour*))
(t
(setf status :success)))
(ecase status
((:success :warn :ignore)
(delete-file-if-exists output-file-cross)
(when output-truename
(rename-file output-truename output-file-cross)
(setf output-truename output-file-cross)))
(:error
(delete-file-if-exists output-truename)
(setf output-truename nil)))
(values output-truename warnings-p failure-p))
(multiple-value-bind (output-truename warnings-p failure-p)
(apply 'compiler::compile-file input-file :output-file tmp-file :c-file t keys)
(cond
(failure-p
(setf status *compile-file-failure-behaviour*))
(warnings-p
(setf status *compile-file-warnings-behaviour*))
(t
(setf status :success)))
(ecase status
((:success :warn :ignore)
(delete-file-if-exists output-file)
(when output-truename
(rename-file output-truename output-file)
(setf output-truename output-file)))
(:error
(delete-file-if-exists output-truename)
(setf output-truename nil)))
(values output-truename warnings-p failure-p))))
More information about the ecl-devel
mailing list