cc-bytecomp.el 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. ;;; cc-bytecomp.el --- compile time setup for proper compilation
  2. ;; Copyright (C) 2000-2015 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' and `cc-bytecomp-defvar'.
  61. ;;
  62. ;; This file is not used at all after the package has been byte
  63. ;; compiled. It is however necessary when running uncompiled.
  64. ;;; Code:
  65. (defvar cc-bytecomp-unbound-variables nil)
  66. (defvar cc-bytecomp-original-functions nil)
  67. (defvar cc-bytecomp-original-properties nil)
  68. (defvar cc-bytecomp-loaded-files nil)
  69. (setq cc-bytecomp-unbound-variables nil)
  70. (setq cc-bytecomp-original-functions nil)
  71. (setq cc-bytecomp-original-properties nil)
  72. (setq cc-bytecomp-loaded-files nil)
  73. (defvar cc-bytecomp-environment-set nil)
  74. (defmacro cc-bytecomp-debug-msg (&rest args)
  75. ;;`(message ,@args)
  76. )
  77. (defun cc-bytecomp-compiling-or-loading ()
  78. ;; Determine whether byte-compilation or loading is currently active,
  79. ;; returning 'compiling, 'loading or nil.
  80. ;; If both are active, the "innermost" activity counts. Note that
  81. ;; compilation can trigger loading (various `require' type forms)
  82. ;; and loading can trigger compilation (the package manager does
  83. ;; this). We walk the lisp stack if necessary.
  84. (cond
  85. ((and load-in-progress
  86. (boundp 'byte-compile-dest-file)
  87. (stringp byte-compile-dest-file))
  88. (let ((n 0) elt)
  89. (while (and
  90. (setq elt (backtrace-frame n))
  91. (not (and (car elt)
  92. (memq (cadr elt)
  93. '(load require
  94. byte-compile-file byte-recompile-directory
  95. batch-byte-compile)))))
  96. (setq n (1+ n)))
  97. (cond
  98. ((memq (cadr elt) '(load require))
  99. 'loading)
  100. ((memq (cadr elt) '(byte-compile-file
  101. byte-recompile-directory
  102. batch-byte-compile))
  103. 'compiling)
  104. (t ; Can't happen.
  105. (message "cc-bytecomp-compiling-or-loading: System flags spuriously set")
  106. nil))))
  107. (load-in-progress
  108. ;; Being loaded.
  109. 'loading)
  110. ((and (boundp 'byte-compile-dest-file)
  111. (stringp byte-compile-dest-file))
  112. ;; Being compiled.
  113. 'compiling)
  114. (t
  115. ;; Being evaluated interactively.
  116. nil)))
  117. (defsubst cc-bytecomp-is-compiling ()
  118. "Return non-nil if eval'ed during compilation."
  119. (eq (cc-bytecomp-compiling-or-loading) 'compiling))
  120. (defsubst cc-bytecomp-is-loading ()
  121. "Return non-nil if eval'ed during loading.
  122. Nil will be returned if we're in a compilation triggered by the loading."
  123. (eq (cc-bytecomp-compiling-or-loading) 'loading))
  124. (defun cc-bytecomp-setup-environment ()
  125. ;; Eval'ed during compilation to setup variables, functions etc
  126. ;; declared with `cc-bytecomp-defvar' et al.
  127. (if (not (cc-bytecomp-is-loading))
  128. (let (p)
  129. (if cc-bytecomp-environment-set
  130. (error "Byte compilation environment already set - \
  131. perhaps a `cc-bytecomp-restore-environment' is forgotten somewhere"))
  132. (setq p cc-bytecomp-unbound-variables)
  133. (while p
  134. (if (not (boundp (car p)))
  135. (progn
  136. (eval `(defvar ,(car p)))
  137. (set (car p) (intern (concat "cc-bytecomp-ignore-var:"
  138. (symbol-name (car p)))))
  139. (cc-bytecomp-debug-msg
  140. "cc-bytecomp-setup-environment: Covered variable %s"
  141. (car p))))
  142. (setq p (cdr p)))
  143. (setq p cc-bytecomp-original-functions)
  144. (while p
  145. (let ((fun (car (car p)))
  146. (temp-macro (car (cdr (car p)))))
  147. (if (not (fboundp fun))
  148. (if temp-macro
  149. (progn
  150. (eval `(defmacro ,fun ,@temp-macro))
  151. (cc-bytecomp-debug-msg
  152. "cc-bytecomp-setup-environment: Bound macro %s" fun))
  153. (fset fun (intern (concat "cc-bytecomp-ignore-fun:"
  154. (symbol-name fun))))
  155. (cc-bytecomp-debug-msg
  156. "cc-bytecomp-setup-environment: Covered function %s" fun))))
  157. (setq p (cdr p)))
  158. (setq p cc-bytecomp-original-properties)
  159. (while p
  160. (let ((sym (car (car (car p))))
  161. (prop (cdr (car (car p))))
  162. (tempdef (car (cdr (car p)))))
  163. (put sym prop tempdef)
  164. (cc-bytecomp-debug-msg
  165. "cc-bytecomp-setup-environment: Bound property %s for %s to %s"
  166. prop sym tempdef))
  167. (setq p (cdr p)))
  168. (setq cc-bytecomp-environment-set t)
  169. (cc-bytecomp-debug-msg
  170. "cc-bytecomp-setup-environment: Done"))))
  171. (defun cc-bytecomp-restore-environment ()
  172. ;; Eval'ed during compilation to restore variables, functions etc
  173. ;; declared with `cc-bytecomp-defvar' et al.
  174. (if (not (cc-bytecomp-is-loading))
  175. (let (p)
  176. (setq p cc-bytecomp-unbound-variables)
  177. (while p
  178. (let ((var (car p)))
  179. (if (boundp var)
  180. (if (eq (intern (concat "cc-bytecomp-ignore-var:"
  181. (symbol-name var)))
  182. (symbol-value var))
  183. (progn
  184. (makunbound var)
  185. (cc-bytecomp-debug-msg
  186. "cc-bytecomp-restore-environment: Unbound variable %s"
  187. var))
  188. (cc-bytecomp-debug-msg
  189. "cc-bytecomp-restore-environment: Not restoring variable %s"
  190. var))))
  191. (setq p (cdr p)))
  192. (setq p cc-bytecomp-original-functions)
  193. (while p
  194. (let ((fun (car (car p)))
  195. (temp-macro (car (cdr (car p))))
  196. (def (car (cdr (cdr (car p))))))
  197. (if (fboundp fun)
  198. (if (eq (or temp-macro
  199. (intern (concat "cc-bytecomp-ignore-fun:"
  200. (symbol-name fun))))
  201. (symbol-function fun))
  202. (if (eq def 'unbound)
  203. (progn
  204. (fmakunbound fun)
  205. (cc-bytecomp-debug-msg
  206. "cc-bytecomp-restore-environment: Unbound function %s"
  207. fun))
  208. (fset fun def)
  209. (cc-bytecomp-debug-msg
  210. "cc-bytecomp-restore-environment: Restored function %s"
  211. fun))
  212. (cc-bytecomp-debug-msg
  213. "cc-bytecomp-restore-environment: Not restoring function %s"
  214. fun))))
  215. (setq p (cdr p)))
  216. (setq p cc-bytecomp-original-properties)
  217. (while p
  218. (let ((sym (car (car (car p))))
  219. (prop (cdr (car (car p))))
  220. (tempdef (car (cdr (car p))))
  221. (origdef (cdr (cdr (car p)))))
  222. (if (eq (get sym prop) tempdef)
  223. (progn
  224. (put sym prop origdef)
  225. (cc-bytecomp-debug-msg
  226. "cc-bytecomp-restore-environment: Restored property %s for %s to %s"
  227. prop sym origdef))
  228. (cc-bytecomp-debug-msg
  229. "cc-bytecomp-restore-environment: Not restoring property %s for %s"
  230. prop sym)))
  231. (setq p (cdr p)))
  232. (setq cc-bytecomp-environment-set nil)
  233. (cc-bytecomp-debug-msg
  234. "cc-bytecomp-restore-environment: Done"))))
  235. (eval
  236. ;; This eval is to avoid byte compilation of the function below.
  237. ;; There's some bug in XEmacs 21.4.6 that can cause it to dump core
  238. ;; here otherwise. My theory is that `cc-bytecomp-load' might be
  239. ;; redefined recursively during the `load' inside it, and if it in
  240. ;; that case is byte compiled then the byte interpreter gets
  241. ;; confused. I haven't succeeded in isolating the bug, though. /mast
  242. '(defun cc-bytecomp-load (cc-part)
  243. ;; Eval'ed during compilation to load a CC Mode file from the source
  244. ;; directory (assuming it's the same as the compiled file
  245. ;; destination dir).
  246. (if (and (boundp 'byte-compile-dest-file)
  247. (stringp byte-compile-dest-file))
  248. (progn
  249. (cc-bytecomp-restore-environment)
  250. (let ((load-path
  251. (cons (file-name-directory byte-compile-dest-file)
  252. load-path))
  253. (cc-file (concat cc-part ".el")))
  254. (if (member cc-file cc-bytecomp-loaded-files)
  255. ()
  256. (setq cc-bytecomp-loaded-files
  257. (cons cc-file cc-bytecomp-loaded-files))
  258. (cc-bytecomp-debug-msg
  259. "cc-bytecomp-load: Loading %S" cc-file)
  260. (load cc-file nil t t)
  261. (cc-bytecomp-debug-msg
  262. "cc-bytecomp-load: Loaded %S" cc-file)))
  263. (cc-bytecomp-setup-environment)
  264. t))))
  265. (defvar cc-bytecomp-noruntime-functions nil
  266. "Saved value of `byte-compile-noruntime-functions'.")
  267. (defmacro cc-require (cc-part)
  268. "Force loading of the corresponding .el file in the current directory
  269. during compilation, but compile in a `require'. Don't use within
  270. `eval-when-compile'.
  271. Having cyclic cc-require's will result in infinite recursion. That's
  272. somewhat intentional."
  273. `(progn
  274. (eval-when-compile
  275. (if (boundp 'byte-compile-noruntime-functions) ; in case load uncompiled
  276. (setq cc-bytecomp-noruntime-functions
  277. byte-compile-noruntime-functions))
  278. (cc-bytecomp-load (symbol-name ,cc-part)))
  279. ;; Hack to suppress spurious "might not be defined at runtime" warnings.
  280. ;; The basic issue is that
  281. ;; (eval-when-compile (require 'foo))
  282. ;; (require 'foo)
  283. ;; produces bogus noruntime warnings about functions from foo.
  284. (eval-when-compile
  285. (setq byte-compile-noruntime-functions cc-bytecomp-noruntime-functions))
  286. (require ,cc-part)))
  287. (defmacro cc-provide (feature)
  288. "A replacement for the `provide' form that restores the environment
  289. after the compilation. Don't use within `eval-when-compile'."
  290. `(progn
  291. (eval-when-compile (cc-bytecomp-restore-environment))
  292. (provide ,feature)))
  293. (defmacro cc-load (cc-part)
  294. "Force loading of the corresponding .el file in the current directory
  295. during compilation. Don't use outside `eval-when-compile' or
  296. `eval-and-compile'.
  297. Having cyclic cc-load's will result in infinite recursion. That's
  298. somewhat intentional."
  299. `(or (and (featurep 'cc-bytecomp)
  300. (cc-bytecomp-load ,cc-part))
  301. (load ,cc-part nil t nil)))
  302. (defmacro cc-require-when-compile (cc-part)
  303. "Force loading of the corresponding .el file in the current directory
  304. during compilation, but do a compile time `require' otherwise. Don't
  305. use within `eval-when-compile'."
  306. `(eval-when-compile
  307. (if (and (fboundp 'cc-bytecomp-is-compiling)
  308. (cc-bytecomp-is-compiling))
  309. (if (not (featurep ,cc-part))
  310. (cc-bytecomp-load (symbol-name ,cc-part)))
  311. (require ,cc-part))))
  312. (defmacro cc-external-require (feature)
  313. "Do a `require' of an external package.
  314. This restores and sets up the compilation environment before and
  315. afterwards. Don't use within `eval-when-compile'."
  316. `(progn
  317. (eval-when-compile (cc-bytecomp-restore-environment))
  318. (require ,feature)
  319. (eval-when-compile (cc-bytecomp-setup-environment))))
  320. (defmacro cc-bytecomp-defvar (var)
  321. "Binds the symbol as a variable during compilation of the file,
  322. to silence the byte compiler. Don't use within `eval-when-compile'."
  323. `(eval-when-compile
  324. (if (boundp ',var)
  325. (cc-bytecomp-debug-msg
  326. "cc-bytecomp-defvar: %s bound already as variable" ',var)
  327. (if (not (memq ',var cc-bytecomp-unbound-variables))
  328. (progn
  329. (cc-bytecomp-debug-msg
  330. "cc-bytecomp-defvar: Saving %s (as unbound)" ',var)
  331. (setq cc-bytecomp-unbound-variables
  332. (cons ',var cc-bytecomp-unbound-variables))))
  333. (if (cc-bytecomp-is-compiling)
  334. (progn
  335. (defvar ,var)
  336. (set ',var (intern (concat "cc-bytecomp-ignore-var:"
  337. (symbol-name ',var))))
  338. (cc-bytecomp-debug-msg
  339. "cc-bytecomp-defvar: Covered variable %s" ',var))))))
  340. (defmacro cc-bytecomp-defun (fun)
  341. "Bind the symbol as a function during compilation of the file,
  342. to silence the byte compiler. Don't use within `eval-when-compile'.
  343. If the symbol already is bound as a function, it will keep that
  344. definition. That means that this macro will not shut up warnings
  345. about incorrect number of arguments. It's dangerous to try to replace
  346. existing functions since the byte compiler might need the definition
  347. at compile time, e.g. for macros and inline functions."
  348. `(eval-when-compile
  349. (if (fboundp ',fun)
  350. (cc-bytecomp-debug-msg
  351. "cc-bytecomp-defun: %s bound already as function" ',fun)
  352. (if (not (assq ',fun cc-bytecomp-original-functions))
  353. (progn
  354. (cc-bytecomp-debug-msg
  355. "cc-bytecomp-defun: Saving %s (as unbound)" ',fun)
  356. (setq cc-bytecomp-original-functions
  357. (cons (list ',fun nil 'unbound)
  358. cc-bytecomp-original-functions))))
  359. (if (cc-bytecomp-is-compiling)
  360. (progn
  361. (fset ',fun (intern (concat "cc-bytecomp-ignore-fun:"
  362. (symbol-name ',fun))))
  363. (cc-bytecomp-debug-msg
  364. "cc-bytecomp-defun: Covered function %s" ',fun))))))
  365. (defmacro cc-bytecomp-put (symbol propname value)
  366. "Set a property on a symbol during compilation (and evaluation) of
  367. the file. Don't use outside `eval-when-compile'."
  368. `(eval-when-compile
  369. (if (not (assoc (cons ,symbol ,propname) cc-bytecomp-original-properties))
  370. (progn
  371. (cc-bytecomp-debug-msg
  372. "cc-bytecomp-put: Saving property %s for %s with value %s"
  373. ,propname ,symbol (get ,symbol ,propname))
  374. (setq cc-bytecomp-original-properties
  375. (cons (cons (cons ,symbol ,propname)
  376. (cons ,value (get ,symbol ,propname)))
  377. cc-bytecomp-original-properties))))
  378. (put ,symbol ,propname ,value)
  379. (cc-bytecomp-debug-msg
  380. "cc-bytecomp-put: Bound property %s for %s to %s"
  381. ,propname ,symbol ,value)))
  382. (defmacro cc-bytecomp-boundp (symbol)
  383. "Return non-nil if the given symbol is bound as a variable outside
  384. the compilation. This is the same as using `boundp' but additionally
  385. exclude any variables that have been bound during compilation with
  386. `cc-bytecomp-defvar'."
  387. (if (and (cc-bytecomp-is-compiling)
  388. (memq (car (cdr symbol)) cc-bytecomp-unbound-variables))
  389. nil
  390. `(boundp ,symbol)))
  391. (defmacro cc-bytecomp-fboundp (symbol)
  392. "Return non-nil if the given symbol is bound as a function outside
  393. the compilation. This is the same as using `fboundp' but additionally
  394. exclude any functions that have been bound during compilation with
  395. `cc-bytecomp-defun'."
  396. (let (fun-elem)
  397. (if (and (cc-bytecomp-is-compiling)
  398. (setq fun-elem (assq (car (cdr symbol))
  399. cc-bytecomp-original-functions))
  400. (eq (elt fun-elem 2) 'unbound))
  401. nil
  402. `(fboundp ,symbol))))
  403. (provide 'cc-bytecomp)
  404. ;; Local Variables:
  405. ;; indent-tabs-mode: t
  406. ;; tab-width: 8
  407. ;; End:
  408. ;;; cc-bytecomp.el ends here