2021-02-12 16:08:01 -05:00
|
|
|
;;; ede/proj-comp.el --- EDE Generic Project compiler/rule driver -*- lexical-binding: t; -*-
|
2009-09-20 15:06:05 +00:00
|
|
|
|
2022-01-01 02:45:51 -05:00
|
|
|
;; Copyright (C) 1999-2001, 2004-2005, 2007, 2009-2022 Free Software
|
2013-01-01 09:11:05 +00:00
|
|
|
;; Foundation, Inc.
|
2009-09-20 15:06:05 +00:00
|
|
|
|
|
|
|
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
|
|
|
;; Keywords: project, make
|
|
|
|
|
|
|
|
;; This file is part of GNU Emacs.
|
|
|
|
|
|
|
|
;; GNU Emacs 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 Emacs 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
|
2017-09-13 15:52:52 -07:00
|
|
|
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
2009-09-20 15:06:05 +00:00
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
;;
|
|
|
|
;; This software handles the maintenance of compiler and rule definitions
|
|
|
|
;; for different object types.
|
|
|
|
;;
|
|
|
|
;; The `ede-compiler' class lets different types of project objects create
|
|
|
|
;; definitions of compilers that can be swapped in and out for compiling
|
|
|
|
;; source code. Users can also define new compiler types whenever they
|
|
|
|
;; some customized behavior.
|
|
|
|
;;
|
2009-10-01 04:10:10 +00:00
|
|
|
;; The `ede-makefile-rule' class lets users add customized rules into their
|
2009-09-20 15:06:05 +00:00
|
|
|
;; objects, and also lets different compilers add chaining rules to their
|
|
|
|
;; behaviors.
|
|
|
|
;;
|
|
|
|
;; It is important that all new compiler types be registered once. That
|
|
|
|
;; way the chaining rules and variables are inserted into any given Makefile
|
|
|
|
;; only once.
|
|
|
|
;;
|
|
|
|
;; To insert many compiler elements, wrap them in `ede-compiler-begin-unique'
|
|
|
|
;; before calling their insert methods.
|
|
|
|
;; To write a method that inserts a variable or rule for a compiler
|
|
|
|
;; based object, wrap the body of your call in `ede-compiler-only-once'
|
|
|
|
|
|
|
|
(require 'ede) ;source object
|
|
|
|
(require 'ede/autoconf-edit)
|
|
|
|
|
|
|
|
;;; Types:
|
|
|
|
(defclass ede-compilation-program (eieio-instance-inheritor)
|
|
|
|
((name :initarg :name
|
|
|
|
:type string
|
|
|
|
:custom string
|
|
|
|
:documentation "Name of this type of compiler.")
|
|
|
|
(variables :initarg :variables
|
|
|
|
:type list
|
|
|
|
:custom (repeat (cons (string :tag "Variable")
|
|
|
|
(string :tag "Value")))
|
|
|
|
:documentation
|
|
|
|
"Variables needed in the Makefile for this compiler.
|
|
|
|
An assoc list where each element is (VARNAME . VALUE) where VARNAME
|
|
|
|
is a string, and VALUE is either a string, or a list of strings.
|
|
|
|
For example, GCC would define CC=gcc, and emacs would define EMACS=emacs.")
|
|
|
|
(sourcetype :initarg :sourcetype
|
|
|
|
:type list ;; of symbols
|
|
|
|
:documentation
|
|
|
|
"A list of `ede-sourcecode' objects this class will handle.
|
|
|
|
This is used to match target objects with the compilers and linkers
|
|
|
|
they can use, and which files this object is interested in."
|
|
|
|
:accessor ede-object-sourcecode)
|
|
|
|
(rules :initarg :rules
|
|
|
|
:initform nil
|
|
|
|
:type list
|
|
|
|
:custom (repeat (object :objecttype ede-makefile-rule))
|
|
|
|
:documentation
|
|
|
|
"Auxiliary rules needed for this compiler to run.
|
|
|
|
For example, yacc/lex files need additional chain rules, or inferences.")
|
|
|
|
(commands :initarg :commands
|
|
|
|
:type list
|
|
|
|
:custom (repeat string)
|
|
|
|
:documentation
|
|
|
|
"The commands used to execute this compiler.
|
|
|
|
The object which uses this compiler will place these commands after
|
2011-11-03 21:03:45 +01:00
|
|
|
its rule definition.")
|
2009-09-20 15:06:05 +00:00
|
|
|
(autoconf :initarg :autoconf
|
|
|
|
:initform nil
|
|
|
|
:type list
|
|
|
|
:custom (repeat string)
|
|
|
|
:documentation
|
|
|
|
"Autoconf function to call if this type of compiler is used.
|
|
|
|
When a project is in Automake mode, this defines the autoconf function to
|
|
|
|
call to initialize automake to use this compiler.
|
|
|
|
For example, there may be multiple C compilers, but they all probably
|
|
|
|
use the same autoconf form.")
|
|
|
|
(objectextention :initarg :objectextention
|
|
|
|
:type string
|
|
|
|
:documentation
|
2011-11-20 04:48:53 +01:00
|
|
|
"A string which is the extension used for object files.
|
|
|
|
For example, C code uses .o on Unix, and Emacs Lisp uses .elc.")
|
2009-09-20 15:06:05 +00:00
|
|
|
)
|
|
|
|
"A program used to compile or link a program via a Makefile.
|
|
|
|
Contains everything needed to output code into a Makefile, or autoconf
|
|
|
|
file.")
|
|
|
|
|
|
|
|
(defclass ede-compiler (ede-compilation-program)
|
|
|
|
((makedepends :initarg :makedepends
|
|
|
|
:initform nil
|
|
|
|
:type boolean
|
|
|
|
:documentation
|
|
|
|
"Non-nil if this compiler can make dependencies.")
|
|
|
|
(uselinker :initarg :uselinker
|
|
|
|
:initform nil
|
|
|
|
:type boolean
|
|
|
|
:documentation
|
|
|
|
"Non-nil if this compiler creates code that can be linked.
|
|
|
|
This requires that the containing target also define a list of available
|
|
|
|
linkers that can be used.")
|
|
|
|
)
|
|
|
|
"Definition for a compiler.
|
|
|
|
Different types of objects will provide different compilers for
|
|
|
|
different situations.")
|
|
|
|
|
|
|
|
(defclass ede-linker (ede-compilation-program)
|
|
|
|
()
|
|
|
|
"Contains information needed to link many generated object files together.")
|
|
|
|
|
|
|
|
(defclass ede-makefile-rule ()
|
|
|
|
((target :initarg :target
|
|
|
|
:initform ""
|
|
|
|
:type string
|
|
|
|
:custom string
|
|
|
|
:documentation "The target pattern.
|
|
|
|
A pattern of \"%.o\" is used for inference rules, and would match object files.
|
|
|
|
A target of \"foo.o\" explicitly matches the file foo.o.")
|
|
|
|
(dependencies :initarg :dependencies
|
|
|
|
:initform ""
|
|
|
|
:type string
|
|
|
|
:custom string
|
|
|
|
:documentation "Dependencies on this target.
|
|
|
|
A pattern of \"%.o\" would match a file of the same prefix as the target
|
|
|
|
if that target is also an inference rule pattern.
|
|
|
|
A dependency of \"foo.c\" explicitly lists foo.c as a dependency.
|
|
|
|
A variable such as $(name_SOURCES) will list all the source files
|
|
|
|
belonging to the target name.")
|
|
|
|
(rules :initarg :rules
|
|
|
|
:initform nil
|
|
|
|
:type list
|
|
|
|
:custom (repeat string)
|
|
|
|
:documentation "Scripts to execute.
|
2011-11-14 22:00:24 +01:00
|
|
|
These scripts will be executed in sh (Unless the SHELL variable is overridden).
|
2009-09-20 15:06:05 +00:00
|
|
|
Do not prefix with TAB.
|
|
|
|
Each individual element of this list can be either a string, or
|
|
|
|
a lambda function. (The custom element does not yet express that.")
|
|
|
|
(phony :initarg :phony
|
|
|
|
:initform nil
|
|
|
|
:type boolean
|
|
|
|
:custom boolean
|
|
|
|
:documentation "Is this a phony rule?
|
|
|
|
Adds this rule to a .PHONY list."))
|
|
|
|
"A single rule for building some target.")
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
(defvar ede-compiler-list nil
|
|
|
|
"The master list of all EDE compilers.")
|
|
|
|
|
|
|
|
(defvar ede-linker-list nil
|
|
|
|
"The master list of all EDE compilers.")
|
|
|
|
|
|
|
|
(defvar ede-current-build-list nil
|
|
|
|
"List of EDE compilers that have already inserted parts of themselves.
|
2009-10-01 04:10:10 +00:00
|
|
|
This is used when creating a Makefile to prevent duplicate variables and
|
2009-09-20 15:06:05 +00:00
|
|
|
rules from being created.")
|
|
|
|
|
2021-02-12 16:08:01 -05:00
|
|
|
(cl-defmethod initialize-instance :after ((this ede-compiler) &rest _fields)
|
2009-09-20 15:06:05 +00:00
|
|
|
"Make sure that all ede compiler objects are cached in
|
|
|
|
`ede-compiler-list'."
|
|
|
|
(add-to-list 'ede-compiler-list this))
|
|
|
|
|
2021-02-12 16:08:01 -05:00
|
|
|
(cl-defmethod initialize-instance :after ((this ede-linker) &rest _fields)
|
2009-09-20 15:06:05 +00:00
|
|
|
"Make sure that all ede compiler objects are cached in
|
|
|
|
`ede-linker-list'."
|
|
|
|
(add-to-list 'ede-linker-list this))
|
|
|
|
|
|
|
|
(defmacro ede-compiler-begin-unique (&rest body)
|
|
|
|
"Execute BODY, making sure that `ede-current-build-list' is maintained.
|
|
|
|
This will prevent rules from creating duplicate variables or rules."
|
2021-02-12 16:08:01 -05:00
|
|
|
(declare (indent 0) (debug t))
|
2009-09-20 15:06:05 +00:00
|
|
|
`(let ((ede-current-build-list nil))
|
|
|
|
,@body))
|
|
|
|
|
|
|
|
(defmacro ede-compiler-only-once (object &rest body)
|
|
|
|
"Using OBJECT, execute BODY only once per Makefile generation."
|
2021-02-12 16:08:01 -05:00
|
|
|
(declare (indent 1) (debug t))
|
2009-09-20 15:06:05 +00:00
|
|
|
`(if (not (member ,object ede-current-build-list))
|
|
|
|
(progn
|
|
|
|
(add-to-list 'ede-current-build-list ,object)
|
|
|
|
,@body)))
|
|
|
|
|
|
|
|
(defmacro ede-linker-begin-unique (&rest body)
|
|
|
|
"Execute BODY, making sure that `ede-current-build-list' is maintained.
|
|
|
|
This will prevent rules from creating duplicate variables or rules."
|
2021-02-12 16:08:01 -05:00
|
|
|
(declare (indent 0) (debug t))
|
2009-09-20 15:06:05 +00:00
|
|
|
`(let ((ede-current-build-list nil))
|
|
|
|
,@body))
|
|
|
|
|
|
|
|
(defmacro ede-linker-only-once (object &rest body)
|
|
|
|
"Using OBJECT, execute BODY only once per Makefile generation."
|
2021-02-12 16:08:01 -05:00
|
|
|
(declare (indent 1) (debug t))
|
2009-09-20 15:06:05 +00:00
|
|
|
`(if (not (member ,object ede-current-build-list))
|
|
|
|
(progn
|
|
|
|
(add-to-list 'ede-current-build-list ,object)
|
|
|
|
,@body)))
|
|
|
|
|
2014-01-15 22:24:06 -08:00
|
|
|
;;; Queries
|
2009-09-20 15:06:05 +00:00
|
|
|
(defun ede-proj-find-compiler (compilers sourcetype)
|
|
|
|
"Return a compiler from the list COMPILERS that will compile SOURCETYPE."
|
|
|
|
(while (and compilers
|
|
|
|
(not (member sourcetype (oref (car compilers) sourcetype))))
|
|
|
|
(setq compilers (cdr compilers)))
|
|
|
|
(car-safe compilers))
|
|
|
|
|
|
|
|
(defun ede-proj-find-linker (linkers sourcetype)
|
|
|
|
"Return a compiler from the list LINKERS to be used with SOURCETYPE."
|
|
|
|
(while (and linkers
|
|
|
|
(slot-boundp (car linkers) 'sourcetype)
|
|
|
|
(not (member sourcetype (oref (car linkers) sourcetype))))
|
|
|
|
(setq linkers (cdr linkers)))
|
|
|
|
(car-safe linkers))
|
|
|
|
|
|
|
|
;;; Methods:
|
2015-02-04 13:49:49 -05:00
|
|
|
(cl-defmethod ede-proj-tweak-autoconf ((this ede-compilation-program))
|
2011-04-13 13:50:12 +02:00
|
|
|
"Tweak the configure file (current buffer) to accommodate THIS."
|
2009-09-20 15:06:05 +00:00
|
|
|
(mapcar
|
|
|
|
(lambda (obj)
|
|
|
|
(cond ((stringp obj)
|
|
|
|
(autoconf-insert-new-macro obj))
|
|
|
|
((consp obj)
|
|
|
|
(autoconf-insert-new-macro (car obj) (cdr obj)))
|
|
|
|
(t (error "Autoconf directives must be a string, or cons cell")))
|
|
|
|
)
|
|
|
|
(oref this autoconf)))
|
|
|
|
|
2021-02-12 16:08:01 -05:00
|
|
|
(cl-defmethod ede-proj-flush-autoconf ((_this ede-compilation-program))
|
2011-04-13 13:50:12 +02:00
|
|
|
"Flush the configure file (current buffer) to accommodate THIS."
|
2009-09-20 15:06:05 +00:00
|
|
|
nil)
|
|
|
|
|
2009-10-04 19:00:54 +00:00
|
|
|
(defmacro proj-comp-insert-variable-once (varname &rest body)
|
|
|
|
"Add VARNAME into the current Makefile if it doesn't exist.
|
|
|
|
Execute BODY in a location where a value can be placed."
|
Prefer `declare` over a `put` of `list-indent-function`.
While at it, I enabled lexical-binding in the affected files.
* lisp/cedet/semantic/sb.el: Enable lexical-binding.
(semantic-sb-with-tag-buffer): Use `declare`.
* lisp/cedet/semantic/bovine/el.el: Enable lexical-binding.
(semantic-elisp-setup-form-parser): Use `declare`.
* lisp/emacs-lisp/ert.el:
* lisp/emacs-lisp/ert-x.el: Remove redundant `put`.
* lisp/emulation/cua-rect.el: Enable lexical-binding.
(cua--rectangle-operation, cua--rectangle-aux-replace): Use `declare`.
* lisp/mh-e/mh-acros.el: Enable lexical-binding.
(mh-do-in-gnu-emacs, mh-do-in-xemacs, mh-funcall-if-exists, defun-mh)
(defmacro-mh, with-mh-folder-updating, mh-in-show-buffer)
(mh-do-at-event-location, mh-iterate-on-messages-in-region)
(mh-iterate-on-range): Use `declare`.
* lisp/mh-e/mh-compat.el: Enable lexical-binding.
(mh-flet): Use `declare`.
* lisp/mh-e/mh-e.el: Enable lexical-binding.
(defgroup-mh, defcustom-mh, defface-mh): Use `declare`.
* lisp/net/sieve.el: Enable lexical-binding. Remove redundant :group args.
(sieve-activate, sieve-remove, sieve-edit-script): Remove unused arg
from the interactive spec.
(sieve-deactivate-all): Remove unused var `name`.
(sieve-change-region): Use `declare`.
* lisp/obsolete/fast-lock.el: Enable lexical-binding.
Remove redundant :group args. Remove XEmacs compat code.
(save-buffer-state): Remove macro.
(fast-lock-add-properties): Use `with-silent-modifications` instead.
* lisp/obsolete/lazy-lock.el: Enable lexical-binding.
Remove redundant :group args.
(do-while): Use `declare`.
(save-buffer-state): Remove macro.
(lazy-lock-fontify-rest-after-change, lazy-lock-defer-line-after-change)
(lazy-lock-defer-rest-after-change, lazy-lock-after-fontify-buffer)
(lazy-lock-after-unfontify-buffer, lazy-lock-fontify-region):
Use `with-silent-modifications` instead.
* lisp/obsolete/pgg.el: Enable lexical-binding. Remove XEmacs compat code.
(pgg-save-coding-system, pgg-as-lbt, pgg-process-when-success):
Use `declare`.
(pgg-add-passphrase-to-cache): Remove unused var `new-timer`.
(pgg-decrypt-region): Remove unused var `buf`.
* lisp/org/org-agenda.el (org-let, org-let2): Move from org-macs and
use `declare`.
* lisp/org/org-macs.el (org-let, org-let2): Move these functions that
are inherently harmful to your karma to the only package that uses them.
(org-scroll): Use `pcase` to avoid `eval` and use more readable syntax
for those integers standing for events.
* lisp/progmodes/antlr-mode.el: Enable lexical-binding.
(save-buffer-state-x): Use `declare` and `with-silent-modifications`.
* lisp/international/mule-util.el (with-coding-priority):
* lisp/cedet/ede/proj-comp.el (proj-comp-insert-variable-once):
* lisp/org/org-element.el (org-element-map):
* test/lisp/emacs-lisp/bytecomp-tests.el (test-byte-comp-compile-and-load):
* test/lisp/emacs-lisp/generator-tests.el (cps-testcase): Use `declare`.
2021-02-22 11:54:17 -05:00
|
|
|
(declare (indent 1) (debug (sexp body)))
|
2021-03-15 00:08:34 -04:00
|
|
|
`(let ((v ,varname))
|
2009-10-04 19:00:54 +00:00
|
|
|
(unless (re-search-backward (concat "^" v "\\s-*=") nil t)
|
|
|
|
(insert v "=")
|
|
|
|
,@body
|
2021-03-15 00:08:34 -04:00
|
|
|
(insert "\n")
|
|
|
|
(goto-char (point-max)))))
|
2009-10-04 19:00:54 +00:00
|
|
|
|
2015-02-04 13:49:49 -05:00
|
|
|
(cl-defmethod ede-proj-makefile-insert-variables ((this ede-compilation-program))
|
2009-09-20 15:06:05 +00:00
|
|
|
"Insert variables needed by the compiler THIS."
|
|
|
|
(if (eieio-instance-inheritor-slot-boundp this 'variables)
|
|
|
|
(with-slots (variables) this
|
|
|
|
(mapcar
|
|
|
|
(lambda (var)
|
2009-10-04 19:00:54 +00:00
|
|
|
(proj-comp-insert-variable-once (car var)
|
2009-10-03 19:28:05 +00:00
|
|
|
(let ((cd (cdr var)))
|
|
|
|
(if (listp cd)
|
|
|
|
(mapc (lambda (c) (insert " " c)) cd)
|
|
|
|
(insert cd)))))
|
2009-09-20 15:06:05 +00:00
|
|
|
variables))))
|
|
|
|
|
2015-02-04 13:49:49 -05:00
|
|
|
(cl-defmethod ede-compiler-intermediate-objects-p ((this ede-compiler))
|
2009-09-20 15:06:05 +00:00
|
|
|
"Return non-nil if THIS has intermediate object files.
|
|
|
|
If this compiler creates code that can be linked together,
|
|
|
|
then the object files created by the compiler are considered intermediate."
|
|
|
|
(oref this uselinker))
|
|
|
|
|
2021-02-12 16:08:01 -05:00
|
|
|
(cl-defmethod ede-compiler-intermediate-object-variable ((_this ede-compiler)
|
|
|
|
targetname)
|
2009-09-20 15:06:05 +00:00
|
|
|
"Return a string based on THIS representing a make object variable.
|
|
|
|
TARGETNAME is the name of the target that these objects belong to."
|
|
|
|
(concat targetname "_OBJ"))
|
|
|
|
|
2015-02-04 13:49:49 -05:00
|
|
|
(cl-defmethod ede-proj-makefile-insert-object-variables ((this ede-compiler)
|
2009-09-20 15:06:05 +00:00
|
|
|
targetname sourcefiles)
|
|
|
|
"Insert an OBJ variable to specify object code to be generated for THIS.
|
|
|
|
The name of the target is TARGETNAME as a string. SOURCEFILES is the list of
|
|
|
|
files to be objectified.
|
|
|
|
Not all compilers do this."
|
|
|
|
(if (ede-compiler-intermediate-objects-p this)
|
|
|
|
(progn
|
|
|
|
(insert (ede-compiler-intermediate-object-variable this targetname)
|
|
|
|
"=")
|
|
|
|
(let ((src (oref this sourcetype)))
|
|
|
|
(mapc (lambda (s)
|
|
|
|
(let ((ts src))
|
|
|
|
(while (and ts (not (ede-want-file-source-p
|
|
|
|
(symbol-value (car ts)) s)))
|
|
|
|
(setq ts (cdr ts)))
|
|
|
|
;; Only insert the object if the given file is a major
|
|
|
|
;; source-code type.
|
|
|
|
(if ts;; a match as a source file.
|
|
|
|
(insert " " (file-name-sans-extension s)
|
|
|
|
(oref this objectextention)))))
|
|
|
|
sourcefiles)
|
|
|
|
(insert "\n")))))
|
|
|
|
|
2015-02-04 13:49:49 -05:00
|
|
|
(cl-defmethod ede-proj-makefile-insert-rules ((this ede-compilation-program))
|
2009-09-20 15:06:05 +00:00
|
|
|
"Insert rules needed for THIS compiler object."
|
|
|
|
(ede-compiler-only-once this
|
2021-03-12 11:32:42 -05:00
|
|
|
(mapc #'ede-proj-makefile-insert-rules (oref this rules))))
|
2009-09-20 15:06:05 +00:00
|
|
|
|
2015-02-04 13:49:49 -05:00
|
|
|
(cl-defmethod ede-proj-makefile-insert-rules ((this ede-makefile-rule))
|
2009-09-20 15:06:05 +00:00
|
|
|
"Insert rules needed for THIS rule object."
|
2012-10-02 02:10:29 +08:00
|
|
|
(if (oref this phony) (insert ".PHONY: " (oref this target) "\n"))
|
2009-09-20 15:06:05 +00:00
|
|
|
(insert (oref this target) ": " (oref this dependencies) "\n\t"
|
|
|
|
(mapconcat (lambda (c) c) (oref this rules) "\n\t")
|
|
|
|
"\n\n"))
|
|
|
|
|
2015-02-04 13:49:49 -05:00
|
|
|
(cl-defmethod ede-proj-makefile-insert-commands ((this ede-compilation-program))
|
2009-09-20 15:06:05 +00:00
|
|
|
"Insert the commands needed to use compiler THIS.
|
|
|
|
The object creating makefile rules must call this method for the
|
|
|
|
compiler it decides to use after inserting in the rule."
|
|
|
|
(when (slot-boundp this 'commands)
|
|
|
|
(with-slots (commands) this
|
|
|
|
(mapc
|
2012-10-02 02:10:29 +08:00
|
|
|
(lambda (obj) (insert
|
|
|
|
(if (bolp) "\t" " ")
|
|
|
|
(cond ((stringp obj)
|
|
|
|
obj)
|
|
|
|
((and (listp obj)
|
|
|
|
(eq (car obj) 'lambda))
|
|
|
|
(funcall obj))
|
|
|
|
(t
|
|
|
|
(format "%S" obj)))
|
|
|
|
"\n"))
|
2009-09-20 15:06:05 +00:00
|
|
|
commands))
|
|
|
|
(insert "\n")))
|
|
|
|
|
|
|
|
(provide 'ede/proj-comp)
|
|
|
|
|
|
|
|
;;; ede/proj-comp.el ends here
|