Commit | Line | Data |
---|---|---|
b90caf50 | 1 | ;;; ede/proj-comp.el --- EDE Generic Project compiler/rule driver |
acc33231 | 2 | |
73b0cd50 | 3 | ;; Copyright (C) 1999-2001, 2004-2005, 2007, 2009-2011 |
a785b776 | 4 | ;; Free Software Foundation, Inc. |
acc33231 CY |
5 | |
6 | ;; Author: Eric M. Ludlam <zappo@gnu.org> | |
7 | ;; Keywords: project, make | |
8 | ||
9 | ;; This file is part of GNU Emacs. | |
10 | ||
11 | ;; GNU Emacs is free software: you can redistribute it and/or modify | |
12 | ;; it under the terms of the GNU General Public License as published by | |
13 | ;; the Free Software Foundation, either version 3 of the License, or | |
14 | ;; (at your option) any later version. | |
15 | ||
16 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | ;; GNU General Public License for more details. | |
20 | ||
21 | ;; You should have received a copy of the GNU General Public License | |
22 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | |
23 | ||
24 | ;;; Commentary: | |
25 | ;; | |
26 | ;; This software handles the maintenance of compiler and rule definitions | |
27 | ;; for different object types. | |
28 | ;; | |
29 | ;; The `ede-compiler' class lets different types of project objects create | |
30 | ;; definitions of compilers that can be swapped in and out for compiling | |
31 | ;; source code. Users can also define new compiler types whenever they | |
32 | ;; some customized behavior. | |
33 | ;; | |
a785b776 | 34 | ;; The `ede-makefile-rule' class lets users add customized rules into their |
acc33231 CY |
35 | ;; objects, and also lets different compilers add chaining rules to their |
36 | ;; behaviors. | |
37 | ;; | |
38 | ;; It is important that all new compiler types be registered once. That | |
39 | ;; way the chaining rules and variables are inserted into any given Makefile | |
40 | ;; only once. | |
41 | ;; | |
42 | ;; To insert many compiler elements, wrap them in `ede-compiler-begin-unique' | |
43 | ;; before calling their insert methods. | |
44 | ;; To write a method that inserts a variable or rule for a compiler | |
45 | ;; based object, wrap the body of your call in `ede-compiler-only-once' | |
46 | ||
67d3ffe4 | 47 | (eval-when-compile (require 'cl)) |
acc33231 CY |
48 | (require 'ede) ;source object |
49 | (require 'ede/autoconf-edit) | |
50 | ||
51 | ;;; Types: | |
52 | (defclass ede-compilation-program (eieio-instance-inheritor) | |
53 | ((name :initarg :name | |
54 | :type string | |
55 | :custom string | |
56 | :documentation "Name of this type of compiler.") | |
57 | (variables :initarg :variables | |
58 | :type list | |
59 | :custom (repeat (cons (string :tag "Variable") | |
60 | (string :tag "Value"))) | |
61 | :documentation | |
62 | "Variables needed in the Makefile for this compiler. | |
63 | An assoc list where each element is (VARNAME . VALUE) where VARNAME | |
64 | is a string, and VALUE is either a string, or a list of strings. | |
65 | For example, GCC would define CC=gcc, and emacs would define EMACS=emacs.") | |
66 | (sourcetype :initarg :sourcetype | |
67 | :type list ;; of symbols | |
68 | :documentation | |
69 | "A list of `ede-sourcecode' objects this class will handle. | |
70 | This is used to match target objects with the compilers and linkers | |
71 | they can use, and which files this object is interested in." | |
72 | :accessor ede-object-sourcecode) | |
73 | (rules :initarg :rules | |
74 | :initform nil | |
75 | :type list | |
76 | :custom (repeat (object :objecttype ede-makefile-rule)) | |
77 | :documentation | |
78 | "Auxiliary rules needed for this compiler to run. | |
79 | For example, yacc/lex files need additional chain rules, or inferences.") | |
80 | (commands :initarg :commands | |
81 | :type list | |
82 | :custom (repeat string) | |
83 | :documentation | |
84 | "The commands used to execute this compiler. | |
85 | The object which uses this compiler will place these commands after | |
07a79ce4 | 86 | its rule definition.") |
acc33231 CY |
87 | (autoconf :initarg :autoconf |
88 | :initform nil | |
89 | :type list | |
90 | :custom (repeat string) | |
91 | :documentation | |
92 | "Autoconf function to call if this type of compiler is used. | |
93 | When a project is in Automake mode, this defines the autoconf function to | |
94 | call to initialize automake to use this compiler. | |
95 | For example, there may be multiple C compilers, but they all probably | |
96 | use the same autoconf form.") | |
97 | (objectextention :initarg :objectextention | |
98 | :type string | |
99 | :documentation | |
100 | "A string which is the extention used for object files. | |
101 | For example, C code uses .o on unix, and Emacs Lisp uses .elc.") | |
102 | ) | |
103 | "A program used to compile or link a program via a Makefile. | |
104 | Contains everything needed to output code into a Makefile, or autoconf | |
105 | file.") | |
106 | ||
107 | (defclass ede-compiler (ede-compilation-program) | |
108 | ((makedepends :initarg :makedepends | |
109 | :initform nil | |
110 | :type boolean | |
111 | :documentation | |
112 | "Non-nil if this compiler can make dependencies.") | |
113 | (uselinker :initarg :uselinker | |
114 | :initform nil | |
115 | :type boolean | |
116 | :documentation | |
117 | "Non-nil if this compiler creates code that can be linked. | |
118 | This requires that the containing target also define a list of available | |
119 | linkers that can be used.") | |
120 | ) | |
121 | "Definition for a compiler. | |
122 | Different types of objects will provide different compilers for | |
123 | different situations.") | |
124 | ||
125 | (defclass ede-linker (ede-compilation-program) | |
126 | () | |
127 | "Contains information needed to link many generated object files together.") | |
128 | ||
129 | (defclass ede-makefile-rule () | |
130 | ((target :initarg :target | |
131 | :initform "" | |
132 | :type string | |
133 | :custom string | |
134 | :documentation "The target pattern. | |
135 | A pattern of \"%.o\" is used for inference rules, and would match object files. | |
136 | A target of \"foo.o\" explicitly matches the file foo.o.") | |
137 | (dependencies :initarg :dependencies | |
138 | :initform "" | |
139 | :type string | |
140 | :custom string | |
141 | :documentation "Dependencies on this target. | |
142 | A pattern of \"%.o\" would match a file of the same prefix as the target | |
143 | if that target is also an inference rule pattern. | |
144 | A dependency of \"foo.c\" explicitly lists foo.c as a dependency. | |
145 | A variable such as $(name_SOURCES) will list all the source files | |
146 | belonging to the target name.") | |
147 | (rules :initarg :rules | |
148 | :initform nil | |
149 | :type list | |
150 | :custom (repeat string) | |
151 | :documentation "Scripts to execute. | |
0b381c7e | 152 | These scripts will be executed in sh (Unless the SHELL variable is overridden). |
acc33231 CY |
153 | Do not prefix with TAB. |
154 | Each individual element of this list can be either a string, or | |
155 | a lambda function. (The custom element does not yet express that.") | |
156 | (phony :initarg :phony | |
157 | :initform nil | |
158 | :type boolean | |
159 | :custom boolean | |
160 | :documentation "Is this a phony rule? | |
161 | Adds this rule to a .PHONY list.")) | |
162 | "A single rule for building some target.") | |
163 | ||
164 | ;;; Code: | |
165 | (defvar ede-compiler-list nil | |
166 | "The master list of all EDE compilers.") | |
167 | ||
168 | (defvar ede-linker-list nil | |
169 | "The master list of all EDE compilers.") | |
170 | ||
171 | (defvar ede-current-build-list nil | |
172 | "List of EDE compilers that have already inserted parts of themselves. | |
a785b776 | 173 | This is used when creating a Makefile to prevent duplicate variables and |
acc33231 CY |
174 | rules from being created.") |
175 | ||
176 | (defmethod initialize-instance :AFTER ((this ede-compiler) &rest fields) | |
177 | "Make sure that all ede compiler objects are cached in | |
178 | `ede-compiler-list'." | |
179 | (add-to-list 'ede-compiler-list this)) | |
180 | ||
181 | (defmethod initialize-instance :AFTER ((this ede-linker) &rest fields) | |
182 | "Make sure that all ede compiler objects are cached in | |
183 | `ede-linker-list'." | |
184 | (add-to-list 'ede-linker-list this)) | |
185 | ||
186 | (defmacro ede-compiler-begin-unique (&rest body) | |
187 | "Execute BODY, making sure that `ede-current-build-list' is maintained. | |
188 | This will prevent rules from creating duplicate variables or rules." | |
189 | `(let ((ede-current-build-list nil)) | |
190 | ,@body)) | |
191 | ||
192 | (defmacro ede-compiler-only-once (object &rest body) | |
193 | "Using OBJECT, execute BODY only once per Makefile generation." | |
194 | `(if (not (member ,object ede-current-build-list)) | |
195 | (progn | |
196 | (add-to-list 'ede-current-build-list ,object) | |
197 | ,@body))) | |
198 | ||
199 | (defmacro ede-linker-begin-unique (&rest body) | |
200 | "Execute BODY, making sure that `ede-current-build-list' is maintained. | |
201 | This will prevent rules from creating duplicate variables or rules." | |
202 | `(let ((ede-current-build-list nil)) | |
203 | ,@body)) | |
204 | ||
205 | (defmacro ede-linker-only-once (object &rest body) | |
206 | "Using OBJECT, execute BODY only once per Makefile generation." | |
207 | `(if (not (member ,object ede-current-build-list)) | |
208 | (progn | |
209 | (add-to-list 'ede-current-build-list ,object) | |
210 | ,@body))) | |
211 | ||
212 | (add-hook 'edebug-setup-hook | |
213 | (lambda () | |
214 | (def-edebug-spec ede-compiler-begin-unique def-body) | |
215 | (def-edebug-spec ede-compiler-only-once (form def-body)) | |
216 | (def-edebug-spec ede-linker-begin-unique def-body) | |
217 | (def-edebug-spec ede-linker-only-once (form def-body)) | |
218 | (def-edebug-spec ede-pmake-insert-variable-shared (form def-body)) | |
219 | )) | |
220 | ||
221 | ;;; Querys | |
222 | (defun ede-proj-find-compiler (compilers sourcetype) | |
223 | "Return a compiler from the list COMPILERS that will compile SOURCETYPE." | |
224 | (while (and compilers | |
225 | (not (member sourcetype (oref (car compilers) sourcetype)))) | |
226 | (setq compilers (cdr compilers))) | |
227 | (car-safe compilers)) | |
228 | ||
229 | (defun ede-proj-find-linker (linkers sourcetype) | |
230 | "Return a compiler from the list LINKERS to be used with SOURCETYPE." | |
231 | (while (and linkers | |
232 | (slot-boundp (car linkers) 'sourcetype) | |
233 | (not (member sourcetype (oref (car linkers) sourcetype)))) | |
234 | (setq linkers (cdr linkers))) | |
235 | (car-safe linkers)) | |
236 | ||
237 | ;;; Methods: | |
238 | (defmethod ede-proj-tweak-autoconf ((this ede-compilation-program)) | |
7ee6a1d3 | 239 | "Tweak the configure file (current buffer) to accommodate THIS." |
acc33231 CY |
240 | (mapcar |
241 | (lambda (obj) | |
242 | (cond ((stringp obj) | |
243 | (autoconf-insert-new-macro obj)) | |
244 | ((consp obj) | |
245 | (autoconf-insert-new-macro (car obj) (cdr obj))) | |
246 | (t (error "Autoconf directives must be a string, or cons cell"))) | |
247 | ) | |
248 | (oref this autoconf))) | |
249 | ||
250 | (defmethod ede-proj-flush-autoconf ((this ede-compilation-program)) | |
7ee6a1d3 | 251 | "Flush the configure file (current buffer) to accommodate THIS." |
acc33231 CY |
252 | nil) |
253 | ||
d91485a9 CY |
254 | (defmacro proj-comp-insert-variable-once (varname &rest body) |
255 | "Add VARNAME into the current Makefile if it doesn't exist. | |
256 | Execute BODY in a location where a value can be placed." | |
257 | `(let ((addcr t) (v ,varname)) | |
258 | (unless (re-search-backward (concat "^" v "\\s-*=") nil t) | |
259 | (insert v "=") | |
260 | ,@body | |
261 | (if addcr (insert "\n")) | |
262 | (goto-char (point-max))) | |
263 | )) | |
264 | (put 'proj-comp-insert-variable-once 'lisp-indent-function 1) | |
265 | ||
acc33231 CY |
266 | (defmethod ede-proj-makefile-insert-variables ((this ede-compilation-program)) |
267 | "Insert variables needed by the compiler THIS." | |
268 | (if (eieio-instance-inheritor-slot-boundp this 'variables) | |
269 | (with-slots (variables) this | |
270 | (mapcar | |
271 | (lambda (var) | |
d91485a9 | 272 | (proj-comp-insert-variable-once (car var) |
e6e267fc CY |
273 | (let ((cd (cdr var))) |
274 | (if (listp cd) | |
275 | (mapc (lambda (c) (insert " " c)) cd) | |
276 | (insert cd))))) | |
acc33231 CY |
277 | variables)))) |
278 | ||
279 | (defmethod ede-compiler-intermediate-objects-p ((this ede-compiler)) | |
280 | "Return non-nil if THIS has intermediate object files. | |
281 | If this compiler creates code that can be linked together, | |
282 | then the object files created by the compiler are considered intermediate." | |
283 | (oref this uselinker)) | |
284 | ||
285 | (defmethod ede-compiler-intermediate-object-variable ((this ede-compiler) | |
286 | targetname) | |
287 | "Return a string based on THIS representing a make object variable. | |
288 | TARGETNAME is the name of the target that these objects belong to." | |
289 | (concat targetname "_OBJ")) | |
290 | ||
291 | (defmethod ede-proj-makefile-insert-object-variables ((this ede-compiler) | |
292 | targetname sourcefiles) | |
293 | "Insert an OBJ variable to specify object code to be generated for THIS. | |
294 | The name of the target is TARGETNAME as a string. SOURCEFILES is the list of | |
295 | files to be objectified. | |
296 | Not all compilers do this." | |
297 | (if (ede-compiler-intermediate-objects-p this) | |
298 | (progn | |
299 | (insert (ede-compiler-intermediate-object-variable this targetname) | |
300 | "=") | |
301 | (let ((src (oref this sourcetype))) | |
302 | (mapc (lambda (s) | |
303 | (let ((ts src)) | |
304 | (while (and ts (not (ede-want-file-source-p | |
305 | (symbol-value (car ts)) s))) | |
306 | (setq ts (cdr ts))) | |
307 | ;; Only insert the object if the given file is a major | |
308 | ;; source-code type. | |
309 | (if ts;; a match as a source file. | |
310 | (insert " " (file-name-sans-extension s) | |
311 | (oref this objectextention))))) | |
312 | sourcefiles) | |
313 | (insert "\n"))))) | |
314 | ||
315 | (defmethod ede-proj-makefile-insert-rules ((this ede-compilation-program)) | |
316 | "Insert rules needed for THIS compiler object." | |
317 | (ede-compiler-only-once this | |
318 | (mapc 'ede-proj-makefile-insert-rules (oref this rules)))) | |
319 | ||
320 | (defmethod ede-proj-makefile-insert-rules ((this ede-makefile-rule)) | |
321 | "Insert rules needed for THIS rule object." | |
322 | (if (oref this phony) (insert ".PHONY: (oref this target)\n")) | |
323 | (insert (oref this target) ": " (oref this dependencies) "\n\t" | |
324 | (mapconcat (lambda (c) c) (oref this rules) "\n\t") | |
325 | "\n\n")) | |
326 | ||
327 | (defmethod ede-proj-makefile-insert-commands ((this ede-compilation-program)) | |
328 | "Insert the commands needed to use compiler THIS. | |
329 | The object creating makefile rules must call this method for the | |
330 | compiler it decides to use after inserting in the rule." | |
331 | (when (slot-boundp this 'commands) | |
332 | (with-slots (commands) this | |
333 | (mapc | |
334 | (lambda (obj) (insert "\t" | |
335 | (cond ((stringp obj) | |
336 | obj) | |
337 | ((and (listp obj) | |
338 | (eq (car obj) 'lambda)) | |
339 | (funcall obj)) | |
340 | (t | |
341 | (format "%S" obj))) | |
342 | "\n")) | |
343 | commands)) | |
344 | (insert "\n"))) | |
345 | ||
346 | ;;; Some details about our new macro | |
347 | ;; | |
348 | (add-hook 'edebug-setup-hook | |
349 | (lambda () | |
350 | (def-edebug-spec ede-compiler-begin-unique def-body))) | |
351 | (put 'ede-compiler-begin-unique 'lisp-indent-function 0) | |
352 | (put 'ede-compiler-only-once 'lisp-indent-function 1) | |
353 | (put 'ede-linker-begin-unique 'lisp-indent-function 0) | |
354 | (put 'ede-linker-only-once 'lisp-indent-function 1) | |
355 | ||
356 | (provide 'ede/proj-comp) | |
357 | ||
358 | ;;; ede/proj-comp.el ends here |