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