Commit | Line | Data |
---|---|---|
acc33231 CY |
1 | ;;; ede/cpp-root.el --- A simple way to wrap a C++ project with a single root |
2 | ||
ab422c4d | 3 | ;; Copyright (C) 2007-2013 Free Software Foundation, Inc. |
acc33231 CY |
4 | |
5 | ;; Author: Eric M. Ludlam <eric@siege-engine.com> | |
6 | ||
7 | ;; This file is part of GNU Emacs. | |
8 | ||
9 | ;; GNU Emacs is free software: you can redistribute it and/or modify | |
10 | ;; it under the terms of the GNU General Public License as published by | |
11 | ;; the Free Software Foundation, either version 3 of the License, or | |
12 | ;; (at your option) any later version. | |
13 | ||
14 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | ;; GNU General Public License for more details. | |
18 | ||
19 | ;; You should have received a copy of the GNU General Public License | |
20 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | |
21 | ||
22 | ;;; Commentary: | |
23 | ;; | |
07a79ce4 | 24 | ;; NOTE: ede/cpp-root.el has been commented so as to also make it |
acc33231 CY |
25 | ;; useful for learning how to make similar project types. |
26 | ;; | |
27 | ;; Not everyone can use automake, or an EDE project type. For | |
28 | ;; pre-existing code, it is often helpful jut to be able to wrap the | |
29 | ;; whole thing up in as simple a way as possible. | |
30 | ;; | |
31 | ;; The cpp-root project type will allow you to create a single object | |
32 | ;; with no save-file in your .emacs file that will be recognized, and | |
a785b776 | 33 | ;; provide a way to easily allow EDE to provide Semantic with the |
acc33231 CY |
34 | ;; ability to find header files, and other various source files |
35 | ;; quickly. | |
36 | ;; | |
37 | ;; The cpp-root class knows a few things about C++ projects, such as | |
38 | ;; the prevalence of "include" directories, and typical file-layout | |
39 | ;; stuff. If this isn't sufficient, you can subclass | |
40 | ;; `ede-cpp-root-project' and add your own tweaks in just a few lines. | |
41 | ;; See the end of this file for an example. | |
42 | ;; | |
43 | ;;; EXAMPLE | |
44 | ;; | |
a785b776 | 45 | ;; Add this to your .emacs file, modifying appropriate bits as needed. |
acc33231 CY |
46 | ;; |
47 | ;; (ede-cpp-root-project "SOMENAME" :file "/dir/to/some/file") | |
48 | ;; | |
49 | ;; Replace SOMENAME with whatever name you want, and the filename to | |
50 | ;; an actual file at the root of your project. It might be a | |
51 | ;; Makefile, a README file. Whatever. It doesn't matter. It's just | |
52 | ;; a key to hang the rest of EDE off of. | |
53 | ;; | |
54 | ;; The most likely reason to create this project, is to help make | |
55 | ;; finding files within the project faster. In conjunction with | |
56 | ;; Semantic completion, having a short include path is key. You can | |
57 | ;; override the include path like this: | |
58 | ;; | |
59 | ;; (ede-cpp-root-project "NAME" :file "FILENAME" | |
60 | ;; :include-path '( "/include" "../include" "/c/include" ) | |
61 | ;; :system-include-path '( "/usr/include/c++/3.2.2/" ) | |
62 | ;; :spp-table '( ("MOOSE" . "") | |
63 | ;; ("CONST" . "const") ) | |
64 | ;; :spp-files '( "include/config.h" ) | |
65 | ;; ) | |
66 | ;; | |
67 | ;; In this case each item in the include path list is searched. If | |
68 | ;; the directory starts with "/", then that expands to the project | |
69 | ;; root directory. If a directory does not start with "/", then it | |
70 | ;; is relative to the default-directory of the current buffer when | |
71 | ;; the file name is expanded. | |
72 | ;; | |
73 | ;; The include path only affects C/C++ header files. Use the slot | |
74 | ;; :header-match-regexp to change it. | |
75 | ;; | |
76 | ;; The :system-include-path allows you to specify full directory | |
77 | ;; names to include directories where system header files can be | |
78 | ;; found. These will be applied to files in this project only. | |
79 | ;; | |
80 | ;; The :spp-table provides a list of project specific #define style | |
81 | ;; macros that are unique to this project, passed in to the compiler | |
82 | ;; on the command line, or are in special headers. | |
83 | ;; | |
84 | ;; The :spp-files option is like :spp-table, except you can provide a | |
85 | ;; file name for a header in your project where most of your CPP | |
86 | ;; macros reside. Doing this can be easier than listing everything in | |
87 | ;; the :spp-table option. The files listed in :spp-files should not | |
62a81506 | 88 | ;; start with a /, and are relative to something in :include-path. |
acc33231 CY |
89 | ;; |
90 | ;; If you want to override the file-finding tool with your own | |
91 | ;; function you can do this: | |
92 | ;; | |
93 | ;; (ede-cpp-root-project "NAME" :file "FILENAME" :locate-fcn 'MYFCN) | |
94 | ;; | |
95 | ;; Where FILENAME is a file in the root directory of the project. | |
96 | ;; Where MYFCN is a symbol for a function. See: | |
97 | ;; | |
98 | ;; M-x describe-class RET ede-cpp-root-project RET | |
99 | ;; | |
100 | ;; for documentation about the locate-fcn extension. | |
101 | ;; | |
102 | ;;; ADVANCED EXAMPLE | |
103 | ;; | |
104 | ;; If the cpp-root project style is right for you, but you want a | |
105 | ;; dynamic loader, instead of hard-coding values in your .emacs, you | |
106 | ;; can do that too, but you will need to write some lisp code. | |
107 | ;; | |
108 | ;; To do that, you need to add an entry to the | |
109 | ;; `ede-project-class-files' list, and also provide two functions to | |
110 | ;; teach EDE how to load your project pattern | |
111 | ;; | |
a785b776 | 112 | ;; It would look like this: |
acc33231 CY |
113 | ;; |
114 | ;; (defun MY-FILE-FOR-DIR (&optional dir) | |
115 | ;; "Return a full file name to the project file stored in DIR." | |
116 | ;; <write your code here, or return nil> | |
117 | ;; ) | |
118 | ;; | |
119 | ;; (defun MY-ROOT-FCN () | |
120 | ;; "Return the root directory for `default-directory'" | |
121 | ;; ;; You might be able to use `ede-cpp-root-project-root'. | |
122 | ;; ) | |
123 | ;; | |
124 | ;; (defun MY-LOAD (dir) | |
125 | ;; "Load a project of type `cpp-root' for the directory DIR. | |
126 | ;; Return nil if there isn't one." | |
127 | ;; (ede-cpp-root-project "NAME" :file (expand-file-name "FILE" dir) | |
128 | ;; :locate-fcn 'MYFCN) | |
129 | ;; ) | |
130 | ;; | |
131 | ;; (add-to-list 'ede-project-class-files | |
132 | ;; (ede-project-autoload "cpp-root" | |
133 | ;; :name "CPP ROOT" | |
b93e37e5 | 134 | ;; :file 'ede/cpp-root |
acc33231 CY |
135 | ;; :proj-file 'MY-FILE-FOR-DIR |
136 | ;; :proj-root 'MY-ROOT-FCN | |
137 | ;; :load-type 'MY-LOAD | |
62a81506 CY |
138 | ;; :class-sym 'ede-cpp-root-project |
139 | ;; :safe-p t) | |
acc33231 CY |
140 | ;; t) |
141 | ;; | |
142 | ;;; TODO | |
143 | ;; | |
144 | ;; Need a way to reconfigure a project, and have it affect all open buffers. | |
145 | ;; From Tobias Gerdin: | |
146 | ;; | |
147 | ;; >>3) Is there any way to refresh a ede-cpp-root-project dynamically? I have | |
148 | ;; >>some file open part of the project, fiddle with the include paths and would | |
149 | ;; >>like the open buffer to notice this when I re-evaluate the | |
150 | ;; >>ede-cpp-root-project constructor. | |
151 | ;; > | |
152 | ;; > Another good idea. The easy way is to "revert-buffer" as needed. The | |
153 | ;; > ede "project local variables" does this already, so it should be easy | |
154 | ;; > to adapt something. | |
155 | ;; | |
156 | ;; I actually tried reverting the buffer but Semantic did not seem to pick | |
157 | ;; up the differences (the "include summary" reported the same include paths). | |
158 | ||
159 | (require 'ede) | |
160 | ||
161 | (defvar semantic-lex-spp-project-macro-symbol-obarray) | |
162 | (declare-function semantic-lex-make-spp-table "semantic/lex-spp") | |
163 | (declare-function semanticdb-file-table-object "semantic/db") | |
164 | (declare-function semanticdb-needs-refresh-p "semantic/db") | |
165 | (declare-function semanticdb-refresh-table "semantic/db") | |
166 | ||
167 | ;;; Code: | |
168 | ||
169 | ;;; PROJECT CACHE: | |
170 | ;; | |
171 | ;; cpp-root projects are created in a .emacs or other config file, but | |
172 | ;; there still needs to be a way for a particular file to be | |
173 | ;; identified against it. The cache is where we look to map a file | |
174 | ;; against a project. | |
175 | ;; | |
176 | ;; Setting up a simple in-memory cache of active projects allows the | |
177 | ;; user to re-load their configuration file several times without | |
178 | ;; messing up the active project set. | |
179 | ;; | |
180 | (defvar ede-cpp-root-project-list nil | |
181 | "List of projects created by option `ede-cpp-root-project'.") | |
182 | ||
183 | (defun ede-cpp-root-file-existing (dir) | |
184 | "Find a cpp-root project in the list of cpp-root projects. | |
185 | DIR is the directory to search from." | |
186 | (let ((projs ede-cpp-root-project-list) | |
187 | (ans nil)) | |
188 | (while (and projs (not ans)) | |
189 | (let ((root (ede-project-root-directory (car projs)))) | |
190 | (when (string-match (concat "^" (regexp-quote root)) dir) | |
191 | (setq ans (car projs)))) | |
192 | (setq projs (cdr projs))) | |
193 | ans)) | |
194 | ||
195 | ;;; PROJECT AUTOLOAD CONFIG | |
196 | ;; | |
197 | ;; Each project type registers itself into the project-class list. | |
198 | ;; This way, each time a file is loaded, EDE can map that file to a | |
199 | ;; project. This project type checks files against the internal cache | |
200 | ;; of projects created by the user. | |
201 | ;; | |
202 | ;; EDE asks two kinds of questions. One is, does this DIR belong to a | |
203 | ;; project. If it does, it then asks, what is the ROOT directory to | |
204 | ;; the project in DIR. This is easy for cpp-root projects, but more | |
205 | ;; complex for multiply nested projects. | |
206 | ;; | |
207 | ;; If EDE finds out that a project exists for DIR, it then loads that | |
208 | ;; project. The LOAD routine can either create a new project object | |
209 | ;; (if it needs to load it off disk) or more likely can return an | |
210 | ;; existing object for the discovered directory. cpp-root always uses | |
211 | ;; the second case. | |
212 | ||
213 | (defun ede-cpp-root-project-file-for-dir (&optional dir) | |
214 | "Return a full file name to the project file stored in DIR." | |
215 | (let ((proj (ede-cpp-root-file-existing dir))) | |
216 | (when proj (oref proj :file)))) | |
217 | ||
218 | (defvar ede-cpp-root-count 0 | |
219 | "Count number of hits to the cpp root thing. | |
220 | This is a debugging variable to test various optimizations in file | |
221 | lookup in the main EDE logic.") | |
222 | ||
223 | ;;;###autoload | |
224 | (defun ede-cpp-root-project-root (&optional dir) | |
225 | "Get the root directory for DIR." | |
226 | (let ((projfile (ede-cpp-root-project-file-for-dir | |
227 | (or dir default-directory)))) | |
228 | (setq ede-cpp-root-count (1+ ede-cpp-root-count)) | |
229 | ;(debug) | |
230 | (when projfile | |
231 | (file-name-directory projfile)))) | |
232 | ||
233 | (defun ede-cpp-root-load (dir &optional rootproj) | |
234 | "Return a CPP root object if you created one. | |
235 | Return nil if there isn't one. | |
236 | Argument DIR is the directory it is created for. | |
237 | ROOTPROJ is nil, since there is only one project." | |
238 | ;; Snoop through our master list. | |
239 | (ede-cpp-root-file-existing dir)) | |
240 | ||
cb85c0d8 | 241 | ;;;###autoload |
62a81506 CY |
242 | (ede-add-project-autoload |
243 | (ede-project-autoload "cpp-root" | |
244 | :name "CPP ROOT" | |
e8cc7880 | 245 | :file 'ede/cpp-root |
62a81506 CY |
246 | :proj-file 'ede-cpp-root-project-file-for-dir |
247 | :proj-root 'ede-cpp-root-project-root | |
248 | :load-type 'ede-cpp-root-load | |
e8cc7880 | 249 | :class-sym 'ede-cpp-root-project |
62a81506 CY |
250 | :new-p nil |
251 | :safe-p t) | |
252 | ;; When a user creates one of these, it should override any other project | |
253 | ;; type that might happen to be in this directory, so force this to the | |
254 | ;; very front. | |
255 | 'unique) | |
cb85c0d8 | 256 | |
acc33231 CY |
257 | ;;; CLASSES |
258 | ;; | |
259 | ;; EDE sets up projects with two kinds of objects. | |
260 | ;; | |
261 | ;; The PROJECT is a class that represents everything under a directory | |
262 | ;; hierarchy. A TARGET represents a subset of files within a project. | |
263 | ;; A project can have multiple targets, and multiple sub-projects. | |
264 | ;; Sub projects should map to sub-directories. | |
265 | ;; | |
266 | ;; The CPP-ROOT project maps any file in C or C++ mode to a target for | |
267 | ;; C files. | |
268 | ;; | |
269 | ;; When creating a custom project the project developer an opportunity | |
270 | ;; to run code to setup various tools whenever an associated buffer is | |
271 | ;; loaded. The CPP-ROOT project spends most of its time setting up C | |
272 | ;; level include paths, and PreProcessor macro tables. | |
273 | ||
274 | (defclass ede-cpp-root-target (ede-target) | |
e8cc7880 DE |
275 | ((project :initform nil |
276 | :initarg :project)) | |
acc33231 CY |
277 | "EDE cpp-root project target. |
278 | All directories need at least one target.") | |
279 | ||
e8cc7880 | 280 | ;;;###autoload |
acc33231 CY |
281 | (defclass ede-cpp-root-project (ede-project eieio-instance-tracker) |
282 | ((tracking-symbol :initform 'ede-cpp-root-project-list) | |
283 | (include-path :initarg :include-path | |
284 | :initform '( "/include" "../include/" ) | |
285 | :type list | |
286 | :documentation | |
287 | "The default locate function expands filenames within a project. | |
288 | If a header file (.h, .hh, etc) name is expanded, and | |
289 | the :locate-fcn slot is nil, then the include path is checked | |
290 | first, and other directories are ignored. For very large | |
291 | projects, this optimization can save a lot of time. | |
292 | ||
293 | Directory names in the path can be relative to the current | |
294 | buffer's `default-directory' (not starting with a /). Directories | |
295 | that are relative to the project's root should start with a /, such | |
296 | as \"/include\", meaning the directory `include' off the project root | |
297 | directory.") | |
298 | (system-include-path :initarg :system-include-path | |
299 | :initform nil | |
300 | :type list | |
301 | :documentation | |
302 | "The system include path for files in this project. | |
303 | C files initialized in an ede-cpp-root-project have their semantic | |
304 | system include path set to this value. If this is nil, then the | |
305 | semantic path is not modified.") | |
306 | (spp-table :initarg :spp-table | |
307 | :initform nil | |
308 | :type list | |
309 | :documentation | |
310 | "C Preprocessor macros for your files. | |
311 | Preprocessor symbols will be used while parsing your files. | |
312 | These macros might be passed in through the command line compiler, or | |
313 | are critical symbols derived from header files. Providing header files | |
314 | macro values through this slot improves accuracy and performance. | |
315 | Use `:spp-files' to use these files directly.") | |
316 | (spp-files :initarg :spp-files | |
317 | :initform nil | |
318 | :type list | |
319 | :documentation | |
320 | "C header file with Preprocessor macros for your files. | |
321 | The PreProcessor symbols appearing in these files will be used while | |
322 | parsing files in this project. | |
323 | See `semantic-lex-c-preprocessor-symbol-map' for more on how this works.") | |
324 | (header-match-regexp :initarg :header-match-regexp | |
325 | :initform | |
326 | "\\.\\(h\\(h\\|xx\\|pp\\|\\+\\+\\)?\\|H\\)$\\|\\<\\w+$" | |
327 | :type string | |
328 | :documentation | |
329 | "Regexp used to identify C/C++ header files.") | |
330 | (locate-fcn :initarg :locate-fcn | |
331 | :initform nil | |
332 | :type (or null function) | |
333 | :documentation | |
334 | "The locate function can be used in place of | |
335 | `ede-expand-filename' so you can quickly customize your custom target | |
336 | to use specialized local routines instead of the EDE routines. | |
337 | The function symbol must take two arguments: | |
338 | NAME - The name of the file to find. | |
339 | DIR - The directory root for this cpp-root project. | |
340 | ||
341 | It should return the fully qualified file name passed in from NAME. If that file does not | |
342 | exist, it should return nil." | |
343 | ) | |
e8cc7880 DE |
344 | (compile-command :initarg :compile-command |
345 | :initform nil | |
346 | :type (or null string function) | |
347 | :documentation | |
348 | "Compilation command that will be used for this project. | |
349 | It could be string or function that will accept proj argument and should return string. | |
350 | The string will be passed to 'compuile' function that will be issued in root | |
351 | directory of project." | |
352 | ) | |
acc33231 CY |
353 | ) |
354 | "EDE cpp-root project class. | |
045b9da7 | 355 | Each directory needs a project file to control it.") |
acc33231 CY |
356 | |
357 | ;;; INIT | |
358 | ;; | |
359 | ;; Most projects use `initialize-instance' to do special setup | |
360 | ;; on the object when it is created. In this case, EDE-CPP-ROOT can | |
361 | ;; find previous copies of this project, and make sure that one of the | |
362 | ;; objects is deleted. | |
363 | ||
364 | (defmethod initialize-instance ((this ede-cpp-root-project) | |
365 | &rest fields) | |
366 | "Make sure the :file is fully expanded." | |
367 | ;; Add ourselves to the master list | |
368 | (call-next-method) | |
369 | (let ((f (expand-file-name (oref this :file)))) | |
370 | ;; Remove any previous entries from the main list. | |
371 | (let ((old (eieio-instance-tracker-find (file-name-directory f) | |
372 | :directory 'ede-cpp-root-project-list))) | |
373 | ;; This is safe, because :directory isn't filled in till later. | |
374 | (when (and old (not (eq old this))) | |
375 | (delete-instance old))) | |
376 | ;; Basic initialization. | |
377 | (when (or (not (file-exists-p f)) | |
378 | (file-directory-p f)) | |
379 | (delete-instance this) | |
e8cc7880 | 380 | (error ":file for ede-cpp-root-project must be a file")) |
acc33231 CY |
381 | (oset this :file f) |
382 | (oset this :directory (file-name-directory f)) | |
383 | (ede-project-directory-remove-hash (file-name-directory f)) | |
384 | (ede-add-project-to-global-list this) | |
385 | (unless (slot-boundp this 'targets) | |
386 | (oset this :targets nil)) | |
387 | ;; We need to add ourselves to the master list. | |
388 | ;;(setq ede-projects (cons this ede-projects)) | |
389 | )) | |
390 | ||
391 | ;;; SUBPROJ Management. | |
392 | ;; | |
393 | ;; This is a way to allow a subdirectory to point back to the root | |
394 | ;; project, simplifying authoring new single-point projects. | |
395 | ||
396 | (defmethod ede-find-subproject-for-directory ((proj ede-cpp-root-project) | |
397 | dir) | |
398 | "Return PROJ, for handling all subdirs below DIR." | |
399 | proj) | |
400 | ||
401 | ;;; TARGET MANAGEMENT | |
402 | ;; | |
403 | ;; Creating new targets on a per directory basis is a good way to keep | |
404 | ;; files organized. See ede-emacs for an example with multiple file | |
405 | ;; types. | |
406 | (defmethod ede-find-target ((proj ede-cpp-root-project) buffer) | |
407 | "Find an EDE target in PROJ for BUFFER. | |
408 | If one doesn't exist, create a new one for this directory." | |
409 | (let* ((targets (oref proj targets)) | |
410 | (dir default-directory) | |
411 | (ans (object-assoc dir :path targets)) | |
412 | ) | |
413 | (when (not ans) | |
414 | (setq ans (ede-cpp-root-target dir | |
415 | :name (file-name-nondirectory | |
416 | (directory-file-name dir)) | |
417 | :path dir | |
e8cc7880 DE |
418 | :source nil |
419 | :project proj)) | |
acc33231 CY |
420 | (object-add-to-list proj :targets ans) |
421 | ) | |
422 | ans)) | |
423 | ||
424 | ;;; FILE NAMES | |
425 | ;; | |
426 | ;; One of the more important jobs of EDE is to find files in a | |
427 | ;; directory structure. cpp-root has tricks it knows about how most C | |
428 | ;; projects are set up with include paths. | |
429 | ;; | |
430 | ;; This tools also uses the ede-locate setup for augmented file name | |
431 | ;; lookup using external tools. | |
432 | (defmethod ede-expand-filename-impl ((proj ede-cpp-root-project) name) | |
433 | "Within this project PROJ, find the file NAME. | |
434 | This knows details about or source tree." | |
435 | ;; The slow part of the original is looping over subprojects. | |
436 | ;; This version has no subprojects, so this will handle some | |
437 | ;; basic cases. | |
438 | (let ((ans (call-next-method))) | |
439 | (unless ans | |
440 | (let* ((lf (oref proj locate-fcn)) | |
441 | (dir (file-name-directory (oref proj file)))) | |
442 | (if lf | |
443 | (setq ans (funcall lf name dir)) | |
444 | (if (ede-cpp-root-header-file-p proj name) | |
445 | ;; Else, use our little hack. | |
446 | (let ((ip (oref proj include-path)) | |
447 | (tmp nil)) | |
448 | (while ip | |
449 | ;; Translate | |
450 | (setq tmp (ede-cpp-root-translate-file proj (car ip))) | |
451 | ;; Test this name. | |
452 | (setq tmp (expand-file-name name tmp)) | |
453 | (if (file-exists-p tmp) | |
454 | (setq ans tmp)) | |
455 | (setq ip (cdr ip)) )) | |
456 | ;; Else, do the usual. | |
457 | (setq ans (call-next-method))) | |
458 | ))) | |
62a81506 | 459 | ;; TODO - does this call-next-method happen twice. Is that bad?? Why is it here? |
acc33231 CY |
460 | (or ans (call-next-method)))) |
461 | ||
462 | (defmethod ede-project-root ((this ede-cpp-root-project)) | |
463 | "Return my root." | |
464 | this) | |
465 | ||
466 | (defmethod ede-project-root-directory ((this ede-cpp-root-project)) | |
467 | "Return my root." | |
468 | (file-name-directory (oref this file))) | |
469 | ||
470 | ;;; C/CPP SPECIFIC CODE | |
471 | ;; | |
472 | ;; The following code is specific to setting up header files, | |
473 | ;; include lists, and Preprocessor symbol tables. | |
474 | ||
475 | (defmethod ede-cpp-root-header-file-p ((proj ede-cpp-root-project) name) | |
476 | "Non nil if in PROJ the filename NAME is a header." | |
477 | (save-match-data | |
478 | (string-match (oref proj header-match-regexp) name))) | |
479 | ||
480 | (defmethod ede-cpp-root-translate-file ((proj ede-cpp-root-project) filename) | |
481 | "For PROJ, translate a user specified FILENAME. | |
482 | This is for project include paths and spp source files." | |
483 | ;; Step one: Root of this project. | |
484 | (let ((dir (file-name-directory (oref proj file)))) | |
485 | ||
486 | ;; Step two: Analyze first char, and rehost | |
487 | (if (and (not (string= filename "")) (= (aref filename 0) ?/)) | |
488 | ;; Check relative to root of project | |
489 | (setq filename (expand-file-name (substring filename 1) | |
490 | dir)) | |
491 | ;; Relative to current directory. | |
492 | (setq filename (expand-file-name filename))) | |
493 | ||
494 | filename)) | |
495 | ||
acc33231 CY |
496 | (defmethod ede-system-include-path ((this ede-cpp-root-project)) |
497 | "Get the system include path used by project THIS." | |
498 | (oref this system-include-path)) | |
499 | ||
500 | (defmethod ede-preprocessor-map ((this ede-cpp-root-project)) | |
501 | "Get the pre-processor map for project THIS." | |
502 | (require 'semantic/db) | |
503 | (let ((spp (oref this spp-table)) | |
504 | (root (ede-project-root this)) | |
505 | ) | |
506 | (mapc | |
507 | (lambda (F) | |
508 | (let* ((expfile (ede-expand-filename root F)) | |
509 | (table (when expfile | |
510 | (semanticdb-file-table-object expfile))) | |
511 | ) | |
e8cc7880 DE |
512 | (cond |
513 | ((not (file-exists-p expfile)) | |
514 | (message "Cannot find file %s in project." F)) | |
515 | ((string= expfile (buffer-file-name)) | |
516 | ;; Don't include this file in it's own spp table. | |
517 | ) | |
518 | ((not table) | |
519 | (message "No db table available for %s." expfile)) | |
520 | (t | |
62a81506 CY |
521 | (when (semanticdb-needs-refresh-p table) |
522 | (semanticdb-refresh-table table)) | |
e8cc7880 | 523 | (setq spp (append spp (oref table lexical-table))))))) |
acc33231 CY |
524 | (oref this spp-files)) |
525 | spp)) | |
526 | ||
527 | (defmethod ede-system-include-path ((this ede-cpp-root-target)) | |
62a81506 | 528 | "Get the system include path used by target THIS." |
acc33231 CY |
529 | (ede-system-include-path (ede-target-parent this))) |
530 | ||
531 | (defmethod ede-preprocessor-map ((this ede-cpp-root-target)) | |
532 | "Get the pre-processor map for project THIS." | |
533 | (ede-preprocessor-map (ede-target-parent this))) | |
534 | ||
e8cc7880 DE |
535 | (defmethod project-compile-project ((proj ede-cpp-root-project) &optional command) |
536 | "Compile the entire current project PROJ. | |
537 | Argument COMMAND is the command to use when compiling." | |
538 | ;; we need to be in the proj root dir for this to work | |
539 | (let* ((cmd (oref proj :compile-command)) | |
540 | (ov (oref proj :local-variables)) | |
541 | (lcmd (when ov (cdr (assoc 'compile-command ov)))) | |
542 | (cmd-str (cond | |
543 | ((stringp cmd) cmd) | |
544 | ((functionp cmd) (funcall cmd proj)) | |
545 | ((stringp lcmd) lcmd) | |
546 | ((functionp lcmd) (funcall lcmd proj))))) | |
547 | (when cmd-str | |
548 | (let ((default-directory (ede-project-root-directory proj))) | |
549 | (compile cmd-str))))) | |
550 | ||
551 | (defmethod project-compile-target ((obj ede-cpp-root-target) &optional command) | |
552 | "Compile the current target OBJ. | |
553 | Argument COMMAND is the command to use for compiling the target." | |
554 | (when (oref obj :project) | |
555 | (project-compile-project (oref obj :project) command))) | |
556 | ||
557 | ||
cb85c0d8 EL |
558 | ;;; Quick Hack |
559 | (defun ede-create-lots-of-projects-under-dir (dir projfile &rest attributes) | |
560 | "Create a bunch of projects under directory DIR. | |
561 | PROJFILE is a file name sans directory that indicates a subdirectory | |
562 | is a project directory. | |
563 | Generic ATTRIBUTES, such as :include-path can be added. | |
564 | Note: This needs some work." | |
565 | (let ((files (directory-files dir t))) | |
566 | (dolist (F files) | |
567 | (if (file-exists-p (expand-file-name projfile F)) | |
568 | `(ede-cpp-root-project (file-name-nondirectory F) | |
569 | :name (file-name-nondirectory F) | |
570 | :file (expand-file-name projfile F) | |
571 | attributes))))) | |
572 | ||
acc33231 CY |
573 | (provide 'ede/cpp-root) |
574 | ||
575 | ;; Local variables: | |
576 | ;; generated-autoload-file: "loaddefs.el" | |
acc33231 CY |
577 | ;; generated-autoload-load-name: "ede/cpp-root" |
578 | ;; End: | |
579 | ||
580 | ;;; ede/cpp-root.el ends here |