cc-bytecomp.el 16 KB

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