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