1 ;;; cc-bytecomp.el --- compile time setup for proper compilation
3 ;; Copyright (C) 2000, 01 Free Software Foundation, Inc.
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
11 ;; This file is part of GNU Emacs.
13 ;; GNU Emacs is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
18 ;; GNU Emacs is distributed in the hope that it will be useful,
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.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
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.
38 (defvar cc-bytecomp-unbound-variables nil
)
39 (defvar cc-bytecomp-original-functions nil
)
40 (defvar cc-bytecomp-original-properties nil
)
41 (defvar cc-bytecomp-load-depth
0)
42 (defvar cc-bytecomp-loaded-files nil
)
43 (defvar cc-bytecomp-environment-set nil
)
45 (put 'cc-eval-when-compile
'lisp-indent-hook
0)
46 (defmacro cc-eval-when-compile
(&rest body
)
47 "Like `progn', but evaluates the body at compile time.
48 The result of the body appears to the compiler as a quoted constant.
50 This variant works around what looks like a bug in
51 `eval-when-compile': During byte compilation it byte compiles its
52 contents before evaluating it. That can cause forms to be compiled in
53 situations they aren't intended to be compiled. See cc-bytecomp.el
54 for further discussion."
56 ;; Example: It's not possible to defsubst a primitive, e.g. the
57 ;; following will produce an error (in any emacs flavor), since
58 ;; `nthcdr' is a primitive function that's handled specially by the
59 ;; byte compiler and thus can't be redefined:
61 ;; (defsubst nthcdr (val) val)
63 ;; `defsubst', like `defmacro', needs to be evaluated at compile
64 ;; time, so this will produce an error during byte compilation.
66 ;; CC Mode occasionally needs to do things like this for cross-emacs
67 ;; compatibility (although we try to avoid it since it results in
68 ;; byte code that isn't compatible between emacsen). It therefore
69 ;; uses the following to conditionally do a `defsubst':
72 ;; (if (not (fboundp 'foo))
73 ;; (defsubst foo ...)))
75 ;; But `eval-when-compile' byte compiles its contents and _then_
76 ;; evaluates it (in all current emacs versions, up to and including
77 ;; Emacs 20.6 and XEmacs 21.1 as of this writing). So this will
78 ;; still produce an error, since the byte compiler will get to the
79 ;; defsubst anyway. That's arguably a bug because the point with
80 ;; `eval-when-compile' is that it should evaluate rather than
81 ;; compile its contents.
82 `(eval-when-compile (eval '(progn ,@body
))))
84 (defun cc-bytecomp-setup-environment ()
85 ;; Eval'ed during compilation to setup variables, functions etc
86 ;; declared with `cc-bytecomp-defvar' et al.
87 (if (= cc-bytecomp-load-depth
0)
89 (if cc-bytecomp-environment-set
90 (error "Byte compilation environment already set - \
91 perhaps a `cc-bytecomp-restore-environment' is forgotten somewhere"))
92 (setq p cc-bytecomp-unbound-variables
)
94 (if (not (boundp (car p
)))
96 (eval `(defvar ,(car p
)))
97 (set (car p
) 'cc-bytecomp-ignore
)))
99 (setq p cc-bytecomp-original-functions
)
101 (let ((fun (car (car p
)))
102 (temp-macro (car (cdr (car p
)))))
104 (eval `(defmacro ,fun
,@temp-macro
))
105 (fset fun
'cc-bytecomp-ignore
)))
107 (setq p cc-bytecomp-original-properties
)
109 (let ((sym (car (car (car p
))))
110 (prop (cdr (car (car p
))))
111 (tempdef (car (cdr (car p
)))))
112 (put sym prop tempdef
))
114 (setq cc-bytecomp-environment-set t
))))
116 (defun cc-bytecomp-restore-environment ()
117 ;; Eval'ed during compilation to restore variables, functions etc
118 ;; declared with `cc-bytecomp-defvar' et al.
119 (if (= cc-bytecomp-load-depth
0)
121 (setq p cc-bytecomp-unbound-variables
)
124 (if (and (boundp var
)
125 (eq var
'cc-bytecomp-ignore
))
128 (setq p cc-bytecomp-original-functions
)
130 (let ((fun (car (car p
)))
131 (def (car (cdr (cdr (car p
))))))
132 (if (and (fboundp fun
)
133 (eq (symbol-function fun
) 'cc-bytecomp-ignore
))
134 (if (eq def
'unbound
)
138 (setq p cc-bytecomp-original-properties
)
140 (let ((sym (car (car (car p
))))
141 (prop (cdr (car (car p
))))
142 (tempdef (car (cdr (car p
))))
143 (origdef (cdr (cdr (car p
)))))
144 (if (eq (get sym prop
) tempdef
)
145 (put sym prop origdef
)))
147 (setq cc-bytecomp-environment-set nil
))))
149 (defun cc-bytecomp-load (cc-part)
150 ;; Eval'ed during compilation to load a CC Mode file from the source
151 ;; directory (assuming it's the same as the compiled file
153 (if (and (boundp 'byte-compile-dest-file
)
154 (stringp byte-compile-dest-file
))
156 (cc-bytecomp-restore-environment)
157 (let ((cc-bytecomp-load-depth (1+ cc-bytecomp-load-depth
))
159 (cons (file-name-directory byte-compile-dest-file
)
161 (cc-file (concat cc-part
".el")))
162 (if (member cc-file cc-bytecomp-loaded-files
)
164 (setq cc-bytecomp-loaded-files
165 (cons cc-file cc-bytecomp-loaded-files
))
166 (load cc-file nil t t
)))
167 (cc-bytecomp-setup-environment)
170 (defmacro cc-require
(cc-part)
171 "Force loading of the corresponding .el file in the current
172 directory during compilation, but compile in a `require'. Don't use
173 within `eval-when-compile'.
175 Having cyclic cc-require's will result in infinite recursion. That's
176 somewhat intentional."
178 (cc-eval-when-compile (cc-bytecomp-load (symbol-name ,cc-part
)))
181 (defmacro cc-provide
(feature)
182 "A replacement for the `provide' form that restores the environment
183 after the compilation. Don't use within `eval-when-compile'."
185 (eval-when-compile (cc-bytecomp-restore-environment))
188 (defmacro cc-load
(cc-part)
189 "Force loading of the corresponding .el file in the current
190 directory during compilation. Don't use outside `eval-when-compile'
191 or `eval-and-compile'.
193 Having cyclic cc-load's will result in infinite recursion. That's
194 somewhat intentional."
195 `(or (and (featurep 'cc-bytecomp
)
196 (cc-bytecomp-load ,cc-part
))
197 (load ,cc-part nil t nil
)))
199 (defun cc-bytecomp-is-compiling ()
200 "Return non-nil if eval'ed during compilation. Don't use outside
201 `eval-when-compile'."
202 (and (boundp 'byte-compile-dest-file
)
203 (stringp byte-compile-dest-file
)))
205 (defmacro cc-bytecomp-defvar
(var)
206 "Binds the symbol as a variable during compilation of the file,
207 to silence the byte compiler. Don't use within `eval-when-compile'."
211 (if (not (memq ',var cc-bytecomp-unbound-variables
))
212 (setq cc-bytecomp-unbound-variables
213 (cons ',var cc-bytecomp-unbound-variables
)))
214 (if (and (cc-bytecomp-is-compiling)
215 (= cc-bytecomp-load-depth
0))
218 (set ',var
'cc-bytecomp-ignore
))))))
220 (defmacro cc-bytecomp-defun
(fun)
221 "Bind the symbol as a function during compilation of the file,
222 to silence the byte compiler. Don't use within `eval-when-compile'."
224 (if (not (assq ',fun cc-bytecomp-original-functions
))
225 (setq cc-bytecomp-original-functions
229 (symbol-function ',fun
)
231 cc-bytecomp-original-functions
)))
232 (if (and (cc-bytecomp-is-compiling)
233 (= cc-bytecomp-load-depth
0)
234 (not (fboundp ',fun
)))
235 (fset ',fun
'cc-bytecomp-ignore
))))
237 (put 'cc-bytecomp-defmacro
'lisp-indent-function
'defun
)
238 (defmacro cc-bytecomp-defmacro
(fun &rest temp-macro
)
239 "Bind the symbol as a macro during compilation (and evaluation) of the
240 file. Don't use outside `eval-when-compile'."
242 (if (not (assq ',fun cc-bytecomp-original-functions
))
243 (setq cc-bytecomp-original-functions
247 (symbol-function ',fun
)
249 cc-bytecomp-original-functions
)))
250 (defmacro ,fun
,@temp-macro
)))
252 (defmacro cc-bytecomp-put
(symbol propname value
)
253 "Set a property on a symbol during compilation (and evaluation) of
254 the file. Don't use outside `eval-when-compile'."
255 `(cc-eval-when-compile
256 (if (not (assoc (cons ,symbol
,propname
) cc-bytecomp-original-properties
))
257 (setq cc-bytecomp-original-properties
258 (cons (cons (cons ,symbol
,propname
)
259 (cons ,value
(get ,symbol
,propname
)))
260 cc-bytecomp-original-properties
)))
261 (put ,symbol
,propname
,value
)))
263 (defmacro cc-bytecomp-obsolete-var
(symbol)
264 "Suppress warnings about that the given symbol is an obsolete variable.
265 Don't use within `eval-when-compile'."
267 (if (get ',symbol
'byte-obsolete-variable
)
268 (cc-bytecomp-put ',symbol
'byte-obsolete-variable nil
))))
270 (defun cc-bytecomp-ignore-obsolete (form)
271 ;; Wraps a call to `byte-compile-obsolete' that suppresses the warning.
272 (let ((byte-compile-warnings
273 (delq 'obsolete
(append byte-compile-warnings nil
))))
274 (byte-compile-obsolete form
)))
276 (defmacro cc-bytecomp-obsolete-fun
(symbol)
277 "Suppress warnings about that the given symbol is an obsolete function.
278 Don't use within `eval-when-compile'."
280 (if (eq (get ',symbol
'byte-compile
) 'byte-compile-obsolete
)
281 (cc-bytecomp-put ',symbol
'byte-compile
282 'cc-bytecomp-ignore-obsolete
))))
284 ;; Override ourselves with a version loaded from source if we're
285 ;; compiling, like cc-require does for all the other files.
286 (if (and (cc-bytecomp-is-compiling)
287 (= cc-bytecomp-load-depth
0))
289 (cons (file-name-directory byte-compile-dest-file
) load-path
))
290 (cc-bytecomp-load-depth 1))
291 (load "cc-bytecomp.el" nil t t
)))
294 (provide 'cc-bytecomp
)
296 ;;; cc-bytecomp.el ends here