]> code.delx.au - gnu-emacs/blob - lisp/cedet/ede/generic.el
d3be545a158b53c0f54231ee4433ae399a2635cb
[gnu-emacs] / lisp / cedet / ede / generic.el
1 ;;; ede/generic.el --- Base Support for generic build systems
2
3 ;; Copyright (C) 2010-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 ;; 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.
27 ;;
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.
33 ;;
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.
37 ;;
38 ;; TOO MANY PROJECTS DETECTED:
39 ;;
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.
43 ;;
44 ;; Customization:
45 ;;
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.
52 ;;
53 ;; Adding support for new projects:
54 ;;
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.
57 ;;
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.
63 ;;
64 ;; Lastly, call `ede-generic-new-autoloader' to setup your project so
65 ;; EDE can use it.
66 ;;
67 ;; Adding support for new types of source code:
68 ;;
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.
72 ;;
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.
76 ;;
77 ;; NOTE: It is not necessary to modify ede/generic.el to add any of
78 ;; the above described support features.
79
80 (require 'eieio-opt)
81 (require 'ede/config)
82 (require 'ede/shell)
83 (require 'semantic/db)
84
85 ;;; Code:
86 ;;
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")
93 )
94 "User Configuration object for a generic project.")
95
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"))
104 ;;;
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)))
114 ))
115
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.")
131 )
132 "Baseclass for all targets belonging to the generic ede system."
133 :abstract t)
134
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.")
147 )
148 "The baseclass for all generic EDE project types."
149 :abstract t)
150
151 (cl-defmethod initialize-instance ((this ede-generic-project)
152 &rest fields)
153 "Make sure the targets slot is bound."
154 (cl-call-next-method)
155 (unless (slot-boundp this 'targets)
156 (oset this :targets nil))
157 )
158
159 (cl-defmethod ede-project-root ((this ede-generic-project))
160 "Return my root."
161 this)
162
163 (cl-defmethod ede-find-subproject-for-directory ((proj ede-generic-project)
164 dir)
165 "Return PROJ, for handling all subdirs below DIR."
166 proj)
167
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.")
175
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.")
181
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.")
187
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.")
193
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.")
200
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.")
207
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)
216 ))
217 match))
218
219 (cl-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)
228 )
229 ;; Pick a matching class type.
230 (when ext
231 (dolist (C classes)
232 (let* ((classsym (intern (car C)))
233 (extreg (oref-default 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
243 cls
244 :name (oref-default cls shortname)
245 :path dir
246 :source nil))
247 (object-add-to-list proj :targets ans)
248 )
249 ans))
250
251 ;;; Creating Derived Projects:
252 ;;
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 obsolete and ignored.
259 EXTERNAL-NAME is a human readable name to describe the project; it
260 must be unique among all autoloaded projects.
261 PROJECTFILE is a file name that identifies a project of this type to EDE, such as
262 a Makefile, or SConstruct file.
263 CLASS is the EIEIO class that is used to track this project. It should subclass
264 `ede-generic-project'."
265 (ede-add-project-autoload
266 (ede-project-autoload :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))
282
283 ;;;###autoload
284 (defun ede-enable-generic-projects ()
285 "Enable generic project loaders."
286 (interactive)
287 (ede-generic-new-autoloader "generic-makefile" "Generic Make"
288 "Makefile" 'ede-generic-makefile-project)
289 (ede-generic-new-autoloader "generic-scons" "Generic SCons"
290 "SConstruct" 'ede-generic-scons-project)
291 (ede-generic-new-autoloader "generic-cmake" "Generic CMake"
292 "CMakeLists" 'ede-generic-cmake-project)
293
294 ;; Super Generic found via revision control tags.
295 (ede-generic-new-autoloader "generic-git" "Generic Git"
296 ".git" 'ede-generic-vc-project)
297 (ede-generic-new-autoloader "generic-bzr" "Generic Bazaar"
298 ".bzr" 'ede-generic-vc-project)
299 (ede-generic-new-autoloader "generic-hg" "Generic Mercurial"
300 ".hg" 'ede-generic-vc-project)
301 (ede-generic-new-autoloader "generic-svn" "Generic Subversions"
302 ".svn" 'ede-generic-vc-project)
303 (ede-generic-new-autoloader "generic-cvs" "Generic CVS"
304 "CVS" 'ede-generic-vc-project)
305 (ede-generic-new-autoloader "generic-mtn" "Generic Monotone"
306 "_MTN" 'ede-generic-vc-project)
307
308 ;; Take advantage of existing 'projectile' based projects.
309 ;; @TODO - if projectile supports compile commands etc, can we
310 ;; read that out? Howto if projectile is not part of core emacs.
311 (ede-generic-new-autoloader "generic-projectile" "Generic .projectile"
312 ".projectile" 'ede-generic-vc-project)
313
314 )
315
316 \f
317 ;;; SPECIFIC TYPES OF GENERIC BUILDS
318 ;;
319
320 ;;; MAKEFILE
321
322 (defclass ede-generic-makefile-project (ede-generic-project)
323 ((buildfile :initform "Makefile")
324 )
325 "Generic Project for makefiles.")
326
327 (cl-defmethod ede-generic-setup-configuration ((proj ede-generic-makefile-project) config)
328 "Setup a configuration for Make."
329 (oset config build-command "make -k")
330 (oset config debug-command "gdb ")
331 )
332
333
334 ;;; SCONS
335 (defclass ede-generic-scons-project (ede-generic-project)
336 ((buildfile :initform "SConstruct")
337 )
338 "Generic Project for scons.")
339
340 (cl-defmethod ede-generic-setup-configuration ((proj ede-generic-scons-project) config)
341 "Setup a configuration for SCONS."
342 (oset config build-command "scons")
343 (oset config debug-command "gdb ")
344 )
345
346
347 ;;; CMAKE
348 (defclass ede-generic-cmake-project (ede-generic-project)
349 ((buildfile :initform "CMakeLists")
350 )
351 "Generic Project for cmake.")
352
353 (cl-defmethod ede-generic-setup-configuration ((proj ede-generic-cmake-project) config)
354 "Setup a configuration for CMake."
355 (oset config build-command "cmake")
356 (oset config debug-command "gdb ")
357 )
358
359 ;;; Generic Version Control System
360 (defclass ede-generic-vc-project (ede-generic-project)
361 ()
362 "Generic project found via Version Control files.")
363
364 (cl-defmethod ede-generic-setup-configuration ((proj ede-generic-vc-project) config)
365 "Setup a configuration for projects identified by revision control."
366 )
367
368 (provide 'ede/generic)
369
370 ;; Local variables:
371 ;; generated-autoload-file: "loaddefs.el"
372 ;; generated-autoload-load-name: "ede/generic"
373 ;; End:
374
375 ;;; ede/generic.el ends here