| 1 | ;;; cc-bytecomp.el --- compile time setup for proper compilation |
| 2 | |
| 3 | ;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 |
| 4 | ;; Free Software Foundation, Inc. |
| 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 | |
| 12 | ;; This file is part of GNU Emacs. |
| 13 | |
| 14 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
| 15 | ;; it under the terms of the GNU General Public License as published by |
| 16 | ;; the Free Software Foundation, either version 3 of the License, or |
| 17 | ;; (at your option) any later version. |
| 18 | |
| 19 | ;; GNU Emacs is distributed in the hope that it will be useful, |
| 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 |
| 25 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
| 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. |
| 33 | ;; |
| 34 | ;; There's really nothing CC Mode specific here; this functionality |
| 35 | ;; ought to be provided by the byte compilers or some accompanying |
| 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. |
| 74 | |
| 75 | \f |
| 76 | ;;; Code: |
| 77 | |
| 78 | (defvar cc-bytecomp-unbound-variables nil) |
| 79 | (defvar cc-bytecomp-original-functions nil) |
| 80 | (defvar cc-bytecomp-original-properties nil) |
| 81 | (defvar cc-bytecomp-loaded-files nil) |
| 82 | (defvar cc-bytecomp-environment-set nil) |
| 83 | |
| 84 | (defmacro cc-bytecomp-debug-msg (&rest args) |
| 85 | ;;`(message ,@args) |
| 86 | ) |
| 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. |
| 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. |
| 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))) |
| 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)))) |
| 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))))) |
| 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)))) |
| 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))))) |
| 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)) |
| 134 | (setq p (cdr p))) |
| 135 | (setq cc-bytecomp-environment-set t) |
| 136 | (cc-bytecomp-debug-msg |
| 137 | "cc-bytecomp-setup-environment: Done")))) |
| 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. |
| 142 | (if (not load-in-progress) |
| 143 | (let (p) |
| 144 | (setq p cc-bytecomp-unbound-variables) |
| 145 | (while p |
| 146 | (let ((var (car p))) |
| 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)))) |
| 159 | (setq p (cdr p))) |
| 160 | (setq p cc-bytecomp-original-functions) |
| 161 | (while p |
| 162 | (let ((fun (car (car p))) |
| 163 | (temp-macro (car (cdr (car p)))) |
| 164 | (def (car (cdr (cdr (car p)))))) |
| 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)))) |
| 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) |
| 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))) |
| 199 | (setq p (cdr p))) |
| 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)))) |
| 235 | |
| 236 | (defmacro cc-require (cc-part) |
| 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'. |
| 240 | |
| 241 | Having cyclic cc-require's will result in infinite recursion. That's |
| 242 | somewhat intentional." |
| 243 | `(progn |
| 244 | (eval-when-compile (cc-bytecomp-load (symbol-name ,cc-part))) |
| 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) |
| 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'. |
| 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 | |
| 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 | |
| 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) |
| 297 | (cc-bytecomp-debug-msg |
| 298 | "cc-bytecomp-defvar: %s bound already as variable" ',var) |
| 299 | (if (not (memq ',var cc-bytecomp-unbound-variables)) |
| 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)))) |
| 305 | (if (and (cc-bytecomp-is-compiling) |
| 306 | (not load-in-progress)) |
| 307 | (progn |
| 308 | (defvar ,var) |
| 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)))))) |
| 313 | |
| 314 | (defmacro cc-bytecomp-defun (fun) |
| 315 | "Bind the symbol as a function during compilation of the file, |
| 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." |
| 323 | `(eval-when-compile |
| 324 | (if (fboundp ',fun) |
| 325 | (cc-bytecomp-debug-msg |
| 326 | "cc-bytecomp-defun: %s bound already as function" ',fun) |
| 327 | (if (not (assq ',fun cc-bytecomp-original-functions)) |
| 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)))) |
| 334 | (if (and (cc-bytecomp-is-compiling) |
| 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)))))) |
| 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'." |
| 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)))) |
| 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'." |
| 369 | `(eval-when-compile |
| 370 | (if (not (assoc (cons ,symbol ,propname) cc-bytecomp-original-properties)) |
| 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))) |
| 383 | |
| 384 | (defmacro cc-bytecomp-obsolete-var (symbol) |
| 385 | "Suppress warnings that the given symbol is an obsolete variable. |
| 386 | Don't use within `eval-when-compile'." |
| 387 | `(eval-when-compile |
| 388 | (if (get ',symbol 'byte-obsolete-variable) |
| 389 | (cc-bytecomp-put ',symbol 'byte-obsolete-variable nil) |
| 390 | ;; This avoids a superfluous compiler warning |
| 391 | ;; about calling `get' for effect. |
| 392 | t))) |
| 393 | |
| 394 | (defun cc-bytecomp-ignore-obsolete (form) |
| 395 | ;; Wraps a call to `byte-compile-obsolete' that suppresses the warning. |
| 396 | (let ((byte-compile-warnings byte-compile-warnings)) |
| 397 | (byte-compile-disable-warning 'obsolete) |
| 398 | (byte-compile-obsolete form))) |
| 399 | |
| 400 | (defmacro cc-bytecomp-obsolete-fun (symbol) |
| 401 | "Suppress warnings that the given symbol is an obsolete function. |
| 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 |
| 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)))) |
| 433 | |
| 434 | \f |
| 435 | (provide 'cc-bytecomp) |
| 436 | |
| 437 | ;; arch-tag: 2d71b3ad-57b0-4b13-abd3-ab836e08f975 |
| 438 | ;;; cc-bytecomp.el ends here |