Commit | Line | Data |
---|---|---|
3afbc435 | 1 | ;;; cc-bytecomp.el --- compile time setup for proper compilation |
130c507e | 2 | |
4e643dd2 | 3 | ;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
d7a0267c | 4 | ;; Free Software Foundation, Inc. |
130c507e GM |
5 | |
6 | ;; Author: Martin Stjernholm | |
7 | ;; Maintainer: bug-cc-mode@gnu.org | |
8 | ;; Created: 15-Jul-2000 | |
9 | ;; Version: See cc-mode.el | |
10 | ;; Keywords: c languages oop | |
11 | ||
2be7dabc GM |
12 | ;; This file is part of GNU Emacs. |
13 | ||
14 | ;; GNU Emacs is free software; you can redistribute it and/or modify | |
130c507e | 15 | ;; it under the terms of the GNU General Public License as published by |
1a484753 | 16 | ;; the Free Software Foundation; either version 3, or (at your option) |
2be7dabc | 17 | ;; any later version. |
130c507e | 18 | |
2be7dabc | 19 | ;; GNU Emacs is distributed in the hope that it will be useful, |
130c507e GM |
20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | ;; GNU General Public License for more details. | |
23 | ||
24 | ;; You should have received a copy of the GNU General Public License | |
0386b551 | 25 | ;; along with this program; see the file COPYING. If not, write to |
3a35cf56 LK |
26 | ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
27 | ;; Boston, MA 02110-1301, USA. | |
130c507e GM |
28 | |
29 | ;;; Commentary: | |
30 | ||
31 | ;; This file is used to ensure that the CC Mode files are correctly | |
32 | ;; compiled regardless the environment (e.g. if an older CC Mode with | |
33 | ;; outdated macros are loaded during compilation). It also provides | |
34 | ;; features to defeat the compiler warnings for selected symbols. | |
a66cd3ee MS |
35 | ;; |
36 | ;; There's really nothing CC Mode specific here; this functionality | |
37 | ;; ought to be provided by the byte compilers or some accompanying | |
d9e94c22 MS |
38 | ;; library. To use it from some package "foo.el", begin by putting |
39 | ;; the following blurb at the top of the file: | |
40 | ;; | |
41 | ;; (eval-when-compile | |
42 | ;; (let ((load-path | |
43 | ;; (if (and (boundp 'byte-compile-dest-file) | |
44 | ;; (stringp byte-compile-dest-file)) | |
45 | ;; (cons (file-name-directory byte-compile-dest-file) load-path) | |
46 | ;; load-path))) | |
47 | ;; (load "cc-bytecomp" nil t)) | |
48 | ;; | |
49 | ;; This (unfortunately rather clumsy) form will ensure that the | |
50 | ;; cc-bytecomp.el in the same directory as foo.el is loaded during | |
51 | ;; byte compilation of the latter. | |
52 | ;; | |
53 | ;; At the end of foo.el there should normally be a "(provide 'foo)". | |
54 | ;; Replace it with "(cc-provide 'foo)"; that is necessary to restore | |
55 | ;; the environment after the byte compilation. If you don't have a | |
56 | ;; `provide' at the end, you have to add the following as the very | |
57 | ;; last form in the file: | |
58 | ;; | |
59 | ;; (eval-when-compile (cc-bytecomp-restore-environment)) | |
60 | ;; | |
61 | ;; Now everything is set to use the various functions and macros in | |
62 | ;; this package. | |
63 | ;; | |
64 | ;; If your package is split into several files, you should use | |
65 | ;; `cc-require', `cc-require-when-compile' or `cc-load' to load them. | |
66 | ;; That ensures that the files in the same directory always are | |
67 | ;; loaded, to avoid mixup with other versions of them that might exist | |
68 | ;; elsewhere in the load path. | |
69 | ;; | |
70 | ;; To suppress byte compiler warnings, use the macros | |
71 | ;; `cc-bytecomp-defun', `cc-bytecomp-defvar', | |
72 | ;; `cc-bytecomp-obsolete-fun', and `cc-bytecomp-obsolete-var'. | |
73 | ;; | |
74 | ;; This file is not used at all after the package has been byte | |
75 | ;; compiled. It is however necessary when running uncompiled. | |
130c507e GM |
76 | |
77 | \f | |
3afbc435 PJ |
78 | ;;; Code: |
79 | ||
130c507e GM |
80 | (defvar cc-bytecomp-unbound-variables nil) |
81 | (defvar cc-bytecomp-original-functions nil) | |
82 | (defvar cc-bytecomp-original-properties nil) | |
130c507e GM |
83 | (defvar cc-bytecomp-loaded-files nil) |
84 | (defvar cc-bytecomp-environment-set nil) | |
85 | ||
d9e94c22 MS |
86 | (defmacro cc-bytecomp-debug-msg (&rest args) |
87 | ;;`(message ,@args) | |
88 | ) | |
130c507e GM |
89 | |
90 | (defun cc-bytecomp-setup-environment () | |
91 | ;; Eval'ed during compilation to setup variables, functions etc | |
92 | ;; declared with `cc-bytecomp-defvar' et al. | |
d9e94c22 MS |
93 | (if (not load-in-progress) |
94 | ;; Look at `load-in-progress' to tell whether we're called | |
95 | ;; directly in the file being compiled or just from some file | |
96 | ;; being loaded during compilation. | |
130c507e GM |
97 | (let (p) |
98 | (if cc-bytecomp-environment-set | |
99 | (error "Byte compilation environment already set - \ | |
100 | perhaps a `cc-bytecomp-restore-environment' is forgotten somewhere")) | |
101 | (setq p cc-bytecomp-unbound-variables) | |
102 | (while p | |
103 | (if (not (boundp (car p))) | |
104 | (progn | |
105 | (eval `(defvar ,(car p))) | |
d9e94c22 MS |
106 | (set (car p) (intern (concat "cc-bytecomp-ignore-var:" |
107 | (symbol-name (car p))))) | |
108 | (cc-bytecomp-debug-msg | |
109 | "cc-bytecomp-setup-environment: Covered variable %s" | |
110 | (car p)))) | |
130c507e GM |
111 | (setq p (cdr p))) |
112 | (setq p cc-bytecomp-original-functions) | |
113 | (while p | |
114 | (let ((fun (car (car p))) | |
115 | (temp-macro (car (cdr (car p))))) | |
d9e94c22 MS |
116 | (if (not (fboundp fun)) |
117 | (if temp-macro | |
118 | (progn | |
119 | (eval `(defmacro ,fun ,@temp-macro)) | |
120 | (cc-bytecomp-debug-msg | |
121 | "cc-bytecomp-setup-environment: Bound macro %s" fun)) | |
122 | (fset fun (intern (concat "cc-bytecomp-ignore-fun:" | |
123 | (symbol-name fun)))) | |
124 | (cc-bytecomp-debug-msg | |
125 | "cc-bytecomp-setup-environment: Covered function %s" fun)))) | |
130c507e GM |
126 | (setq p (cdr p))) |
127 | (setq p cc-bytecomp-original-properties) | |
128 | (while p | |
129 | (let ((sym (car (car (car p)))) | |
130 | (prop (cdr (car (car p)))) | |
131 | (tempdef (car (cdr (car p))))) | |
d9e94c22 MS |
132 | (put sym prop tempdef) |
133 | (cc-bytecomp-debug-msg | |
134 | "cc-bytecomp-setup-environment: Bound property %s for %s to %s" | |
135 | prop sym tempdef)) | |
130c507e | 136 | (setq p (cdr p))) |
d9e94c22 MS |
137 | (setq cc-bytecomp-environment-set t) |
138 | (cc-bytecomp-debug-msg | |
139 | "cc-bytecomp-setup-environment: Done")))) | |
130c507e GM |
140 | |
141 | (defun cc-bytecomp-restore-environment () | |
142 | ;; Eval'ed during compilation to restore variables, functions etc | |
143 | ;; declared with `cc-bytecomp-defvar' et al. | |
d9e94c22 | 144 | (if (not load-in-progress) |
130c507e GM |
145 | (let (p) |
146 | (setq p cc-bytecomp-unbound-variables) | |
147 | (while p | |
148 | (let ((var (car p))) | |
d9e94c22 MS |
149 | (if (boundp var) |
150 | (if (eq (intern (concat "cc-bytecomp-ignore-var:" | |
151 | (symbol-name var))) | |
152 | (symbol-value var)) | |
153 | (progn | |
154 | (makunbound var) | |
155 | (cc-bytecomp-debug-msg | |
156 | "cc-bytecomp-restore-environment: Unbound variable %s" | |
157 | var)) | |
158 | (cc-bytecomp-debug-msg | |
159 | "cc-bytecomp-restore-environment: Not restoring variable %s" | |
160 | var)))) | |
130c507e GM |
161 | (setq p (cdr p))) |
162 | (setq p cc-bytecomp-original-functions) | |
163 | (while p | |
164 | (let ((fun (car (car p))) | |
d9e94c22 | 165 | (temp-macro (car (cdr (car p)))) |
130c507e | 166 | (def (car (cdr (cdr (car p)))))) |
d9e94c22 MS |
167 | (if (fboundp fun) |
168 | (if (eq (or temp-macro | |
169 | (intern (concat "cc-bytecomp-ignore-fun:" | |
170 | (symbol-name fun)))) | |
171 | (symbol-function fun)) | |
172 | (if (eq def 'unbound) | |
173 | (progn | |
174 | (fmakunbound fun) | |
175 | (cc-bytecomp-debug-msg | |
176 | "cc-bytecomp-restore-environment: Unbound function %s" | |
177 | fun)) | |
178 | (fset fun def) | |
179 | (cc-bytecomp-debug-msg | |
180 | "cc-bytecomp-restore-environment: Restored function %s" | |
181 | fun)) | |
182 | (cc-bytecomp-debug-msg | |
183 | "cc-bytecomp-restore-environment: Not restoring function %s" | |
184 | fun)))) | |
130c507e GM |
185 | (setq p (cdr p))) |
186 | (setq p cc-bytecomp-original-properties) | |
187 | (while p | |
188 | (let ((sym (car (car (car p)))) | |
189 | (prop (cdr (car (car p)))) | |
190 | (tempdef (car (cdr (car p)))) | |
191 | (origdef (cdr (cdr (car p))))) | |
192 | (if (eq (get sym prop) tempdef) | |
d9e94c22 MS |
193 | (progn |
194 | (put sym prop origdef) | |
195 | (cc-bytecomp-debug-msg | |
196 | "cc-bytecomp-restore-environment: Restored property %s for %s to %s" | |
197 | prop sym origdef)) | |
198 | (cc-bytecomp-debug-msg | |
199 | "cc-bytecomp-restore-environment: Not restoring property %s for %s" | |
200 | prop sym))) | |
130c507e | 201 | (setq p (cdr p))) |
d9e94c22 MS |
202 | (setq cc-bytecomp-environment-set nil) |
203 | (cc-bytecomp-debug-msg | |
204 | "cc-bytecomp-restore-environment: Done")))) | |
205 | ||
206 | (eval | |
207 | ;; This eval is to avoid byte compilation of the function below. | |
208 | ;; There's some bug in XEmacs 21.4.6 that can cause it to dump core | |
209 | ;; here otherwise. My theory is that `cc-bytecomp-load' might be | |
210 | ;; redefined recursively during the `load' inside it, and if it in | |
211 | ;; that case is byte compiled then the byte interpreter gets | |
212 | ;; confused. I haven't succeeded in isolating the bug, though. /mast | |
213 | ||
214 | '(defun cc-bytecomp-load (cc-part) | |
215 | ;; Eval'ed during compilation to load a CC Mode file from the source | |
216 | ;; directory (assuming it's the same as the compiled file | |
217 | ;; destination dir). | |
218 | (if (and (boundp 'byte-compile-dest-file) | |
219 | (stringp byte-compile-dest-file)) | |
220 | (progn | |
221 | (cc-bytecomp-restore-environment) | |
222 | (let ((load-path | |
223 | (cons (file-name-directory byte-compile-dest-file) | |
224 | load-path)) | |
225 | (cc-file (concat cc-part ".el"))) | |
226 | (if (member cc-file cc-bytecomp-loaded-files) | |
227 | () | |
228 | (setq cc-bytecomp-loaded-files | |
229 | (cons cc-file cc-bytecomp-loaded-files)) | |
230 | (cc-bytecomp-debug-msg | |
231 | "cc-bytecomp-load: Loading %S" cc-file) | |
232 | (load cc-file nil t t) | |
233 | (cc-bytecomp-debug-msg | |
234 | "cc-bytecomp-load: Loaded %S" cc-file))) | |
235 | (cc-bytecomp-setup-environment) | |
236 | t)))) | |
130c507e GM |
237 | |
238 | (defmacro cc-require (cc-part) | |
d9e94c22 MS |
239 | "Force loading of the corresponding .el file in the current directory |
240 | during compilation, but compile in a `require'. Don't use within | |
241 | `eval-when-compile'. | |
130c507e GM |
242 | |
243 | Having cyclic cc-require's will result in infinite recursion. That's | |
244 | somewhat intentional." | |
245 | `(progn | |
d9e94c22 | 246 | (eval-when-compile (cc-bytecomp-load (symbol-name ,cc-part))) |
130c507e GM |
247 | (require ,cc-part))) |
248 | ||
249 | (defmacro cc-provide (feature) | |
250 | "A replacement for the `provide' form that restores the environment | |
251 | after the compilation. Don't use within `eval-when-compile'." | |
252 | `(progn | |
253 | (eval-when-compile (cc-bytecomp-restore-environment)) | |
254 | (provide ,feature))) | |
255 | ||
256 | (defmacro cc-load (cc-part) | |
d9e94c22 MS |
257 | "Force loading of the corresponding .el file in the current directory |
258 | during compilation. Don't use outside `eval-when-compile' or | |
259 | `eval-and-compile'. | |
130c507e GM |
260 | |
261 | Having cyclic cc-load's will result in infinite recursion. That's | |
262 | somewhat intentional." | |
263 | `(or (and (featurep 'cc-bytecomp) | |
264 | (cc-bytecomp-load ,cc-part)) | |
265 | (load ,cc-part nil t nil))) | |
266 | ||
d9e94c22 MS |
267 | (defmacro cc-require-when-compile (cc-part) |
268 | "Force loading of the corresponding .el file in the current directory | |
269 | during compilation, but do a compile time `require' otherwise. Don't | |
270 | use within `eval-when-compile'." | |
271 | `(eval-when-compile | |
272 | (if (and (featurep 'cc-bytecomp) | |
273 | (cc-bytecomp-is-compiling)) | |
274 | (if (or (not load-in-progress) | |
275 | (not (featurep ,cc-part))) | |
276 | (cc-bytecomp-load (symbol-name ,cc-part))) | |
277 | (require ,cc-part)))) | |
278 | ||
279 | (defmacro cc-external-require (feature) | |
280 | "Do a `require' of an external package. | |
281 | This restores and sets up the compilation environment before and | |
282 | afterwards. Don't use within `eval-when-compile'." | |
283 | `(progn | |
284 | (eval-when-compile (cc-bytecomp-restore-environment)) | |
285 | (require ,feature) | |
286 | (eval-when-compile (cc-bytecomp-setup-environment)))) | |
287 | ||
130c507e GM |
288 | (defun cc-bytecomp-is-compiling () |
289 | "Return non-nil if eval'ed during compilation. Don't use outside | |
290 | `eval-when-compile'." | |
291 | (and (boundp 'byte-compile-dest-file) | |
292 | (stringp byte-compile-dest-file))) | |
293 | ||
294 | (defmacro cc-bytecomp-defvar (var) | |
295 | "Binds the symbol as a variable during compilation of the file, | |
296 | to silence the byte compiler. Don't use within `eval-when-compile'." | |
297 | `(eval-when-compile | |
298 | (if (boundp ',var) | |
d9e94c22 MS |
299 | (cc-bytecomp-debug-msg |
300 | "cc-bytecomp-defvar: %s bound already as variable" ',var) | |
130c507e | 301 | (if (not (memq ',var cc-bytecomp-unbound-variables)) |
d9e94c22 MS |
302 | (progn |
303 | (cc-bytecomp-debug-msg | |
304 | "cc-bytecomp-defvar: Saving %s (as unbound)" ',var) | |
305 | (setq cc-bytecomp-unbound-variables | |
306 | (cons ',var cc-bytecomp-unbound-variables)))) | |
130c507e | 307 | (if (and (cc-bytecomp-is-compiling) |
d9e94c22 | 308 | (not load-in-progress)) |
130c507e GM |
309 | (progn |
310 | (defvar ,var) | |
d9e94c22 MS |
311 | (set ',var (intern (concat "cc-bytecomp-ignore-var:" |
312 | (symbol-name ',var)))) | |
313 | (cc-bytecomp-debug-msg | |
314 | "cc-bytecomp-defvar: Covered variable %s" ',var)))))) | |
130c507e GM |
315 | |
316 | (defmacro cc-bytecomp-defun (fun) | |
317 | "Bind the symbol as a function during compilation of the file, | |
d9e94c22 MS |
318 | to silence the byte compiler. Don't use within `eval-when-compile'. |
319 | ||
320 | If the symbol already is bound as a function, it will keep that | |
321 | definition. That means that this macro will not shut up warnings | |
322 | about incorrect number of arguments. It's dangerous to try to replace | |
323 | existing functions since the byte compiler might need the definition | |
324 | at compile time, e.g. for macros and inline functions." | |
130c507e | 325 | `(eval-when-compile |
6b5bbb98 | 326 | (if (fboundp ',fun) |
d9e94c22 MS |
327 | (cc-bytecomp-debug-msg |
328 | "cc-bytecomp-defun: %s bound already as function" ',fun) | |
6b5bbb98 | 329 | (if (not (assq ',fun cc-bytecomp-original-functions)) |
d9e94c22 MS |
330 | (progn |
331 | (cc-bytecomp-debug-msg | |
332 | "cc-bytecomp-defun: Saving %s (as unbound)" ',fun) | |
333 | (setq cc-bytecomp-original-functions | |
334 | (cons (list ',fun nil 'unbound) | |
335 | cc-bytecomp-original-functions)))) | |
6b5bbb98 | 336 | (if (and (cc-bytecomp-is-compiling) |
d9e94c22 MS |
337 | (not load-in-progress)) |
338 | (progn | |
339 | (fset ',fun (intern (concat "cc-bytecomp-ignore-fun:" | |
340 | (symbol-name ',fun)))) | |
341 | (cc-bytecomp-debug-msg | |
342 | "cc-bytecomp-defun: Covered function %s" ',fun)))))) | |
130c507e GM |
343 | |
344 | (put 'cc-bytecomp-defmacro 'lisp-indent-function 'defun) | |
345 | (defmacro cc-bytecomp-defmacro (fun &rest temp-macro) | |
346 | "Bind the symbol as a macro during compilation (and evaluation) of the | |
347 | file. Don't use outside `eval-when-compile'." | |
d9e94c22 MS |
348 | `(let ((orig-fun (assq ',fun cc-bytecomp-original-functions))) |
349 | (if (not orig-fun) | |
350 | (setq orig-fun | |
351 | (list ',fun | |
352 | nil | |
353 | (if (fboundp ',fun) | |
354 | (progn | |
355 | (cc-bytecomp-debug-msg | |
356 | "cc-bytecomp-defmacro: Saving %s" ',fun) | |
357 | (symbol-function ',fun)) | |
358 | (cc-bytecomp-debug-msg | |
359 | "cc-bytecomp-defmacro: Saving %s as unbound" ',fun) | |
360 | 'unbound)) | |
361 | cc-bytecomp-original-functions | |
362 | (cons orig-fun cc-bytecomp-original-functions))) | |
363 | (defmacro ,fun ,@temp-macro) | |
364 | (cc-bytecomp-debug-msg | |
365 | "cc-bytecomp-defmacro: Bound macro %s" ',fun) | |
366 | (setcar (cdr orig-fun) (symbol-function ',fun)))) | |
130c507e GM |
367 | |
368 | (defmacro cc-bytecomp-put (symbol propname value) | |
369 | "Set a property on a symbol during compilation (and evaluation) of | |
370 | the file. Don't use outside `eval-when-compile'." | |
d9e94c22 | 371 | `(eval-when-compile |
130c507e | 372 | (if (not (assoc (cons ,symbol ,propname) cc-bytecomp-original-properties)) |
d9e94c22 MS |
373 | (progn |
374 | (cc-bytecomp-debug-msg | |
375 | "cc-bytecomp-put: Saving property %s for %s with value %s" | |
376 | ,propname ,symbol (get ,symbol ,propname)) | |
377 | (setq cc-bytecomp-original-properties | |
378 | (cons (cons (cons ,symbol ,propname) | |
379 | (cons ,value (get ,symbol ,propname))) | |
380 | cc-bytecomp-original-properties)))) | |
381 | (put ,symbol ,propname ,value) | |
382 | (cc-bytecomp-debug-msg | |
383 | "cc-bytecomp-put: Bound property %s for %s to %s" | |
384 | ,propname ,symbol ,value))) | |
130c507e GM |
385 | |
386 | (defmacro cc-bytecomp-obsolete-var (symbol) | |
d9e94c22 | 387 | "Suppress warnings that the given symbol is an obsolete variable. |
130c507e GM |
388 | Don't use within `eval-when-compile'." |
389 | `(eval-when-compile | |
390 | (if (get ',symbol 'byte-obsolete-variable) | |
c0316672 RS |
391 | (cc-bytecomp-put ',symbol 'byte-obsolete-variable nil) |
392 | ;; This avoids a superfluous compiler warning | |
393 | ;; about calling `get' for effect. | |
394 | t))) | |
130c507e GM |
395 | |
396 | (defun cc-bytecomp-ignore-obsolete (form) | |
397 | ;; Wraps a call to `byte-compile-obsolete' that suppresses the warning. | |
5e0b2841 GM |
398 | (let ((byte-compile-warnings byte-compile-warnings)) |
399 | (byte-compile-disable-warning 'obsolete) | |
130c507e GM |
400 | (byte-compile-obsolete form))) |
401 | ||
402 | (defmacro cc-bytecomp-obsolete-fun (symbol) | |
d9e94c22 | 403 | "Suppress warnings that the given symbol is an obsolete function. |
130c507e GM |
404 | Don't use within `eval-when-compile'." |
405 | `(eval-when-compile | |
406 | (if (eq (get ',symbol 'byte-compile) 'byte-compile-obsolete) | |
407 | (cc-bytecomp-put ',symbol 'byte-compile | |
d9e94c22 MS |
408 | 'cc-bytecomp-ignore-obsolete) |
409 | ;; This avoids a superfluous compiler warning | |
410 | ;; about calling `get' for effect. | |
411 | t))) | |
412 | ||
413 | (defmacro cc-bytecomp-boundp (symbol) | |
414 | "Return non-nil if the given symbol is bound as a variable outside | |
415 | the compilation. This is the same as using `boundp' but additionally | |
416 | exclude any variables that have been bound during compilation with | |
417 | `cc-bytecomp-defvar'." | |
418 | (if (and (cc-bytecomp-is-compiling) | |
419 | (memq (car (cdr symbol)) cc-bytecomp-unbound-variables)) | |
420 | nil | |
421 | `(boundp ,symbol))) | |
422 | ||
423 | (defmacro cc-bytecomp-fboundp (symbol) | |
424 | "Return non-nil if the given symbol is bound as a function outside | |
425 | the compilation. This is the same as using `fboundp' but additionally | |
426 | exclude any functions that have been bound during compilation with | |
427 | `cc-bytecomp-defun'." | |
428 | (let (fun-elem) | |
429 | (if (and (cc-bytecomp-is-compiling) | |
430 | (setq fun-elem (assq (car (cdr symbol)) | |
431 | cc-bytecomp-original-functions)) | |
432 | (eq (elt fun-elem 2) 'unbound)) | |
433 | nil | |
434 | `(fboundp ,symbol)))) | |
130c507e GM |
435 | |
436 | \f | |
437 | (provide 'cc-bytecomp) | |
3afbc435 | 438 | |
cbee283d | 439 | ;; arch-tag: 2d71b3ad-57b0-4b13-abd3-ab836e08f975 |
3afbc435 | 440 | ;;; cc-bytecomp.el ends here |