Commit | Line | Data |
---|---|---|
b90caf50 | 1 | ;;; ede/proj.el --- EDE Generic Project file driver |
acc33231 | 2 | |
acaf905b | 3 | ;; Copyright (C) 1998-2003, 2007-2012 Free Software Foundation, Inc. |
acc33231 CY |
4 | |
5 | ;; Author: Eric M. Ludlam <zappo@gnu.org> | |
6 | ;; Keywords: project, make | |
7 | ||
8 | ;; This file is part of GNU Emacs. | |
9 | ||
10 | ;; GNU Emacs is free software: you can redistribute it and/or modify | |
11 | ;; it under the terms of the GNU General Public License as published by | |
12 | ;; the Free Software Foundation, either version 3 of the License, or | |
13 | ;; (at your option) any later version. | |
14 | ||
15 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | ;; GNU General Public License for more details. | |
19 | ||
20 | ;; You should have received a copy of the GNU General Public License | |
21 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | |
22 | ||
23 | ;;; Commentary: | |
24 | ;; | |
25 | ;; EDE defines a method for managing a project. EDE-PROJ aims to be a | |
26 | ;; generic project file format based on the EIEIO object stream | |
27 | ;; methods. Changes in the project structure will require Makefile | |
28 | ;; rebuild. The targets provided in ede-proj can be augmented with | |
29 | ;; additional target types inherited directly from `ede-proj-target'. | |
30 | ||
acc33231 CY |
31 | (require 'ede/proj-comp) |
32 | (require 'ede/make) | |
33 | ||
34 | (declare-function ede-proj-makefile-create "ede/pmake") | |
35 | (declare-function ede-proj-configure-synchronize "ede/pconf") | |
36 | ||
37 | (autoload 'ede-proj-target-aux "ede/proj-aux" | |
38 | "Target class for a group of lisp files." nil nil) | |
39 | (autoload 'ede-proj-target-elisp "ede/proj-elisp" | |
40 | "Target class for a group of lisp files." nil nil) | |
41 | (autoload 'ede-proj-target-elisp-autoloads "ede/proj-elisp" | |
42 | "Target class for generating autoload files." nil nil) | |
43 | (autoload 'ede-proj-target-scheme "ede/proj-scheme" | |
44 | "Target class for a group of lisp files." nil nil) | |
45 | (autoload 'ede-proj-target-makefile-miscelaneous "ede/proj-misc" | |
8240628d | 46 | "Target class for a group of miscellaneous w/ a special makefile." nil nil) |
acc33231 CY |
47 | (autoload 'ede-proj-target-makefile-program "ede/proj-prog" |
48 | "Target class for building a program." nil nil) | |
49 | (autoload 'ede-proj-target-makefile-archive "ede/proj-archive" | |
50 | "Target class for building an archive of object code." nil nil) | |
51 | (autoload 'ede-proj-target-makefile-shared-object "ede/proj-shared" | |
52 | "Target class for building a shared object." nil nil) | |
53 | (autoload 'ede-proj-target-makefile-info "ede/proj-info" | |
54 | "Target class for info files." nil nil) | |
55 | ||
56 | ;;; Class Definitions: | |
57 | (defclass ede-proj-target (ede-target) | |
58 | ((auxsource :initarg :auxsource | |
59 | :initform nil | |
60 | :type list | |
61 | :custom (repeat (string :tag "File")) | |
62 | :label "Auxiliary Source Files" | |
63 | :group (default source) | |
a785b776 | 64 | :documentation "Auxiliary source files included in this target. |
acc33231 CY |
65 | Each of these is considered equivalent to a source file, but it is not |
66 | distributed, and each should have a corresponding rule to build it.") | |
67 | (dirty :initform nil | |
68 | :type boolean | |
69 | :documentation "Non-nil when generated files needs updating.") | |
70 | (compiler :initarg :compiler | |
71 | :initform nil | |
72 | :type (or null symbol) | |
73 | :custom (choice (const :tag "None" nil) | |
74 | :slotofchoices availablecompilers) | |
75 | :label "Compiler for building sources" | |
76 | :group make | |
77 | :documentation | |
78 | "The compiler to be used to compile this object. | |
79 | This should be a symbol, which contains the object defining the compiler. | |
80 | This enables save/restore to do so by name, permitting the sharing | |
81 | of these compiler resources, and global customization thereof.") | |
82 | (linker :initarg :linker | |
83 | :initform nil | |
84 | :type (or null symbol) | |
85 | :custom (choice (const :tag "None" nil) | |
86 | :slotofchoices availablelinkers) | |
87 | :label "Linker for combining intermediate object files." | |
88 | :group make | |
89 | :documentation | |
90 | "The linker to be used to link compiled sources for this object. | |
91 | This should be a symbol, which contains the object defining the linker. | |
92 | This enables save/restore to do so by name, permitting the sharing | |
93 | of these linker resources, and global customization thereof.") | |
94 | ;; Class allocated slots | |
95 | (phony :allocation :class | |
96 | :initform nil | |
97 | :type boolean | |
98 | :documentation | |
99 | "A phony target is one where the build target does not relate to a file. | |
100 | Such targets are always built, but make knows how to deal with them..") | |
101 | (availablecompilers :allocation :class | |
102 | :initform nil | |
103 | :type (or null list) | |
104 | :documentation | |
105 | "A list of `ede-compiler' objects. | |
106 | These are the compilers the user can choose from when setting the | |
107 | `compiler' slot.") | |
108 | (availablelinkers :allocation :class | |
109 | :initform nil | |
110 | :type (or null list) | |
111 | :documentation | |
112 | "A list of `ede-linker' objects. | |
113 | These are the linkers the user can choose from when setting the | |
114 | `linker' slot.") | |
115 | ) | |
116 | "Abstract class for ede-proj targets.") | |
117 | ||
118 | (defclass ede-proj-target-makefile (ede-proj-target) | |
119 | ((makefile :initarg :makefile | |
120 | :initform "Makefile" | |
121 | :type string | |
122 | :custom string | |
123 | :label "Parent Makefile" | |
124 | :group make | |
125 | :documentation "File name of generated Makefile.") | |
126 | (partofall :initarg :partofall | |
127 | :initform t | |
128 | :type boolean | |
129 | :custom boolean | |
130 | :label "Part of `all:' target" | |
131 | :group make | |
132 | :documentation | |
133 | "Non nil means the rule created is part of the all target. | |
134 | Setting this to nil creates the rule to build this item, but does not | |
135 | include it in the ALL`all:' rule.") | |
136 | (configuration-variables | |
137 | :initarg :configuration-variables | |
138 | :initform nil | |
139 | :type list | |
140 | :custom (repeat (cons (string :tag "Configuration") | |
141 | (repeat | |
142 | (cons (string :tag "Name") | |
143 | (string :tag "Value"))))) | |
144 | :label "Environment Variables for configurations" | |
145 | :group make | |
146 | :documentation "Makefile variables appended to use in different configurations. | |
147 | These variables are used in the makefile when a configuration becomes active. | |
148 | Target variables are always renamed such as foo_CFLAGS, then included into | |
149 | commands where the variable would usually appear.") | |
150 | (rules :initarg :rules | |
151 | :initform nil | |
152 | :type list | |
153 | :custom (repeat (object :objecttype ede-makefile-rule)) | |
154 | :label "Additional Rules" | |
155 | :group (make) | |
156 | :documentation | |
157 | "Arbitrary rules and dependencies needed to make this target. | |
158 | It is safe to leave this blank.") | |
159 | ) | |
160 | "Abstract class for Makefile based targets.") | |
161 | ||
162 | (defvar ede-proj-target-alist | |
163 | '(("program" . ede-proj-target-makefile-program) | |
164 | ("archive" . ede-proj-target-makefile-archive) | |
165 | ("sharedobject" . ede-proj-target-makefile-shared-object) | |
166 | ("emacs lisp" . ede-proj-target-elisp) | |
167 | ("emacs lisp autoloads" . ede-proj-target-elisp-autoloads) | |
168 | ("info" . ede-proj-target-makefile-info) | |
169 | ("auxiliary" . ede-proj-target-aux) | |
170 | ("scheme" . ede-proj-target-scheme) | |
171 | ("miscellaneous" . ede-proj-target-makefile-miscelaneous) | |
172 | ) | |
173 | "Alist of names to class types for available project target classes.") | |
174 | ||
175 | (defun ede-proj-register-target (name class) | |
176 | "Register a new target class with NAME and class symbol CLASS. | |
177 | This enables the creation of your target type." | |
178 | (let ((a (assoc name ede-proj-target-alist))) | |
179 | (if a | |
180 | (setcdr a class) | |
181 | (setq ede-proj-target-alist | |
182 | (cons (cons name class) ede-proj-target-alist))))) | |
183 | ||
184 | (defclass ede-proj-project (ede-project) | |
185 | ((makefile-type :initarg :makefile-type | |
186 | :initform Makefile | |
187 | :type symbol | |
188 | :custom (choice (const Makefile) | |
189 | ;(const Makefile.in) | |
190 | (const Makefile.am) | |
191 | ;(const cook) | |
192 | ) | |
193 | :documentation "The type of Makefile to generate. | |
194 | Can be one of 'Makefile, 'Makefile.in, or 'Makefile.am. | |
195 | If this value is NOT 'Makefile, then that overrides the :makefile slot | |
196 | in targets.") | |
197 | (variables :initarg :variables | |
198 | :initform nil | |
199 | :type list | |
200 | :custom (repeat (cons (string :tag "Name") | |
201 | (string :tag "Value"))) | |
202 | :group (settings) | |
203 | :documentation "Variables to set in this Makefile.") | |
204 | (configuration-variables | |
205 | :initarg :configuration-variables | |
206 | :initform ("debug" (("DEBUG" . "1"))) | |
207 | :type list | |
208 | :custom (repeat (cons (string :tag "Configuration") | |
209 | (repeat | |
210 | (cons (string :tag "Name") | |
211 | (string :tag "Value"))))) | |
212 | :group (settings) | |
213 | :documentation "Makefile variables to use in different configurations. | |
214 | These variables are used in the makefile when a configuration becomes active.") | |
215 | (inference-rules :initarg :inference-rules | |
216 | :initform nil | |
217 | :custom (repeat | |
218 | (object :objecttype ede-makefile-rule)) | |
219 | :documentation "Inference rules to add to the makefile.") | |
220 | (include-file :initarg :include-file | |
221 | :initform nil | |
222 | :custom (repeat | |
223 | (string :tag "Include File")) | |
224 | :documentation "Additional files to include. | |
225 | These files can contain additional rules, variables, and customizations.") | |
226 | (automatic-dependencies | |
227 | :initarg :automatic-dependencies | |
228 | :initform t | |
229 | :type boolean | |
230 | :custom boolean | |
231 | :group (default settings) | |
232 | :documentation | |
233 | "Non-nil to do implement automatic dependencies in the Makefile.") | |
234 | (menu :initform | |
235 | ( | |
236 | [ "Regenerate Makefiles" ede-proj-regenerate t ] | |
237 | [ "Upload Distribution" ede-upload-distribution t ] | |
238 | ) | |
239 | ) | |
240 | (metasubproject | |
241 | :initarg :metasubproject | |
242 | :initform nil | |
243 | :type boolean | |
244 | :custom boolean | |
245 | :group (default settings) | |
246 | :documentation | |
247 | "Non-nil if this is a metasubproject. | |
248 | Usually, a subproject is determined by a parent project. If multiple top level | |
249 | projects are grouped into a large project not maintained by EDE, then you need | |
250 | to set this to non-nil. The only effect is that the `dist' rule will then avoid | |
251 | making a tar file.") | |
252 | ) | |
253 | "The EDE-PROJ project definition class.") | |
254 | ||
255 | ;;; Code: | |
256 | (defun ede-proj-load (project &optional rootproj) | |
257 | "Load a project file from PROJECT directory. | |
258 | If optional ROOTPROJ is provided then ROOTPROJ is the root project | |
259 | for the tree being read in. If ROOTPROJ is nil, then assume that | |
260 | the PROJECT being read in is the root project." | |
261 | (save-excursion | |
262 | (let ((ret nil) | |
263 | (subdirs (directory-files project nil "[^.].*" nil))) | |
264 | (set-buffer (get-buffer-create " *tmp proj read*")) | |
265 | (unwind-protect | |
266 | (progn | |
267 | (insert-file-contents (concat project "Project.ede") | |
268 | nil nil nil t) | |
269 | (goto-char (point-min)) | |
270 | (setq ret (read (current-buffer))) | |
271 | (if (not (eq (car ret) 'ede-proj-project)) | |
272 | (error "Corrupt project file")) | |
273 | (setq ret (eval ret)) | |
274 | (oset ret file (concat project "Project.ede")) | |
275 | (oset ret directory project) | |
276 | (oset ret rootproject rootproj) | |
277 | ) | |
278 | (kill-buffer " *tmp proj read*")) | |
279 | (while subdirs | |
280 | (let ((sd (file-name-as-directory | |
281 | (expand-file-name (car subdirs) project)))) | |
282 | (if (and (file-directory-p sd) | |
283 | (ede-directory-project-p sd)) | |
284 | (oset ret subproj | |
285 | (cons (ede-proj-load sd (or rootproj ret)) | |
286 | (oref ret subproj)))) | |
287 | (setq subdirs (cdr subdirs)))) | |
288 | ret))) | |
289 | ||
290 | (defun ede-proj-save (&optional project) | |
291 | "Write out object PROJECT into its file." | |
292 | (save-excursion | |
293 | (if (not project) (setq project (ede-current-project))) | |
294 | (let ((b (set-buffer (get-buffer-create " *tmp proj write*"))) | |
295 | (cfn (oref project file)) | |
296 | (cdir (oref project directory))) | |
297 | (unwind-protect | |
298 | (save-excursion | |
299 | (erase-buffer) | |
300 | (let ((standard-output (current-buffer))) | |
301 | (oset project file (file-name-nondirectory cfn)) | |
302 | (slot-makeunbound project :directory) | |
303 | (object-write project ";; EDE project file.")) | |
304 | (write-file cfn nil) | |
305 | ) | |
306 | ;; Restore the :file on exit. | |
307 | (oset project file cfn) | |
308 | (oset project directory cdir) | |
309 | (kill-buffer b))))) | |
310 | ||
311 | (defmethod ede-commit-local-variables ((proj ede-proj-project)) | |
312 | "Commit change to local variables in PROJ." | |
313 | (ede-proj-save proj)) | |
314 | ||
315 | (defmethod eieio-done-customizing ((proj ede-proj-project)) | |
316 | "Call this when a user finishes customizing this object. | |
317 | Argument PROJ is the project to save." | |
318 | (call-next-method) | |
319 | (ede-proj-save proj)) | |
320 | ||
321 | (defmethod eieio-done-customizing ((target ede-proj-target)) | |
322 | "Call this when a user finishes customizing this object. | |
323 | Argument TARGET is the project we are completing customization on." | |
324 | (call-next-method) | |
325 | (ede-proj-save (ede-current-project))) | |
326 | ||
327 | (defmethod ede-commit-project ((proj ede-proj-project)) | |
328 | "Commit any change to PROJ to its file." | |
329 | (ede-proj-save proj)) | |
330 | ||
331 | (defmethod ede-buffer-mine ((this ede-proj-project) buffer) | |
332 | "Return t if object THIS lays claim to the file in BUFFER." | |
333 | (let ((f (ede-convert-path this (buffer-file-name buffer)))) | |
334 | (or (string= (file-name-nondirectory (oref this file)) f) | |
335 | (string= (ede-proj-dist-makefile this) f) | |
336 | (string-match "Makefile\\(\\.\\(in\\|am\\)\\)?$" f) | |
cb85c0d8 EL |
337 | (string-match "config\\(ure\\.\\(in\\|ac\\)\\|\\.status\\)?$" f) |
338 | (string-match "config.h\\(\\.in\\)?" f) | |
339 | (member f '("AUTHORS" "NEWS" "COPYING" "INSTALL" "README")) | |
acc33231 CY |
340 | ))) |
341 | ||
342 | (defmethod ede-buffer-mine ((this ede-proj-target) buffer) | |
343 | "Return t if object THIS lays claim to the file in BUFFER." | |
344 | (or (call-next-method) | |
345 | (ede-target-buffer-in-sourcelist this buffer (oref this auxsource)))) | |
346 | ||
347 | \f | |
348 | ;;; EDE command functions | |
349 | ;; | |
350 | (defvar ede-proj-target-history nil | |
351 | "History when querying for a target type.") | |
352 | ||
353 | (defmethod project-new-target ((this ede-proj-project) | |
354 | &optional name type autoadd) | |
355 | "Create a new target in THIS based on the current buffer." | |
356 | (let* ((name (or name (read-string "Name: " ""))) | |
357 | (type (or type | |
358 | (completing-read "Type: " ede-proj-target-alist | |
359 | nil t nil '(ede-proj-target-history . 1)))) | |
360 | (ot nil) | |
361 | (src (if (and (buffer-file-name) | |
362 | (if (and autoadd (stringp autoadd)) | |
363 | (string= autoadd "y") | |
364 | (y-or-n-p (format "Add %s to %s? " (buffer-name) name)))) | |
365 | (buffer-file-name))) | |
366 | (fcn (cdr (assoc type ede-proj-target-alist))) | |
367 | ) | |
368 | ||
369 | (when (not fcn) | |
a785b776 | 370 | (error "Unknown target type %s for EDE Project" type)) |
acc33231 CY |
371 | |
372 | (setq ot (funcall fcn name :name name | |
373 | :path (ede-convert-path this default-directory) | |
374 | :source (if src | |
375 | (list (file-name-nondirectory src)) | |
376 | nil))) | |
377 | ;; If we added it, set the local buffer's object. | |
378 | (if src (progn | |
379 | (setq ede-object ot) | |
380 | (ede-apply-object-keymap))) | |
381 | ;; Add it to the project object | |
382 | ;;(oset this targets (cons ot (oref this targets))) | |
383 | ;; New form: Add to the end using fancy eieio function. | |
384 | ;; @todone - Some targets probably want to be in the front. | |
385 | ;; How to do that? | |
386 | ;; @ans - See elisp autoloads for answer | |
387 | (object-add-to-list this 'targets ot t) | |
388 | ;; And save | |
389 | (ede-proj-save this))) | |
390 | ||
391 | (defmethod project-new-target-custom ((this ede-proj-project)) | |
392 | "Create a new target in THIS for custom." | |
393 | (let* ((name (read-string "Name: " "")) | |
394 | (type (completing-read "Type: " ede-proj-target-alist | |
395 | nil t nil '(ede-proj-target-history . 1)))) | |
396 | (funcall (cdr (assoc type ede-proj-target-alist)) name :name name | |
397 | :path (ede-convert-path this default-directory) | |
398 | :source nil))) | |
399 | ||
400 | (defmethod project-delete-target ((this ede-proj-target)) | |
cb85c0d8 | 401 | "Delete the current target THIS from its parent project." |
acc33231 CY |
402 | (let ((p (ede-current-project)) |
403 | (ts (oref this source))) | |
404 | ;; Loop across all sources. If it exists in a buffer, | |
cb85c0d8 | 405 | ;; clear its object. |
acc33231 CY |
406 | (while ts |
407 | (let* ((default-directory (oref this path)) | |
408 | (b (get-file-buffer (car ts)))) | |
409 | (if b | |
0816d744 | 410 | (with-current-buffer b |
acc33231 CY |
411 | (if (eq ede-object this) |
412 | (progn | |
413 | (setq ede-object nil) | |
414 | (ede-apply-object-keymap)))))) | |
415 | (setq ts (cdr ts))) | |
cb85c0d8 | 416 | ;; Remove THIS from its parent. |
acc33231 CY |
417 | ;; The two vectors should be pointer equivalent. |
418 | (oset p targets (delq this (oref p targets))) | |
419 | (ede-proj-save (ede-current-project)))) | |
420 | ||
421 | (defmethod project-add-file ((this ede-proj-target) file) | |
422 | "Add to target THIS the current buffer represented as FILE." | |
423 | (let ((file (ede-convert-path this file)) | |
424 | (src (ede-target-sourcecode this))) | |
425 | (while (and src (not (ede-want-file-p (car src) file))) | |
426 | (setq src (cdr src))) | |
427 | (when src | |
428 | (setq src (car src)) | |
429 | (cond ((ede-want-file-source-p this file) | |
430 | (object-add-to-list this 'source file t)) | |
431 | ((ede-want-file-auxiliary-p this file) | |
432 | (object-add-to-list this 'auxsource file t)) | |
433 | (t (error "`project-add-file(ede-target)' source mismatch error"))) | |
434 | (ede-proj-save)))) | |
435 | ||
436 | (defmethod project-remove-file ((target ede-proj-target) file) | |
437 | "For TARGET, remove FILE. | |
438 | FILE must be massaged by `ede-convert-path'." | |
439 | ;; Speedy delete should be safe. | |
440 | (object-remove-from-list target 'source (ede-convert-path target file)) | |
441 | (object-remove-from-list target 'auxsource (ede-convert-path target file)) | |
442 | (ede-proj-save)) | |
443 | ||
444 | (defmethod project-update-version ((this ede-proj-project)) | |
445 | "The :version of project THIS has changed." | |
446 | (ede-proj-save)) | |
447 | ||
448 | (defmethod project-make-dist ((this ede-proj-project)) | |
449 | "Build a distribution for the project based on THIS target." | |
acc33231 CY |
450 | (let ((pm (ede-proj-dist-makefile this)) |
451 | (df (project-dist-files this))) | |
452 | (if (and (file-exists-p (car df)) | |
453 | (not (y-or-n-p "Dist file already exists. Rebuild? "))) | |
454 | (error "Try `ede-update-version' before making a distribution")) | |
455 | (ede-proj-setup-buildenvironment this) | |
cb85c0d8 | 456 | (if (ede-proj-automake-p this) |
35c7e413 CY |
457 | (setq pm (expand-file-name "Makefile" |
458 | (file-name-directory pm)))) | |
459 | (compile (concat ede-make-command " -f " pm " dist")))) | |
acc33231 CY |
460 | |
461 | (defmethod project-dist-files ((this ede-proj-project)) | |
462 | "Return a list of files that constitutes a distribution of THIS project." | |
463 | (list | |
464 | ;; Note to self, keep this first for the above fn to check against. | |
465 | (concat (oref this name) "-" (oref this version) ".tar.gz") | |
466 | )) | |
467 | ||
468 | (defmethod project-compile-project ((proj ede-proj-project) &optional command) | |
469 | "Compile the entire current project PROJ. | |
470 | Argument COMMAND is the command to use when compiling." | |
471 | (let ((pm (ede-proj-dist-makefile proj)) | |
472 | (default-directory (file-name-directory (oref proj file)))) | |
473 | (ede-proj-setup-buildenvironment proj) | |
cb85c0d8 | 474 | (if (ede-proj-automake-p proj) |
4f54db4b CY |
475 | (setq pm (expand-file-name "Makefile" |
476 | (file-name-directory pm)))) | |
acc33231 CY |
477 | (compile (concat ede-make-command" -f " pm " all")))) |
478 | ||
479 | ;;; Target type specific compilations/debug | |
480 | ;; | |
481 | (defmethod project-compile-target ((obj ede-proj-target) &optional command) | |
482 | "Compile the current target OBJ. | |
483 | Argument COMMAND is the command to use for compiling the target." | |
484 | (project-compile-project (ede-current-project) command)) | |
485 | ||
486 | (defmethod project-compile-target ((obj ede-proj-target-makefile) | |
487 | &optional command) | |
488 | "Compile the current target program OBJ. | |
489 | Optional argument COMMAND is the s the alternate command to use." | |
490 | (ede-proj-setup-buildenvironment (ede-current-project)) | |
491 | (compile (concat ede-make-command " -f " (oref obj makefile) " " | |
492 | (ede-proj-makefile-target-name obj)))) | |
493 | ||
494 | (defmethod project-debug-target ((obj ede-proj-target)) | |
495 | "Run the current project target OBJ in a debugger." | |
496 | (error "Debug-target not supported by %s" (object-name obj))) | |
497 | ||
67d3ffe4 CY |
498 | (defmethod project-run-target ((obj ede-proj-target)) |
499 | "Run the current project target OBJ." | |
500 | (error "Run-target not supported by %s" (object-name obj))) | |
501 | ||
acc33231 CY |
502 | (defmethod ede-proj-makefile-target-name ((this ede-proj-target)) |
503 | "Return the name of the main target for THIS target." | |
504 | (ede-name this)) | |
505 | \f | |
506 | ;;; Compiler and source code generators | |
507 | ;; | |
508 | (defmethod ede-want-file-auxiliary-p ((this ede-target) file) | |
509 | "Return non-nil if THIS target wants FILE." | |
510 | ;; By default, all targets reference the source object, and let it decide. | |
511 | (let ((src (ede-target-sourcecode this))) | |
512 | (while (and src (not (ede-want-file-auxiliary-p (car src) file))) | |
513 | (setq src (cdr src))) | |
514 | src)) | |
515 | ||
516 | (defmethod ede-proj-compilers ((obj ede-proj-target)) | |
517 | "List of compilers being used by OBJ. | |
518 | If the `compiler' slot is empty, concoct one on a first match found | |
519 | basis for any given type from the `availablecompilers' slot. | |
520 | Otherwise, return the `compiler' slot. | |
521 | Converts all symbols into the objects to be used." | |
522 | (when (slot-exists-p obj 'compiler) | |
523 | (let ((comp (oref obj compiler))) | |
524 | (if comp | |
525 | ;; Now that we have a pre-set compilers to use, convert tye symbols | |
526 | ;; into objects for ease of use | |
527 | (if (listp comp) | |
528 | (setq comp (mapcar 'symbol-value comp)) | |
529 | (setq comp (list (symbol-value comp)))) | |
530 | (let* ((acomp (oref obj availablecompilers)) | |
531 | (avail (mapcar 'symbol-value acomp)) | |
532 | (st (oref obj sourcetype)) | |
533 | (sources (oref obj source))) | |
534 | ;; COMP is not specified, so generate a list from the available | |
535 | ;; compilers list. | |
536 | (while st | |
537 | (if (ede-want-any-source-files-p (symbol-value (car st)) sources) | |
538 | (let ((c (ede-proj-find-compiler avail (car st)))) | |
539 | (if c (setq comp (cons c comp))))) | |
cb85c0d8 EL |
540 | (setq st (cdr st))) |
541 | ;; Provide a good error msg. | |
542 | (unless comp | |
543 | (error "Could not find compiler match for source code extension \"%s\". | |
544 | You may need to add support for this type of file." | |
545 | (if sources | |
546 | (file-name-extension (car sources)) | |
547 | ""))) | |
548 | )) | |
e4769531 | 549 | ;; Return the discovered compilers. |
acc33231 CY |
550 | comp))) |
551 | ||
552 | (defmethod ede-proj-linkers ((obj ede-proj-target)) | |
553 | "List of linkers being used by OBJ. | |
554 | If the `linker' slot is empty, concoct one on a first match found | |
555 | basis for any given type from the `availablelinkers' slot. | |
556 | Otherwise, return the `linker' slot. | |
557 | Converts all symbols into the objects to be used." | |
558 | (when (slot-exists-p obj 'linker) | |
559 | (let ((link (oref obj linker))) | |
560 | (if link | |
561 | ;; Now that we have a pre-set linkers to use, convert type symbols | |
562 | ;; into objects for ease of use | |
563 | (if (symbolp link) | |
564 | (setq link (list (symbol-value link))) | |
565 | (error ":linker is not a symbol. Howd you do that?")) | |
566 | (let* ((alink (oref obj availablelinkers)) | |
567 | (avail (mapcar 'symbol-value alink)) | |
568 | (st (oref obj sourcetype)) | |
569 | (sources (oref obj source))) | |
570 | ;; LINKER is not specified, so generate a list from the available | |
571 | ;; compilers list. | |
572 | (while st | |
573 | (if (ede-want-any-source-files-p (symbol-value (car st)) sources) | |
574 | (let ((c (ede-proj-find-linker avail (car st)))) | |
575 | (if c (setq link (cons c link))))) | |
576 | (setq st (cdr st))) | |
577 | (unless link | |
578 | ;; No linker stands out! Loop over our linkers and pull out | |
579 | ;; the first that has no source type requirement. | |
580 | (while (and avail (not (eieio-instance-inheritor-slot-boundp (car avail) 'sourcetype))) | |
581 | (setq avail (cdr avail))) | |
582 | (setq link (cdr avail))))) | |
e4769531 | 583 | ;; Return the discovered linkers. |
acc33231 CY |
584 | link))) |
585 | ||
586 | \f | |
3ed8598c | 587 | ;;; Target type specific autogenerating gobbledygook. |
acc33231 CY |
588 | ;; |
589 | ||
590 | (defun ede-proj-makefile-type (&optional proj) | |
591 | "Makefile type of the current project PROJ." | |
592 | (oref (or proj (ede-current-project)) makefile-type)) | |
593 | ||
594 | (defun ede-proj-automake-p (&optional proj) | |
595 | "Return non-nil if the current project PROJ is automake mode." | |
596 | (eq (ede-proj-makefile-type proj) 'Makefile.am)) | |
597 | ||
598 | (defun ede-proj-autoconf-p (&optional proj) | |
599 | "Return non-nil if the current project PROJ is automake mode." | |
600 | (eq (ede-proj-makefile-type proj) 'Makefile.in)) | |
601 | ||
602 | (defun ede-proj-make-p (&optional proj) | |
603 | "Return non-nil if the current project PROJ is automake mode." | |
604 | (eq (ede-proj-makefile-type proj) 'Makefile)) | |
605 | ||
606 | (defmethod ede-proj-dist-makefile ((this ede-proj-project)) | |
607 | "Return the name of the Makefile with the DIST target in it for THIS." | |
608 | (cond ((eq (oref this makefile-type) 'Makefile.am) | |
609 | (concat (file-name-directory (oref this file)) | |
610 | "Makefile.am")) | |
611 | ((eq (oref this makefile-type) 'Makefile.in) | |
35c7e413 CY |
612 | (expand-file-name "Makefile.in" |
613 | (file-name-directory (oref this file)))) | |
acc33231 | 614 | ((object-assoc "Makefile" 'makefile (oref this targets)) |
35c7e413 CY |
615 | (expand-file-name "Makefile" |
616 | (file-name-directory (oref this file)))) | |
acc33231 CY |
617 | (t |
618 | (let ((targets (oref this targets))) | |
619 | (while (and targets | |
620 | (not (obj-of-class-p | |
621 | (car targets) | |
622 | 'ede-proj-target-makefile))) | |
623 | (setq targets (cdr targets))) | |
624 | (if targets (oref (car targets) makefile) | |
35c7e413 CY |
625 | (expand-file-name "Makefile" |
626 | (file-name-directory (oref this file)))))))) | |
acc33231 CY |
627 | |
628 | (defun ede-proj-regenerate () | |
629 | "Regenerate Makefiles for and edeproject project." | |
630 | (interactive) | |
631 | (ede-proj-setup-buildenvironment (ede-current-project) t)) | |
632 | ||
633 | (defmethod ede-proj-makefile-create-maybe ((this ede-proj-project) mfilename) | |
634 | "Create a Makefile for all Makefile targets in THIS if needed. | |
635 | MFILENAME is the makefile to generate." | |
636 | ;; For now, pass through until dirty is implemented. | |
637 | (require 'ede/pmake) | |
638 | (if (or (not (file-exists-p mfilename)) | |
639 | (file-newer-than-file-p (oref this file) mfilename)) | |
640 | (ede-proj-makefile-create this mfilename))) | |
641 | ||
642 | (defmethod ede-proj-setup-buildenvironment ((this ede-proj-project) | |
643 | &optional force) | |
644 | "Setup the build environment for project THIS. | |
645 | Handles the Makefile, or a Makefile.am configure.in combination. | |
646 | Optional argument FORCE will force items to be regenerated." | |
647 | (if (not force) | |
648 | (ede-proj-makefile-create-maybe this (ede-proj-dist-makefile this)) | |
649 | (require 'ede/pmake) | |
650 | (ede-proj-makefile-create this (ede-proj-dist-makefile this))) | |
651 | ;; Rebuild all subprojects | |
652 | (ede-map-subprojects | |
653 | this (lambda (sproj) (ede-proj-setup-buildenvironment sproj force))) | |
654 | ;; Autoconf projects need to do other kinds of initializations. | |
655 | (when (and (ede-proj-automake-p this) | |
656 | (eq this (ede-toplevel this))) | |
657 | (require 'ede/pconf) | |
658 | ;; If the user wants to force this, do it some other way? | |
659 | (ede-proj-configure-synchronize this) | |
660 | ;; Now run automake to fill in the blanks, autoconf, and other | |
661 | ;; auto thingies so that we can just say "make" when done. | |
662 | ) | |
663 | ) | |
664 | ||
665 | \f | |
666 | ;;; Lower level overloads | |
667 | ;; | |
668 | (defmethod project-rescan ((this ede-proj-project)) | |
669 | "Rescan the EDE proj project THIS." | |
670 | (let ((root (or (ede-project-root this) this)) | |
671 | ) | |
672 | (setq ede-projects (delq root ede-projects)) | |
cb85c0d8 | 673 | (ede-load-project-file (ede-project-root-directory root)) |
acc33231 CY |
674 | )) |
675 | ||
acc33231 CY |
676 | (provide 'ede/proj) |
677 | ||
678 | ;;; ede/proj.el ends here |