]> code.delx.au - gnu-emacs/blob - lisp/cedet/ede/linux.el
Update copyright year to 2015
[gnu-emacs] / lisp / cedet / ede / linux.el
1 ;;; ede/linux.el --- Special project for Linux
2
3 ;; Copyright (C) 2008-2015 Free Software Foundation, Inc.
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 ;;
24 ;; Provide a special project type just for Linux, cause Linux is special.
25 ;;
26 ;; Identifies a Linux project automatically.
27 ;; Speedy ede-expand-filename based on extension.
28 ;; Pre-populates the preprocessor map from lisp.h
29 ;;
30 ;; ToDo :
31 ;; * Add "build" options.
32 ;; * Add texinfo lookup options.
33 ;; * Add website
34
35 (eval-when-compile (require 'cl))
36
37 (require 'ede)
38 (require 'ede/make)
39
40 (declare-function semanticdb-file-table-object "semantic/db")
41 (declare-function semanticdb-needs-refresh-p "semantic/db")
42 (declare-function semanticdb-refresh-table "semantic/db")
43
44 ;;; Code:
45 (defgroup project-linux nil
46 "File and tag browser frame."
47 :group 'tools
48 :group 'ede
49 :version "24.3")
50
51 (defcustom project-linux-build-directory-default 'ask
52 "Build directory."
53 :version "24.4"
54 :group 'project-linux
55 :type '(choice (const :tag "Same as source directory" same)
56 (const :tag "Ask the user" ask)))
57
58 (defcustom project-linux-architecture-default 'ask
59 "Target architecture to assume when not auto-detected."
60 :version "24.4"
61 :group 'project-linux
62 :type '(choice (string :tag "Architecture name")
63 (const :tag "Ask the user" ask)))
64
65
66 (defcustom project-linux-compile-target-command (concat ede-make-command " -k -C %s SUBDIRS=%s")
67 "*Default command used to compile a target."
68 :group 'project-linux
69 :type 'string)
70
71 (defcustom project-linux-compile-project-command (concat ede-make-command " -k -C %s")
72 "*Default command used to compile a project."
73 :group 'project-linux
74 :type 'string)
75
76 (defun ede-linux-version (dir)
77 "Find the Linux version for the Linux src in DIR."
78 (let ((buff (get-buffer-create " *linux-query*")))
79 (with-current-buffer buff
80 (erase-buffer)
81 (setq default-directory (file-name-as-directory dir))
82 (insert-file-contents "Makefile" nil 0 512)
83 (goto-char (point-min))
84 (let (major minor sub)
85 (re-search-forward "^VERSION *= *\\([0-9.]+\\)")
86 (setq major (match-string 1))
87 (re-search-forward "^PATCHLEVEL *= *\\([0-9.]+\\)")
88 (setq minor (match-string 1))
89 (re-search-forward "^SUBLEVEL *= *\\([0-9.]+\\)")
90 (setq sub (match-string 1))
91 (prog1
92 (concat major "." minor "." sub)
93 (kill-buffer buff)
94 )))))
95
96 (defclass ede-linux-project (ede-project)
97 ((build-directory :initarg :build-directory
98 :type string
99 :documentation "Build directory.")
100 (architecture :initarg :architecture
101 :type string
102 :documentation "Target architecture.")
103 (include-path :initarg :include-path
104 :type list
105 :documentation "Include directories.
106 Contains both common and target architecture-specific directories."))
107 "Project Type for the Linux source code."
108 :method-invocation-order :depth-first)
109
110
111 (defun ede-linux--get-build-directory (dir)
112 "Detect build directory for sources in DIR.
113 If DIR has not been used as a build directory, fall back to
114 `project-linux-build-directory-default'."
115 (or
116 ;; detected build on source directory
117 (and (file-exists-p (expand-file-name ".config" dir)) dir)
118 ;; use configuration
119 (case project-linux-build-directory-default
120 (same dir)
121 (ask (read-directory-name "Select Linux' build directory: " dir)))))
122
123
124 (defun ede-linux--get-archs (dir)
125 "Returns a list of architecture names found in DIR."
126 (let ((archs-dir (expand-file-name "arch" dir))
127 archs)
128 (when (file-directory-p archs-dir)
129 (mapc (lambda (elem)
130 (when (and
131 (not (string= elem "."))
132 (not (string= elem ".."))
133 (not (string= elem "x86_64")) ; has no separate sources
134 (file-directory-p
135 (expand-file-name elem archs-dir)))
136 (add-to-list 'archs elem t)))
137 (directory-files archs-dir)))
138 archs))
139
140
141 (defun ede-linux--detect-architecture (dir)
142 "Try to auto-detect the architecture as configured in DIR.
143 DIR is Linux' build directory. If it cannot be auto-detected,
144 returns `project-linux-architecture-default'."
145 (let ((archs-dir (expand-file-name "arch" dir))
146 (archs (ede-linux--get-archs dir))
147 arch found)
148 (or (and
149 archs
150 ;; Look for /arch/<arch>/include/generated
151 (progn
152 (while (and archs (not found))
153 (setq arch (car archs))
154 (when (file-directory-p
155 (expand-file-name (concat arch "/include/generated")
156 archs-dir))
157 (setq found arch))
158 (setq archs (cdr archs)))
159 found))
160 project-linux-architecture-default)))
161
162 (defun ede-linux--get-architecture (dir bdir)
163 "Try to auto-detect the architecture as configured in BDIR.
164 Uses `ede-linux--detect-architecture' for the auto-detection. If
165 the result is `ask', let the user choose from architectures found
166 in DIR."
167 (let ((arch (ede-linux--detect-architecture bdir)))
168 (case arch
169 (ask
170 (completing-read "Select target architecture: "
171 (ede-linux--get-archs dir)))
172 (t arch))))
173
174
175 (defun ede-linux--include-path (dir bdir arch)
176 "Returns a list with include directories.
177 Returned directories might not exist, since they are not created
178 until Linux is built for the first time."
179 (map 'list
180 (lambda (elem) (format (concat (car elem) "/" (cdr elem)) arch))
181 ;; XXX: taken from the output of "make V=1"
182 (list (cons dir "arch/%s/include")
183 (cons bdir "arch/%s/include/generated")
184 (cons dir "include")
185 (cons bdir "include")
186 (cons dir "arch/%s/include/uapi")
187 (cons bdir "arch/%s/include/generated/uapi")
188 (cons dir "include/uapi")
189 (cons bdir "include/generated/uapi"))))
190
191 ;;;###autoload
192 (defun ede-linux-load (dir &optional rootproj)
193 "Return an Linux Project object if there is a match.
194 Return nil if there isn't one.
195 Argument DIR is the directory it is created for.
196 ROOTPROJ is nil, since there is only one project."
197 ;; Doesn't already exist, so let's make one.
198 (let* ((bdir (ede-linux--get-build-directory dir))
199 (arch (ede-linux--get-architecture dir bdir))
200 (include-path (ede-linux--include-path dir bdir arch)))
201 (ede-linux-project
202 "Linux"
203 :name "Linux"
204 :version (ede-linux-version dir)
205 :directory (file-name-as-directory dir)
206 :file (expand-file-name "scripts/ver_linux"
207 dir)
208 :build-directory bdir
209 :architecture arch
210 :include-path include-path)))
211
212 ;;;###autoload
213 (ede-add-project-autoload
214 (ede-project-autoload "linux"
215 :name "LINUX ROOT"
216 :file 'ede/linux
217 :proj-file "scripts/ver_linux"
218 :load-type 'ede-linux-load
219 :class-sym 'ede-linux-project
220 :new-p nil
221 :safe-p t)
222 'unique)
223
224 (defclass ede-linux-target-c (ede-target)
225 ()
226 "EDE Linux Project target for C code.
227 All directories need at least one target.")
228
229 (defclass ede-linux-target-misc (ede-target)
230 ()
231 "EDE Linux Project target for Misc files.
232 All directories need at least one target.")
233
234 (defmethod initialize-instance ((this ede-linux-project)
235 &rest fields)
236 "Make sure the targets slot is bound."
237 (call-next-method)
238 (unless (slot-boundp this 'targets)
239 (oset this :targets nil)))
240
241 ;;; File Stuff
242 ;;
243 (defmethod ede-project-root-directory ((this ede-linux-project)
244 &optional file)
245 "Return the root for THIS Linux project with file."
246 (ede-up-directory (file-name-directory (oref this file))))
247
248 (defmethod ede-project-root ((this ede-linux-project))
249 "Return my root."
250 this)
251
252 (defmethod ede-find-subproject-for-directory ((proj ede-linux-project)
253 dir)
254 "Return PROJ, for handling all subdirs below DIR."
255 proj)
256
257 ;;; TARGET MANAGEMENT
258 ;;
259 (defun ede-linux-find-matching-target (class dir targets)
260 "Find a target that is a CLASS and is in DIR in the list of TARGETS."
261 (let ((match nil))
262 (dolist (T targets)
263 (when (and (object-of-class-p T class)
264 (string= (oref T :path) dir))
265 (setq match T)
266 ))
267 match))
268
269 (defmethod ede-find-target ((proj ede-linux-project) buffer)
270 "Find an EDE target in PROJ for BUFFER.
271 If one doesn't exist, create a new one for this directory."
272 (let* ((ext (file-name-extension (buffer-file-name buffer)))
273 (cls (cond ((not ext)
274 'ede-linux-target-misc)
275 ((string-match "c\\|h" ext)
276 'ede-linux-target-c)
277 (t 'ede-linux-target-misc)))
278 (targets (oref proj targets))
279 (dir default-directory)
280 (ans (ede-linux-find-matching-target cls dir targets))
281 )
282 (when (not ans)
283 (setq ans (make-instance
284 cls
285 :name (file-name-nondirectory
286 (directory-file-name dir))
287 :path dir
288 :source nil))
289 (object-add-to-list proj :targets ans)
290 )
291 ans))
292
293 ;;; UTILITIES SUPPORT.
294 ;;
295 (defmethod ede-preprocessor-map ((this ede-linux-target-c))
296 "Get the pre-processor map for Linux C code.
297 All files need the macros from lisp.h!"
298 (require 'semantic/db)
299 (let* ((proj (ede-target-parent this))
300 (root (ede-project-root proj))
301 (versionfile (ede-expand-filename root "include/linux/version.h"))
302 (table (when (and versionfile (file-exists-p versionfile))
303 (semanticdb-file-table-object versionfile)))
304 (filemap '( ("__KERNEL__" . "")
305 ))
306 )
307 (when table
308 (when (semanticdb-needs-refresh-p table)
309 (semanticdb-refresh-table table))
310 (setq filemap (append filemap (oref table lexical-table)))
311 )
312 filemap
313 ))
314
315 (defun ede-linux-file-exists-name (name root subdir)
316 "Return a file name if NAME exists under ROOT with SUBDIR in between."
317 (let ((F (expand-file-name name (expand-file-name subdir root))))
318 (when (file-exists-p F) F)))
319
320 (defmethod ede-expand-filename-impl ((proj ede-linux-project) name)
321 "Within this project PROJ, find the file NAME.
322 Knows about how the Linux source tree is organized."
323 (let* ((ext (file-name-extension name))
324 (root (ede-project-root proj))
325 (dir (ede-project-root-directory root))
326 (bdir (oref proj build-directory))
327 (F (cond
328 ((not ext) nil)
329 ((string-match "h" ext)
330 (let ((dirs (oref proj include-path))
331 found)
332 (while (and dirs (not found))
333 (setq found
334 (or (ede-linux-file-exists-name name bdir (car dirs))
335 (ede-linux-file-exists-name name dir (car dirs))))
336 (setq dirs (cdr dirs)))
337 found))
338 ((string-match "txt" ext)
339 (ede-linux-file-exists-name name dir "Documentation"))
340 (t nil))))
341 (or F (call-next-method))))
342
343 ;;; Command Support
344 ;;
345 (defmethod project-compile-project ((proj ede-linux-project)
346 &optional command)
347 "Compile the entire current project.
348 Argument COMMAND is the command to use when compiling."
349 (let* ((dir (ede-project-root-directory proj)))
350
351 (require 'compile)
352 (if (not project-linux-compile-project-command)
353 (setq project-linux-compile-project-command compile-command))
354 (if (not command)
355 (setq command
356 (format
357 project-linux-compile-project-command
358 dir)))
359
360 (compile command)))
361
362 (defmethod project-compile-target ((obj ede-linux-target-c) &optional command)
363 "Compile the current target.
364 Argument COMMAND is the command to use for compiling the target."
365 (let* ((proj (ede-target-parent obj))
366 (root (ede-project-root proj))
367 (dir (ede-project-root-directory root))
368 (subdir (oref obj path)))
369
370 (require 'compile)
371 (if (not project-linux-compile-project-command)
372 (setq project-linux-compile-project-command compile-command))
373 (if (not command)
374 (setq command
375 (format
376 project-linux-compile-target-command
377 dir subdir)))
378
379 (compile command)))
380
381 (defmethod project-rescan ((this ede-linux-project))
382 "Rescan this Linux project from the sources."
383 (let* ((dir (ede-project-root-directory this))
384 (bdir (ede-linux--get-build-directory dir))
385 (arch (ede-linux--get-architecture dir bdir))
386 (inc (ede-linux--include-path dir bdir arch))
387 (ver (ede-linux-version dir)))
388 (oset this version ver)
389 (oset this :build-directory bdir)
390 (oset this :architecture arch)
391 (oset this :include-path inc)
392 ))
393
394 (provide 'ede/linux)
395
396 ;; Local variables:
397 ;; generated-autoload-file: "loaddefs.el"
398 ;; generated-autoload-load-name: "ede/linux"
399 ;; End:
400
401 ;;; ede/linux.el ends here