mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2025-12-15 15:21:03 -08:00
157 lines
6 KiB
Common Lisp
157 lines
6 KiB
Common Lisp
;;;; -*- Mode: Lisp; Syntax: Common-Lisp; indent-tabs-mode: nil; Package: C -*-
|
|
;;;; vim: set filetype=lisp tabstop=8 shiftwidth=2 expandtab:
|
|
|
|
;;;;
|
|
;;;; Copyright (c) 2010, Juan Jose Garcia-Ripoll
|
|
;;;;
|
|
;;;; See file 'LICENSE' for the copyright details.
|
|
|
|
;;;; CMPFEATURES.LSP -- Gather a list of features from the compiler
|
|
|
|
(in-package "COMPILER")
|
|
|
|
(defun run-and-collect (command args &optional file)
|
|
(handler-case
|
|
(let ((output-stream (si:run-program-inner command args :default t))
|
|
lines)
|
|
#+msvc
|
|
(si::stream-external-format-set
|
|
output-stream
|
|
(list (si::windows-codepage-encoding) :crlf))
|
|
(setf lines (collect-lines output-stream))
|
|
(cond ((null file)
|
|
lines)
|
|
((probe-file file)
|
|
(with-open-file (s file :direction :input)
|
|
(collect-lines s)))
|
|
(t
|
|
(warn "Unable to find file ~A" file))))
|
|
(error (c)
|
|
(format t "~&;;; Unable to execute program ~S~&;;; Condition~&;;; ~A"
|
|
command c))))
|
|
|
|
(defun split-words (string)
|
|
(loop with output = '()
|
|
with word = '()
|
|
for i from 0 below (length string)
|
|
for c = (elt string i)
|
|
do (if (member c '(#\Space #\Tab #\Newline))
|
|
(when word
|
|
(push (make-array (length word) :element-type 'base-char
|
|
:initial-contents (nreverse word))
|
|
output)
|
|
(setf word nil))
|
|
(push c word))
|
|
finally (return (push (make-array (length word) :element-type 'base-char
|
|
:initial-contents (nreverse word))
|
|
output))))
|
|
|
|
(defconstant +known-keywords+
|
|
'("sparc*" "x86*" "*-bit" "32*" "64*" "*32" "*64"
|
|
"elf" "coff" "mach-o"
|
|
"universal"
|
|
"gcc" "icc"))
|
|
|
|
(defun known-keyword (string &optional (patterns +known-keywords+))
|
|
(loop with base = (make-pathname :directory nil :name (string-upcase string))
|
|
for p in patterns
|
|
for pattern-path = (make-pathname :directory nil :name (string-upcase p))
|
|
thereis (pathname-match-p base pattern-path)))
|
|
|
|
(defun gather-keywords (strings patterns)
|
|
(declare (ignore patterns))
|
|
(let ((strings (reduce #'append (mapcar #'split-words strings))))
|
|
(mapcar (lambda (s)
|
|
(intern (string-upcase s) (find-package :keyword)))
|
|
(remove-if-not #'known-keyword strings))))
|
|
|
|
(defun compiler-defines (macros)
|
|
"Test for existence of a set of C preprocessor macros for the compiler flags
|
|
we are currently using with ECL."
|
|
(let* ((f (ext:mkstemp "tmp:foo"))
|
|
(fc (make-pathname :type "c" :defaults f))
|
|
(fs (make-pathname :type "i" :defaults f)))
|
|
(with-open-file (s fc :direction :output :if-exists :overwrite
|
|
:if-does-not-exist :create)
|
|
(loop for i from 0
|
|
for (macro . rest) in macros
|
|
do (format s "~%#ifdef ~A~%ECLVALUE ~4,'0D ~A~%#endif"
|
|
macro i macro)))
|
|
(loop with list = (mapcar #'list (mapcar #'first macros))
|
|
with lines = (run-and-collect c::*cc*
|
|
(append (c::split-program-options c::*cc-flags*)
|
|
#+msvc
|
|
(list "-P" (namestring fc)
|
|
"-Fi" (namestring fs))
|
|
#-msvc
|
|
(list "-E" (namestring fc)
|
|
"-o" (namestring fs)))
|
|
fs)
|
|
for l in lines
|
|
when (eql (search "ECLVALUE" l) 0)
|
|
do (let* ((number (parse-integer (subseq l 9 13)))
|
|
(defines (subseq l 14)))
|
|
(setf (elt list number)
|
|
(elt macros number)))
|
|
finally (progn
|
|
;;(and (probe-file f) (delete-file f))
|
|
;;(and (probe-file fc) (delete-file fc))
|
|
;;(and (probe-file fs) (delete-file fs))
|
|
(return list)))))
|
|
|
|
(defconstant +compiler-macros+
|
|
'(;; Compiler names
|
|
("__INTEL_COMPILER" :intel-compiler)
|
|
("__GNUC__" :gcc-compiler)
|
|
("__SUNPRO_CC" :sun-c++-compiler)
|
|
("__SUNPRO_C" :sun-c-compiler)
|
|
("__xlc__" :ibm-c-compiler)
|
|
("__xlC__" :ibm-c++-compiler)
|
|
("_MSC_VER" :msvc-compiler)
|
|
|
|
;; Processor features
|
|
("__MMX__" :mmx)
|
|
("__SSE__" :sse)
|
|
("__SSE2__" :sse2)
|
|
("__ELF__" :elf)
|
|
("__i386" :i386)
|
|
("__i386__" :i386)
|
|
("__amd64" :amd64)
|
|
("__x86_64__" :x86-64)
|
|
("__X86_64__" :x86-64)
|
|
("_WIN64" :x86-64)
|
|
("__LP64__" :lp64)
|
|
("_LP64" :lp64)
|
|
("__ILP32__" :ilp32)
|
|
("_ILP32" :ilp32)
|
|
("__powerpc" :powerpc)
|
|
("__PPC" :ppc)
|
|
("__PPC__" :ppc)
|
|
("__PPC64__" :ppc64)
|
|
("_PPC64_" :ppc64)
|
|
))
|
|
|
|
(defun run-and-collect-keywords (&rest args)
|
|
(gather-keywords (apply #'run-and-collect args) +known-keywords+))
|
|
|
|
(defun gather-system-features (&key (executable
|
|
#+(or windows cygwin mingw32) "sys:ecl_min.exe"
|
|
#-(or windows cygwin mingw32) "sys:ecl_min"))
|
|
(let* ((ecl-binary (namestring (truename executable)))
|
|
(executable-features
|
|
#-windows
|
|
(run-and-collect-keywords "file" (list ecl-binary)))
|
|
(compiler-version (run-and-collect-keywords c::*cc*
|
|
(if (search "xlc" c::*cc*)
|
|
'("-qversion")
|
|
'("--version"))))
|
|
(compiler-features (reduce #'append
|
|
(mapcar #'rest
|
|
(compiler-defines +compiler-macros+)))))
|
|
(delete-duplicates (nconc executable-features
|
|
compiler-version
|
|
compiler-features)
|
|
:test #'string-equal)))
|
|
|
|
(defun update-compiler-features (&rest args)
|
|
(setf *compiler-features* (apply #'gather-system-features args)))
|