Update copyright year to 2015
[emacs.git] / lisp / cedet / ede / generic.el
blob4d1e0e20707ba370c9eaa305636a209535ee38a7
1 ;;; ede/generic.el --- Base Support for generic build systems
3 ;; Copyright (C) 2010-2015 Free Software Foundation, Inc.
5 ;; Author: Eric M. Ludlam <eric@siege-engine.com>
7 ;; This file is part of GNU Emacs.
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.
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.
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/>.
22 ;;; Commentary:
24 ;; There are a lot of build systems out there, and EDE can't support
25 ;; them all fully. The ede/generic.el system is the base for
26 ;; supporting alternate build systems in a simple way, automatically.
28 ;; The structure is for the ede-generic baseclass, which is augmented
29 ;; by simple sub-classes that can be created by users on an as needed
30 ;; basis. The generic system will have targets for many language
31 ;; types, and create the targets on an as needed basis. All
32 ;; sub-project types will recycle the same generic target types.
34 ;; The generic target types will only be implemented for languages
35 ;; where having EDE support actually matters, with a single MISC to
36 ;; represent anything else.
38 ;; TOO MANY PROJECTS DETECTED:
40 ;; If enabling ede-generic support starts identifying too many
41 ;; projects, drop a file called `.ede-ignore' into any directory where
42 ;; you do not want a project to be.
44 ;; Customization:
46 ;; Since these projects are all so incredibly generic, a user will
47 ;; need to configure some aspects of the project by hand. In order to
48 ;; enable this without configuring the project objects directly (which
49 ;; are auto-generated) a special ede-generic-config object is defined to
50 ;; hold the basics. Generic projects will identify and use these
51 ;; config files.
53 ;; Adding support for new projects:
55 ;; To add support to EDE Generic for new project types is very quick.
56 ;; See the end of this file for examples such as CMake and SCons.
58 ;; Support consists of one class for your project, specifying the file
59 ;; name used by the project system you want to support. It also
60 ;; should implement th method `ede-generic-setup-configuration' to
61 ;; prepopulate the configurable portion of the generic project with
62 ;; build details.
64 ;; Lastly, call `ede-generic-new-autoloader' to setup your project so
65 ;; EDE can use it.
67 ;; Adding support for new types of source code:
69 ;; Sources of different types are supported with a simple class which
70 ;; subclasses `ede-generic-target'. The slots `shortname' and
71 ;; `extension' should be given new initial values.
73 ;; Optionally, any target method used by EDE can then be overridden.
74 ;; The ede-generic-target-c-cpp has some example methods setting up
75 ;; the pre-processor map and system include path.
77 ;; NOTE: It is not necessary to modify ede-generic.el to add any of
78 ;; the above described support features.
80 (require 'eieio-opt)
81 (require 'ede/config)
82 (require 'ede/shell)
83 (require 'semantic/db)
85 ;;; Code:
87 ;; Start with the configuration system
88 (defclass ede-generic-config (ede-extra-config
89 ede-extra-config-build
90 ede-extra-config-program
91 ede-extra-config-c)
92 ((file-header-line :initform ";; EDE Generic Project Configuration")
94 "User Configuration object for a generic project.")
96 (defun ede-generic-load (dir &optional rootproj)
97 "Return a Generic Project object if there is a match.
98 Return nil if there isn't one.
99 Argument DIR is the directory it is created for.
100 ROOTPROJ is nil, since there is only one project."
101 ;; Doesn't already exist, so let's make one.
102 (let* ((alobj ede-constructing))
103 (when (not alobj) (error "Cannot load generic project without the autoload instance"))
105 ;; TODO - find the root dir.
106 (let ((rootdir dir))
107 (funcall (oref alobj class-sym)
108 (symbol-name (oref alobj class-sym))
109 :name (file-name-nondirectory (directory-file-name dir))
110 :version "1.0"
111 :directory (file-name-as-directory rootdir)
112 :file (expand-file-name (oref alobj :proj-file)
113 rootdir)))
116 ;;; Base Classes for the system
117 (defclass ede-generic-target (ede-target-with-config
118 ede-target-with-config-build
119 ede-target-with-config-program)
120 ((shortname :initform ""
121 :type string
122 :allocation :class
123 :documentation
124 "Something prepended to the target name.")
125 (extension :initform ""
126 :type string
127 :allocation :class
128 :documentation
129 "Regular expression representing the extension used for this target.
130 subclasses of this base target will override the default value.")
132 "Baseclass for all targets belonging to the generic ede system."
133 :abstract t)
135 (defclass ede-generic-project (ede-project-with-config
136 ede-project-with-config-build
137 ede-project-with-config-program
138 ede-project-with-config-c
139 ede-project-with-config-java)
140 ((config-class :initform ede-generic-config)
141 (config-file-basename :initform "EDEConfig.el")
142 (buildfile :initform ""
143 :type string
144 :allocation :class
145 :documentation "The file name that identifies a project of this type.
146 The class allocated value is replace by different sub classes.")
148 "The baseclass for all generic EDE project types."
149 :abstract t)
151 (defmethod initialize-instance ((this ede-generic-project)
152 &rest fields)
153 "Make sure the targets slot is bound."
154 (call-next-method)
155 (unless (slot-boundp this 'targets)
156 (oset this :targets nil))
159 (defmethod ede-project-root ((this ede-generic-project))
160 "Return my root."
161 this)
163 (defmethod ede-find-subproject-for-directory ((proj ede-generic-project)
164 dir)
165 "Return PROJ, for handling all subdirs below DIR."
166 proj)
168 ;;; A list of different targets
169 (defclass ede-generic-target-c-cpp (ede-generic-target
170 ede-target-with-config-c)
171 ((shortname :initform "C/C++")
172 (extension :initform "\\([ch]\\(pp\\|xx\\|\\+\\+\\)?\\|cc\\|hh\\|CC?\\)"))
173 "EDE Generic Project target for C and C++ code.
174 All directories need at least one target.")
176 (defclass ede-generic-target-el (ede-generic-target)
177 ((shortname :initform "ELisp")
178 (extension :initform "el"))
179 "EDE Generic Project target for Emacs Lisp code.
180 All directories need at least one target.")
182 (defclass ede-generic-target-fortran (ede-generic-target)
183 ((shortname :initform "Fortran")
184 (extension :initform "[fF]9[05]\\|[fF]\\|for"))
185 "EDE Generic Project target for Fortran code.
186 All directories need at least one target.")
188 (defclass ede-generic-target-texi (ede-generic-target)
189 ((shortname :initform "Texinfo")
190 (extension :initform "texi"))
191 "EDE Generic Project target for texinfo code.
192 All directories need at least one target.")
194 (defclass ede-generic-target-java (ede-generic-target
195 ede-target-with-config-java)
196 ((shortname :initform "Java")
197 (extension :initform "java"))
198 "EDE Generic Project target for texinfo code.
199 All directories need at least one target.")
201 ;; MISC must always be last since it will always match the file.
202 (defclass ede-generic-target-misc (ede-generic-target)
203 ((shortname :initform "Misc")
204 (extension :initform ""))
205 "EDE Generic Project target for Misc files.
206 All directories need at least one target.")
208 ;;; Automatic target acquisition.
209 (defun ede-generic-find-matching-target (class dir targets)
210 "Find a target that is a CLASS and is in DIR in the list of TARGETS."
211 (let ((match nil))
212 (dolist (T targets)
213 (when (and (object-of-class-p T class)
214 (string= (oref T :path) dir))
215 (setq match T)
217 match))
219 (defmethod ede-find-target ((proj ede-generic-project) buffer)
220 "Find an EDE target in PROJ for BUFFER.
221 If one doesn't exist, create a new one for this directory."
222 (let* ((ext (file-name-extension (buffer-file-name buffer)))
223 (classes (eieio-build-class-alist 'ede-generic-target t))
224 (cls nil)
225 (targets (oref proj targets))
226 (dir default-directory)
227 (ans nil)
229 ;; Pick a matching class type.
230 (when ext
231 (dolist (C classes)
232 (let* ((classsym (intern (car C)))
233 (extreg (oref classsym extension)))
234 (when (and (not (string= extreg ""))
235 (string-match (concat "\\`\\(?:" extreg "\\)\\'") ext))
236 (setq cls classsym)))))
237 (when (not cls) (setq cls 'ede-generic-target-misc))
238 ;; find a pre-existing matching target
239 (setq ans (ede-generic-find-matching-target cls dir targets))
240 ;; Create a new instance if there wasn't one
241 (when (not ans)
242 (setq ans (make-instance
244 :name (oref cls shortname)
245 :path dir
246 :source nil))
247 (object-add-to-list proj :targets ans)
249 ans))
251 ;;; Creating Derived Projects:
253 ;; Derived projects need an autoloader so that EDE can find the
254 ;; different projects on disk.
255 (defun ede-generic-new-autoloader (internal-name external-name
256 projectfile class)
257 "Add a new EDE Autoload instance for identifying a generic project.
258 INTERNAL-NAME is a long name that identifies this project type.
259 EXTERNAL-NAME is a shorter human readable name to describe the project.
260 PROJECTFILE is a file name that identifies a project of this type to EDE, such as
261 a Makefile, or SConstruct file.
262 CLASS is the EIEIO class that is used to track this project. It should subclass
263 the class `ede-generic-project' project."
264 (ede-add-project-autoload
265 (ede-project-autoload internal-name
266 :name external-name
267 :file 'ede/generic
268 :proj-file projectfile
269 :root-only nil
270 :load-type 'ede-generic-load
271 :class-sym class
272 :new-p nil
273 ;; NOTE: This project type is SAFE because it handles
274 ;; the user-query before loading its config file. These
275 ;; project types are useful without the config file so
276 ;; do the safe part until the user creates a saved config
277 ;; file for it.
278 :safe-p t)
279 ;; Generics must go at the end, since more specific types
280 ;; can create Makefiles also.
281 'generic))
283 ;;;###autoload
284 (defun ede-enable-generic-projects ()
285 "Enable generic project loaders."
286 (interactive)
287 (ede-generic-new-autoloader "generic-makefile" "Make"
288 "Makefile" 'ede-generic-makefile-project)
289 (ede-generic-new-autoloader "generic-scons" "SCons"
290 "SConstruct" 'ede-generic-scons-project)
291 (ede-generic-new-autoloader "generic-cmake" "CMake"
292 "CMakeLists" 'ede-generic-cmake-project)
294 ;; Super Generic found via revision control tags.
295 (ede-generic-new-autoloader "generic-git" "Git"
296 ".git" 'ede-generic-vc-project)
297 (ede-generic-new-autoloader "generic-bzr" "Bazaar"
298 ".bzr" 'ede-generic-vc-project)
299 (ede-generic-new-autoloader "generic-hg" "Mercurial"
300 ".hg" 'ede-generic-vc-project)
301 (ede-generic-new-autoloader "generic-svn" "Subversions"
302 ".svn" 'ede-generic-vc-project)
303 (ede-generic-new-autoloader "generic-cvs" "CVS"
304 "CVS" 'ede-generic-vc-project)
306 ;; Take advantage of existing 'projectile' based projects.
307 ;; @TODO - if projectile supports compile commands etc, can we
308 ;; read that out? Howto if projectile is not part of core emacs.
309 (ede-generic-new-autoloader "generic-projectile" ".projectile"
310 ".projectile" 'ede-generic-vc-project)
315 ;;; SPECIFIC TYPES OF GENERIC BUILDS
318 ;;; MAKEFILE
320 (defclass ede-generic-makefile-project (ede-generic-project)
321 ((buildfile :initform "Makefile")
323 "Generic Project for makefiles.")
325 (defmethod ede-generic-setup-configuration ((proj ede-generic-makefile-project) config)
326 "Setup a configuration for Make."
327 (oset config build-command "make -k")
328 (oset config debug-command "gdb ")
332 ;;; SCONS
333 (defclass ede-generic-scons-project (ede-generic-project)
334 ((buildfile :initform "SConstruct")
336 "Generic Project for scons.")
338 (defmethod ede-generic-setup-configuration ((proj ede-generic-scons-project) config)
339 "Setup a configuration for SCONS."
340 (oset config build-command "scons")
341 (oset config debug-command "gdb ")
345 ;;; CMAKE
346 (defclass ede-generic-cmake-project (ede-generic-project)
347 ((buildfile :initform "CMakeLists")
349 "Generic Project for cmake.")
351 (defmethod ede-generic-setup-configuration ((proj ede-generic-cmake-project) config)
352 "Setup a configuration for CMake."
353 (oset config build-command "cmake")
354 (oset config debug-command "gdb ")
357 ;;; Generic Version Control System
358 (defclass ede-generic-vc-project (ede-generic-project)
360 "Generic project found via Version Control files.")
362 (defmethod ede-generic-setup-configuration ((proj ede-generic-vc-project) config)
363 "Setup a configuration for projects identified by revision control."
366 (provide 'ede/generic)
368 ;; Local variables:
369 ;; generated-autoload-file: "loaddefs.el"
370 ;; generated-autoload-load-name: "ede/generic"
371 ;; End:
373 ;;; ede/generic.el ends here