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
25 ;; the 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.
35 ;; There's really nothing CC Mode specific here; this functionality
36 ;; ought to be provided by the byte compilers or some accompanying
42 (defvar cc-bytecomp-unbound-variables nil
)
43 (defvar cc-bytecomp-original-functions nil
)
44 (defvar cc-bytecomp-original-properties nil
)
45 (defvar cc-bytecomp-load-depth
0)
46 (defvar cc-bytecomp-loaded-files nil
)
47 (defvar cc-bytecomp-environment-set nil
)
49 (put 'cc-eval-when-compile
'lisp-indent-hook
0)
50 (defmacro cc-eval-when-compile
(&rest body
)
51 "Like `progn', but evaluates the body at compile time.
52 The result of the body appears to the compiler as a quoted constant.
54 This variant works around what looks like a bug in
55 `eval-when-compile': During byte compilation it byte compiles its
56 contents before evaluating it. That can cause forms to be compiled in
57 situations they aren't intended to be compiled. See cc-bytecomp.el
58 for further discussion."
60 ;; Example: It's not possible to defsubst a primitive, e.g. the
61 ;; following will produce an error (in any emacs flavor), since
62 ;; `nthcdr' is a primitive function that's handled specially by the
63 ;; byte compiler and thus can't be redefined:
65 ;; (defsubst nthcdr (val) val)
67 ;; `defsubst', like `defmacro', needs to be evaluated at compile
68 ;; time, so this will produce an error during byte compilation.
70 ;; CC Mode occasionally needs to do things like this for cross-emacs
71 ;; compatibility (although we try to avoid it since it results in
72 ;; byte code that isn't compatible between emacsen). It therefore
73 ;; uses the following to conditionally do a `defsubst':
76 ;; (if (not (fboundp 'foo))
77 ;; (defsubst foo ...)))
79 ;; But `eval-when-compile' byte compiles its contents and _then_
80 ;; evaluates it (in all current emacs versions, up to and including
81 ;; Emacs 20.6 and XEmacs 21.1 as of this writing). So this will
82 ;; still produce an error, since the byte compiler will get to the
83 ;; defsubst anyway. That's arguably a bug because the point with
84 ;; `eval-when-compile' is that it should evaluate rather than
85 ;; compile its contents.
86 `(eval-when-compile (eval '(progn ,@body
))))
88 (defun cc-bytecomp-setup-environment ()
89 ;; Eval'ed during compilation to setup variables, functions etc
90 ;; declared with `cc-bytecomp-defvar' et al.
91 (if (= cc-bytecomp-load-depth
0)
93 (if cc-bytecomp-environment-set
94 (error "Byte compilation environment already set - \
95 perhaps a `cc-bytecomp-restore-environment' is forgotten somewhere"))
96 (setq p cc-bytecomp-unbound-variables
)
98 (if (not (boundp (car p
)))
100 (eval `(defvar ,(car p
)))
101 (set (car p
) 'cc-bytecomp-ignore
)))
103 (setq p cc-bytecomp-original-functions
)
105 (let ((fun (car (car p
)))
106 (temp-macro (car (cdr (car p
)))))
108 (eval `(defmacro ,fun
,@temp-macro
))
109 (fset fun
'cc-bytecomp-ignore
)))
111 (setq p cc-bytecomp-original-properties
)
113 (let ((sym (car (car (car p
))))
114 (prop (cdr (car (car p
))))
115 (tempdef (car (cdr (car p
)))))
116 (put sym prop tempdef
))
118 (setq cc-bytecomp-environment-set t
))))
120 (defun cc-bytecomp-restore-environment ()
121 ;; Eval'ed during compilation to restore variables, functions etc
122 ;; declared with `cc-bytecomp-defvar' et al.
123 (if (= cc-bytecomp-load-depth
0)
125 (setq p cc-bytecomp-unbound-variables
)
128 (if (and (boundp var
)
129 (eq var
'cc-bytecomp-ignore
))
132 (setq p cc-bytecomp-original-functions
)
134 (let ((fun (car (car p
)))
135 (def (car (cdr (cdr (car p
))))))
136 (if (and (fboundp fun
)
137 (eq (symbol-function fun
) 'cc-bytecomp-ignore
))
138 (if (eq def
'unbound
)
142 (setq p cc-bytecomp-original-properties
)
144 (let ((sym (car (car (car p
))))
145 (prop (cdr (car (car p
))))
146 (tempdef (car (cdr (car p
))))
147 (origdef (cdr (cdr (car p
)))))
148 (if (eq (get sym prop
) tempdef
)
149 (put sym prop origdef
)))
151 (setq cc-bytecomp-environment-set nil
))))
153 (defun cc-bytecomp-load (cc-part)
154 ;; Eval'ed during compilation to load a CC Mode file from the source
155 ;; directory (assuming it's the same as the compiled file
157 (if (and (boundp 'byte-compile-dest-file
)
158 (stringp byte-compile-dest-file
))
160 (cc-bytecomp-restore-environment)
161 (let ((cc-bytecomp-load-depth (1+ cc-bytecomp-load-depth
))
163 (cons (file-name-directory byte-compile-dest-file
)
165 (cc-file (concat cc-part
".el")))
166 (if (member cc-file cc-bytecomp-loaded-files
)
168 (setq cc-bytecomp-loaded-files
169 (cons cc-file cc-bytecomp-loaded-files
))
170 (load cc-file nil t t
)))
171 (cc-bytecomp-setup-environment)
174 (defmacro cc-require
(cc-part)
175 "Force loading of the corresponding .el file in the current
176 directory during compilation, but compile in a `require'. Don't use
177 within `eval-when-compile'.
179 Having cyclic cc-require's will result in infinite recursion. That's
180 somewhat intentional."
182 (cc-eval-when-compile (cc-bytecomp-load (symbol-name ,cc-part
)))
185 (defmacro cc-provide
(feature)
186 "A replacement for the `provide' form that restores the environment
187 after the compilation. Don't use within `eval-when-compile'."
189 (eval-when-compile (cc-bytecomp-restore-environment))
192 (defmacro cc-load
(cc-part)
193 "Force loading of the corresponding .el file in the current
194 directory during compilation. Don't use outside `eval-when-compile'
195 or `eval-and-compile'.
197 Having cyclic cc-load's will result in infinite recursion. That's
198 somewhat intentional."
199 `(or (and (featurep 'cc-bytecomp
)
200 (cc-bytecomp-load ,cc-part
))
201 (load ,cc-part nil t nil
)))
203 (defun cc-bytecomp-is-compiling ()
204 "Return non-nil if eval'ed during compilation. Don't use outside
205 `eval-when-compile'."
206 (and (boundp 'byte-compile-dest-file
)
207 (stringp byte-compile-dest-file
)))
209 (defmacro cc-bytecomp-defvar
(var)
210 "Binds the symbol as a variable during compilation of the file,
211 to silence the byte compiler. Don't use within `eval-when-compile'."
215 (if (not (memq ',var cc-bytecomp-unbound-variables
))
216 (setq cc-bytecomp-unbound-variables
217 (cons ',var cc-bytecomp-unbound-variables
)))
218 (if (and (cc-bytecomp-is-compiling)
219 (= cc-bytecomp-load-depth
0))
222 (set ',var
'cc-bytecomp-ignore
))))))
224 (defmacro cc-bytecomp-defun
(fun)
225 "Bind the symbol as a function during compilation of the file,
226 to silence the byte compiler. Don't use within `eval-when-compile'."
230 (if (not (assq ',fun cc-bytecomp-original-functions
))
231 (setq cc-bytecomp-original-functions
232 (cons (list ',fun nil
'unbound
)
233 cc-bytecomp-original-functions
)))
234 (if (and (cc-bytecomp-is-compiling)
235 (= cc-bytecomp-load-depth
0))
236 (fset ',fun
'cc-bytecomp-ignore
)))))
238 (put 'cc-bytecomp-defmacro
'lisp-indent-function
'defun
)
239 (defmacro cc-bytecomp-defmacro
(fun &rest temp-macro
)
240 "Bind the symbol as a macro during compilation (and evaluation) of the
241 file. Don't use outside `eval-when-compile'."
243 (if (not (assq ',fun cc-bytecomp-original-functions
))
244 (setq cc-bytecomp-original-functions
248 (symbol-function ',fun
)
250 cc-bytecomp-original-functions
)))
251 (defmacro ,fun
,@temp-macro
)))
253 (defmacro cc-bytecomp-put
(symbol propname value
)
254 "Set a property on a symbol during compilation (and evaluation) of
255 the file. Don't use outside `eval-when-compile'."
256 `(cc-eval-when-compile
257 (if (not (assoc (cons ,symbol
,propname
) cc-bytecomp-original-properties
))
258 (setq cc-bytecomp-original-properties
259 (cons (cons (cons ,symbol
,propname
)
260 (cons ,value
(get ,symbol
,propname
)))
261 cc-bytecomp-original-properties
)))
262 (put ,symbol
,propname
,value
)))
264 (defmacro cc-bytecomp-obsolete-var
(symbol)
265 "Suppress warnings about that the given symbol is an obsolete variable.
266 Don't use within `eval-when-compile'."
268 (if (get ',symbol
'byte-obsolete-variable
)
269 (cc-bytecomp-put ',symbol
'byte-obsolete-variable nil
)
270 ;; This avoids a superfluous compiler warning
271 ;; about calling `get' for effect.
274 (defun cc-bytecomp-ignore-obsolete (form)
275 ;; Wraps a call to `byte-compile-obsolete' that suppresses the warning.
276 (let ((byte-compile-warnings
277 (delq 'obsolete
(append byte-compile-warnings nil
))))
278 (byte-compile-obsolete form
)))
280 (defmacro cc-bytecomp-obsolete-fun
(symbol)
281 "Suppress warnings about that the given symbol is an obsolete function.
282 Don't use within `eval-when-compile'."
284 (if (eq (get ',symbol
'byte-compile
) 'byte-compile-obsolete
)
285 (cc-bytecomp-put ',symbol
'byte-compile
286 'cc-bytecomp-ignore-obsolete
))))
288 ;; Override ourselves with a version loaded from source if we're
289 ;; compiling, like cc-require does for all the other files.
290 (if (and (cc-bytecomp-is-compiling)
291 (= cc-bytecomp-load-depth
0))
293 (cons (file-name-directory byte-compile-dest-file
) load-path
))
294 (cc-bytecomp-load-depth 1))
295 (load "cc-bytecomp.el" nil t t
)))
298 (provide 'cc-bytecomp
)
300 ;;; cc-bytecomp.el ends here