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