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