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