166 lines
6.9 KiB
EmacsLisp
166 lines
6.9 KiB
EmacsLisp
;;; android-compile.el --- Compile the Android source tree.
|
|
;;
|
|
;; Copyright (C) 2009 The Android Open Source Project
|
|
;;
|
|
;; Licensed under the Apache License, Version 2.0 (the "License");
|
|
;; you may not use this file except in compliance with the License.
|
|
;; You may obtain a copy of the License at
|
|
;;
|
|
;; http://www.apache.org/licenses/LICENSE-2.0
|
|
;;
|
|
;; Unless required by applicable law or agreed to in writing, software
|
|
;; distributed under the License is distributed on an "AS IS" BASIS,
|
|
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
;; See the License for the specific language governing permissions and
|
|
;; limitations under the License.
|
|
|
|
;;; Commentary:
|
|
;;
|
|
;; Helper functions to compile Android file within emacs.
|
|
;; This module ignores 'build/envsetup.sh' and any enviroment set by the
|
|
;; 'lunch' shell function.
|
|
;; Instead it relies solely on 'buildspec.mk', remember that when you
|
|
;; switch configuration.
|
|
;;
|
|
;; The only interactive function is 'android-compile'.
|
|
;; In your .emacs load this file (e.g (require 'android-compile)) then:
|
|
;;
|
|
;; (add-hook 'c++-mode-hook 'android-compile)
|
|
;; (add-hook 'java-mode-hook 'android-compile)
|
|
;; and/or
|
|
;; (global-set-key [f9] 'android-compile)
|
|
;;
|
|
;;
|
|
;; TODO: Maybe we could cache the result of the compile function in
|
|
;; buffer local vars.
|
|
|
|
;;; Code:
|
|
|
|
(require 'compile)
|
|
(require 'android-common)
|
|
|
|
;; No need to be customized.
|
|
(defvar android-compile-ignore-re
|
|
"\\(^\\(\\sw\\|[/_]\\)+\\(Makefile\\|\\.mk\\):[0-9]+:.*warning\\)\\|\\(^/bin/bash\\)"
|
|
"RE to match line to suppress during a compilation.
|
|
During the compilation process line matching the above will be
|
|
suppressed if `android-compilation-no-buildenv-warning' is non nil.")
|
|
|
|
(defun android-makefile-exists-p (directory)
|
|
"Return t if an Android makefile exists in DIRECTORY."
|
|
; Test for Android.mk first: more likely.
|
|
(or (file-exists-p (concat directory "Android.mk"))
|
|
(file-exists-p (concat directory "Makefile"))))
|
|
|
|
(defun android-find-makefile (topdir)
|
|
"Ascend the current path until an Android makefile is found.
|
|
Makefiles are named Android.mk except in the root directory where
|
|
the file is named Makefile.
|
|
TOPDIR is the root directory of the build.
|
|
Return a list with 2 elements (MAKEFILE_PATH IS_ROOT_MAKEFILE).
|
|
MAKEFILE_PATH is the relative path of the makefile wrt TOPDIR.
|
|
Signal an error if no Makefile was found."
|
|
;; TODO: Could check that topdir is the start of default-directory.
|
|
(unless (> (length topdir) 2)
|
|
(error "Topdir invalid %s for current dir %s" topdir default-directory))
|
|
(let ((default-directory default-directory)
|
|
file)
|
|
;; Ascend the path.
|
|
(while (and (> (length default-directory) (length topdir))
|
|
(not (android-makefile-exists-p default-directory)))
|
|
(setq default-directory
|
|
(substring default-directory 0
|
|
(string-match "[^/]+/$" default-directory))))
|
|
|
|
(when (not (android-makefile-exists-p default-directory))
|
|
(error "Not in a valid android tree"))
|
|
|
|
(if (string= default-directory topdir)
|
|
(list "Makefile" t)
|
|
;; Remove the root dir at the start of the filename
|
|
(setq default-directory (substring default-directory (length topdir) nil))
|
|
(setq file (concat default-directory "Android.mk"))
|
|
(list file nil))))
|
|
|
|
;; This filter is registered as a `compilation-filter-hook' and is
|
|
;; called when new data has been inserted in the compile buffer. Don't
|
|
;; assume that only one line has been inserted, typically more than
|
|
;; one has changed since the last call due to stdout buffering.
|
|
;;
|
|
;; We store in a buffer local variable `android-compile-context' a
|
|
;; list with 2 elements, the process and point position at the end of
|
|
;; the last invocation. The process is used to detect a new
|
|
;; compilation. The point position is used to limit our search.
|
|
;;
|
|
;; On entry (point) is at the end of the last block inserted.
|
|
(defun android-compile-filter ()
|
|
"Filter to discard unwanted lines from the compilation buffer.
|
|
|
|
This filter is registered as a `compilation-filter-hook' and is
|
|
called when new data has been inserted in the compile buffer.
|
|
|
|
Has effect only if `android-compilation-no-buildenv-warning' is
|
|
not nil."
|
|
;; Currently we are looking only for compilation warnings from the
|
|
;; build env. Move this test lower, near the while loop if we
|
|
;; support more than one category of regexp.
|
|
(when android-compilation-no-buildenv-warning
|
|
|
|
;; Check if android-compile-context does not exist or if the
|
|
;; process has changed: new compilation.
|
|
(let ((proc (get-buffer-process (current-buffer))))
|
|
(unless (and (local-variable-p 'android-compile-context)
|
|
(eq proc (cadr android-compile-context)))
|
|
(setq android-compile-context (list (point-min) proc))
|
|
(make-local-variable 'android-compile-context)))
|
|
|
|
(let ((beg (car android-compile-context))
|
|
(end (point)))
|
|
(save-excursion
|
|
(goto-char beg)
|
|
;; Need to go back at the beginning of the line before we
|
|
;; start the search: because of the buffering, the previous
|
|
;; block inserted may have ended in the middle of the
|
|
;; expression we are trying to match. As result we missed it
|
|
;; last time and we would miss it again if we started just
|
|
;; where we left of. By processing the line from the start we
|
|
;; are catching that case.
|
|
(forward-line 0)
|
|
(while (search-forward-regexp android-compile-ignore-re end t)
|
|
;; Nuke the line
|
|
(let ((bol (point-at-bol)))
|
|
(forward-line 1)
|
|
(delete-region bol (point)))))
|
|
;; Remember the new end for next time around.
|
|
(setcar android-compile-context (point)))))
|
|
|
|
(defun android-compile ()
|
|
"Elisp equivalent of mm shell function.
|
|
Walk up the path until a makefile is found and build it.
|
|
You need to have a proper buildspec.mk in your top dir.
|
|
|
|
Use `android-compilation-jobs' to control the number of jobs used
|
|
in a compilation."
|
|
(interactive)
|
|
(if (android-project-p)
|
|
(let* ((topdir (android-find-build-tree-root))
|
|
(makefile (android-find-makefile topdir))
|
|
(options
|
|
(concat " -j " (number-to-string android-compilation-jobs))))
|
|
(unless (file-exists-p (concat topdir "buildspec.mk"))
|
|
(error "buildspec.mk missing in %s." topdir))
|
|
;; Add-hook do not re-add if already present. The compile
|
|
;; filter hooks run after the comint cleanup (^M).
|
|
(add-hook 'compilation-filter-hook 'android-compile-filter)
|
|
(set (make-local-variable 'compile-command)
|
|
(if (cadr makefile)
|
|
;; The root Makefile is not invoked using ONE_SHOT_MAKEFILE.
|
|
(concat "make -C " topdir options) ; Build the whole image.
|
|
(concat "ONE_SHOT_MAKEFILE=" (car makefile)
|
|
" make -C " topdir options " files ")))
|
|
(if (interactive-p)
|
|
(call-interactively 'compile)))))
|
|
|
|
(provide 'android-compile)
|
|
|
|
;;; android-compile.el ends here
|