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