blob: ef7bc88efd28a716f8fd86fc716c0c9985dd8cd6 [file] [log] [blame]
Nicolas Catania4a5dc7e2009-10-09 09:24:42 -07001;;; android-compile.el --- Compile the Android source tree.
2;;
3;; Copyright (C) 2009 The Android Open Source Project
4;;
5;; Licensed under the Apache License, Version 2.0 (the "License");
6;; you may not use this file except in compliance with the License.
7;; You may obtain a copy of the License at
8;;
9;; http://www.apache.org/licenses/LICENSE-2.0
10;;
11;; Unless required by applicable law or agreed to in writing, software
12;; distributed under the License is distributed on an "AS IS" BASIS,
13;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14;; See the License for the specific language governing permissions and
15;; limitations under the License.
Nicolas Catania19252812009-10-05 14:49:14 -070016
Nicolas Catania4a5dc7e2009-10-09 09:24:42 -070017;;; Commentary:
18;;
19;; Helper functions to compile Android file within emacs.
20;; This module ignores 'build/envsetup.sh' and any enviroment set by the
21;; 'lunch' shell function.
22;; Instead it relies solely on 'buildspec.mk', remember that when you
23;; switch configuration.
24;;
25;; The only interactive function is 'android-compile'.
26;; In your .emacs load this file (e.g (require 'android-compile)) then:
27;;
28;; (add-hook 'c++-mode-hook 'android-compile)
29;; (add-hook 'java-mode-hook 'android-compile)
30;; and/or
31;; (global-set-key [f9] 'android-compile)
32;;
33;;
34;; TODO: Maybe we could cache the result of the compile function in
35;; buffer local vars.
Nicolas Catania19252812009-10-05 14:49:14 -070036
Nicolas Catania4a5dc7e2009-10-09 09:24:42 -070037;;; Code:
Nicolas Catania19252812009-10-05 14:49:14 -070038
39(require 'compile)
Nicolas Cataniaf94bca22009-10-06 10:45:44 -070040(require 'android-common)
Nicolas Catania19252812009-10-05 14:49:14 -070041
Nicolas Cataniadf098ce2009-10-15 10:48:01 -070042;; No need to be customized.
43(defvar android-compile-ignore-re
44 "\\(^\\(\\sw\\|[/_]\\)+\\(Makefile\\|\\.mk\\):[0-9]+:.*warning\\)\\|\\(^/bin/bash\\)"
45 "RE to match line to suppress during a compilation.
46During the compilation process line matching the above will be
47suppressed if `android-compilation-no-buildenv-warning' is non nil.")
48
Nicolas Catania4a5dc7e2009-10-09 09:24:42 -070049(defun android-makefile-exists-p (directory)
50 "Return t if an Android makefile exists in DIRECTORY."
51 ; Test for Android.mk first: more likely.
52 (or (file-exists-p (concat directory "Android.mk"))
53 (file-exists-p (concat directory "Makefile"))))
54
Nicolas Catania19252812009-10-05 14:49:14 -070055(defun android-find-makefile (topdir)
56 "Ascend the current path until an Android makefile is found.
57Makefiles are named Android.mk except in the root directory where
58the file is named Makefile.
59TOPDIR is the root directory of the build.
60Return a list with 2 elements (MAKEFILE_PATH IS_ROOT_MAKEFILE).
Nicolas Catania4a5dc7e2009-10-09 09:24:42 -070061MAKEFILE_PATH is the relative path of the makefile wrt TOPDIR.
Nicolas Catania19252812009-10-05 14:49:14 -070062Signal an error if no Makefile was found."
Nicolas Catania4a5dc7e2009-10-09 09:24:42 -070063 ;; TODO: Could check that topdir is the start of default-directory.
64 (unless (> (length topdir) 2)
65 (error "Topdir invalid %s for current dir %s" topdir default-directory))
66 (let ((default-directory default-directory)
67 file)
68 ;; Ascend the path.
Nicolas Catania19252812009-10-05 14:49:14 -070069 (while (and (> (length default-directory) (length topdir))
Nicolas Catania4a5dc7e2009-10-09 09:24:42 -070070 (not (android-makefile-exists-p default-directory)))
Nicolas Catania19252812009-10-05 14:49:14 -070071 (setq default-directory
72 (substring default-directory 0
73 (string-match "[^/]+/$" default-directory))))
Nicolas Catania4a5dc7e2009-10-09 09:24:42 -070074
75 (when (not (android-makefile-exists-p default-directory))
76 (error "Not in a valid android tree"))
77
78 (if (string= default-directory topdir)
79 (list "Makefile" t)
80 ;; Remove the root dir at the start of the filename
81 (setq default-directory (substring default-directory (length topdir) nil))
82 (setq file (concat default-directory "Android.mk"))
83 (list file nil))))
84
Nicolas Cataniadf098ce2009-10-15 10:48:01 -070085;; This filter is registered as a `compilation-filter-hook' and is
86;; called when new data has been inserted in the compile buffer. Don't
87;; assume that only one line has been inserted, typically more than
88;; one has changed since the last call due to stdout buffering.
Nicolas Cataniaf6f5bea2009-11-13 09:52:18 -080089;;
90;; We store in a buffer local variable `android-compile-context' a
91;; list with 2 elements, the process and point position at the end of
92;; the last invocation. The process is used to detect a new
93;; compilation. The point position is used to limit our search.
94;;
95;; On entry (point) is at the end of the last block inserted.
Nicolas Cataniadf098ce2009-10-15 10:48:01 -070096(defun android-compile-filter ()
97 "Filter to discard unwanted lines from the compilation buffer.
98
99This filter is registered as a `compilation-filter-hook' and is
100called when new data has been inserted in the compile buffer.
101
102Has effect only if `android-compilation-no-buildenv-warning' is
103not nil."
104 ;; Currently we are looking only for compilation warnings from the
105 ;; build env. Move this test lower, near the while loop if we
106 ;; support more than one category of regexp.
107 (when android-compilation-no-buildenv-warning
108
109 ;; Check if android-compile-context does not exist or if the
110 ;; process has changed: new compilation.
111 (let ((proc (get-buffer-process (current-buffer))))
112 (unless (and (local-variable-p 'android-compile-context)
113 (eq proc (cadr android-compile-context)))
114 (setq android-compile-context (list (point-min) proc))
115 (make-local-variable 'android-compile-context)))
116
117 (let ((beg (car android-compile-context))
118 (end (point)))
119 (save-excursion
120 (goto-char beg)
Nicolas Cataniaf6f5bea2009-11-13 09:52:18 -0800121 ;; Need to go back at the beginning of the line before we
122 ;; start the search: because of the buffering, the previous
123 ;; block inserted may have ended in the middle of the
124 ;; expression we are trying to match. As result we missed it
125 ;; last time and we would miss it again if we started just
126 ;; where we left of. By processing the line from the start we
127 ;; are catching that case.
128 (forward-line 0)
Nicolas Cataniadf098ce2009-10-15 10:48:01 -0700129 (while (search-forward-regexp android-compile-ignore-re end t)
130 ;; Nuke the line
131 (let ((bol (point-at-bol)))
132 (forward-line 1)
133 (delete-region bol (point)))))
134 ;; Remember the new end for next time around.
135 (setcar android-compile-context (point)))))
Nicolas Catania19252812009-10-05 14:49:14 -0700136
Nicolas Catania19252812009-10-05 14:49:14 -0700137(defun android-compile ()
138 "Elisp equivalent of mm shell function.
139Walk up the path until a makefile is found and build it.
Nicolas Cataniaf94bca22009-10-06 10:45:44 -0700140You need to have a proper buildspec.mk in your top dir.
141
142Use `android-compilation-jobs' to control the number of jobs used
143in a compilation."
Nicolas Catania19252812009-10-05 14:49:14 -0700144 (interactive)
145 (if (android-project-p)
146 (let* ((topdir (android-find-build-tree-root))
Nicolas Cataniaf94bca22009-10-06 10:45:44 -0700147 (makefile (android-find-makefile topdir))
148 (options
149 (concat " -j " (number-to-string android-compilation-jobs))))
Nicolas Catania4a5dc7e2009-10-09 09:24:42 -0700150 (unless (file-exists-p (concat topdir "buildspec.mk"))
151 (error "buildspec.mk missing in %s." topdir))
Nicolas Cataniadf098ce2009-10-15 10:48:01 -0700152 ;; Add-hook do not re-add if already present. The compile
153 ;; filter hooks run after the comint cleanup (^M).
154 (add-hook 'compilation-filter-hook 'android-compile-filter)
Nicolas Catania19252812009-10-05 14:49:14 -0700155 (set (make-local-variable 'compile-command)
156 (if (cadr makefile)
157 ;; The root Makefile is not invoked using ONE_SHOT_MAKEFILE.
Nicolas Catania2022dcd2009-10-13 09:10:19 -0700158 (concat "make -C " topdir options) ; Build the whole image.
Nicolas Catania19252812009-10-05 14:49:14 -0700159 (concat "ONE_SHOT_MAKEFILE=" (car makefile)
Nicolas Cataniaf94bca22009-10-06 10:45:44 -0700160 " make -C " topdir options " files ")))
Nicolas Catania19252812009-10-05 14:49:14 -0700161 (if (interactive-p)
Nicolas Cataniaf94bca22009-10-06 10:45:44 -0700162 (call-interactively 'compile)))))
Nicolas Catania19252812009-10-05 14:49:14 -0700163
164(provide 'android-compile)
Nicolas Catania4a5dc7e2009-10-09 09:24:42 -0700165
166;;; android-compile.el ends here