1 ;;; ada-build.el --- Extensions to ada-mode for compiling and running -*- lexical-binding:t -*-
2 ;; Ada projects without 'make' or similar tool
4 ;; Copyright (C) 1994, 1995, 1997 - 2015 Free Software Foundation, Inc.
6 ;; Author: Stephen Leake <stephen_leake@member.fsf.org>
7 ;; Maintainer: Stephen Leake <stephen_leake@member.fsf.org>
9 ;; This file is part of GNU Emacs.
11 ;; GNU Emacs is free software: you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
26 ;; Separate from ada-mode.el because sophisticated users don't need
27 ;; this (they use 'make' or similar tool), so it would just get in the
28 ;; way, particularly for fixing bugs in the core capabilities of
33 ;; see ada-mode.el; the current code is a complete rewrite of the
34 ;; compiling and running capabilities in Ada mode 4.01, done in 2013 by
35 ;; Stephen Leake <stephen_leake@stephe-leake.org>.
37 (when (and (= emacs-major-version 24)
38 (= emacs-minor-version 2))
39 (require 'ada-mode-compat-24.2))
43 ;;;; User customization
45 (defgroup ada-build nil
46 "Major mode for compiling and running Ada projects in Emacs."
49 (defcustom ada-build-prompt-prj 'default
50 "Policy for finding a project file when none is currently selected."
51 :type '(choice (const default)
52 (const prompt-default)
57 (defcustom ada-build-confirm-command nil
58 "If non-nil, prompt for confirmation/edit of each command before it is run."
62 (defcustom ada-build-check-cmd
63 (concat "${cross_prefix}gnatmake -u -c -gnatc ${gnatmake_opt} ${full_current} -cargs -I${src_dir} ${comp_opt}")
64 "Default command to syntax check a single file.
65 Overridden by project variable 'check_cmd'."
68 (defcustom ada-build-make-cmd
69 (concat "${cross_prefix}gnatmake -P${gpr_file} -o ${main} ${main} ${gnatmake_opt} "
70 "-cargs -I${src_dir} ${comp_opt} -bargs ${bind_opt} -largs ${link_opt}")
71 "Default command to compile the application.
72 Overridden by project variable 'make_cmd'."
75 (defcustom ada-build-run-cmd "./${main}"
76 "Default command to run the application, in a spawned shell.
77 Overridden by project variable 'run_cmd'."
82 (defun ada-build-replace-vars (cmd-string)
83 "Recursively expand variable references in CMD-STRING.
84 ${var} is a project variable or environment variable, $var an
87 A prefix may be specified with the format '-<prefix>${var}'; then
88 the value is expanded with the prefix prepended. If the value is
89 a list, the prefix is prepended to each list element. For
90 example, if src_dir contains 'dir_1 dir_2', '-I${src_dir}'
91 expands to '-Idir_1 -Idir_2'.
93 As a special case, ${full_current} is replaced by the name
94 including the directory and extension."
96 (while (string-match "\\(-[^-$ ]+\\)?\\${\\([^}]+\\)}" cmd-string)
97 (let ((prefix (match-string 1 cmd-string))
98 (name (match-string 2 cmd-string))
101 (when (string= name "full_current")
102 (setq value (buffer-file-name)))
105 (setq value (ada-prj-get (intern name))))
108 (setq value (getenv name)))
112 (setq cmd-string (replace-match "" t t cmd-string)))
115 (setq cmd-string (replace-match (concat prefix value) t t cmd-string)))
118 (setq cmd-string (replace-match
119 (mapconcat (lambda (x) (concat prefix x)) value " ")
123 (substitute-in-file-name cmd-string))
125 (defun ada-build-default-prj (project)
126 "Add to PROJECT the default properties list for Ada project variables used by ada-build."
130 'check_cmd ada-build-check-cmd
131 'main (when (buffer-file-name)
132 (file-name-nondirectory
133 (file-name-sans-extension (buffer-file-name))))
134 'make_cmd ada-build-make-cmd
135 'run_cmd ada-build-run-cmd
138 (defun ada-build-select-default-prj ()
139 "Create and select a new default project."
140 (let ((prj-file (expand-file-name "default.adp"))
143 (when (null (assoc prj-file ada-prj-alist))
144 (setq project (ada-prj-default)) ;; ada-build-default-prj included via ada-prj-default-compiler-alist
146 (add-to-list 'ada-prj-alist (cons prj-file project))
149 (ada-select-prj-file prj-file)
152 (defun ada-build-find-select-prj-file ()
153 "Search for a project file in the current directory, parse and select it.
154 The file must have the same basename as the project variable
155 'main' or the current buffer if 'main' is nil, and extension from
156 `ada-prj-file-extensions'. Returns non-nil if a file is
157 selected, nil otherwise."
158 (let* ((base-file-name (file-name-base
159 (or (ada-prj-get 'main)
160 (file-name-nondirectory (file-name-sans-extension (buffer-file-name))))))
163 (file-name-completion base-file-name
165 (lambda (name) (member (file-name-extension name) ada-prj-file-extensions)))
167 (file-name-completion base-file-name
169 (lambda (name) (member (file-name-extension name) ada-prj-file-ext-extra)))))
172 (ada-parse-prj-file filename)
173 (ada-select-prj-file filename))
176 (defun ada-build-prompt-select-prj-file ()
177 "Search for a project file, parse and select it.
178 The file must have an extension from `ada-prj-file-extensions'.
179 Returns non-nil if a file is selected, nil otherwise."
181 (let ((ext (append ada-prj-file-extensions ada-prj-file-ext-extra))
186 "Project file: " ; prompt
188 "" ; default-filename
192 ;; this allows directories, which enables navigating
193 ;; to the desired file. We just assume the user won't
194 ;; return a directory.
195 (or (file-accessible-directory-p name)
196 (member (file-name-extension name) ext)))))
201 (when (not (equal "" filename))
202 (ada-parse-prj-file filename)
203 (ada-select-prj-file filename)
207 (defun ada-build-require-project-file ()
208 "Ensure that a project file is selected.
209 Action when no project file is currently selected is determined
210 by `ada-build-prompt-prj':
212 default - Search for a project file in the current directory with
213 the same name as the main file. If not found, use a default
214 project; no gpr file, current directory only, current file as
217 default-prompt - Search for a project file in the current
218 directory with the same name as the main file. If not found,
219 prompt for a project file; error result does not change current
222 prompt - Prompt for a project file; error result does not
223 change current project.
225 error - Throw an error (no prompt, no default project)."
226 (unless ada-prj-current-file
227 (cl-ecase ada-build-prompt-prj
229 (or (ada-build-find-select-prj-file)
230 (ada-build-select-default-prj)))
233 (or (ada-build-find-select-prj-file)
234 (ada-build-prompt-select-prj-file)))
237 (ada-build-prompt-select-prj-file))
240 (error "no project file selected"))
245 (defun ada-build-run-cmd (prj-field confirm prompt)
246 "Run the command in the PRJ-FIELD project variable.
247 If CONFIRM or `ada-build-confirm-command' are non-nil, ask for
248 user confirmation of the command, using PROMPT."
249 (ada-build-require-project-file)
250 (let ((cmd (ada-prj-get prj-field))
251 (process-environment (ada-prj-get 'proc_env)))
257 (when (or ada-build-confirm-command confirm)
258 (setq cmd (read-from-minibuffer (concat prompt ": ") cmd)))
260 (compile (ada-build-replace-vars cmd))))
262 (defun ada-build-check (&optional confirm)
263 "Run the check_cmd project variable.
264 By default, this checks the current file for syntax errors.
265 If CONFIRM is non-nil, prompt for user confirmation of the command."
267 (ada-build-run-cmd 'check_cmd confirm "check command"))
269 (defun ada-build-make (&optional confirm)
270 "Run the make_cmd project variable.
271 By default, this compiles and links the main program.
272 If CONFIRM is non-nil, prompt for user confirmation of the command."
274 (ada-build-run-cmd 'make_cmd confirm "make command"))
276 (defun ada-build-set-make (&optional confirm)
277 "Set the main project variable to the current file, then run the make_cmd project variable.
278 By default, this compiles and links the new main program.
279 If CONFIRM is non-nil, prompt for user confirmation of the command."
281 (ada-prj-put 'main (file-name-nondirectory (file-name-sans-extension (buffer-file-name))))
282 (ada-build-run-cmd 'make_cmd confirm "make command"))
284 (defun ada-build-run (&optional confirm)
285 "Run the run_cmd project variable.
286 By default, this runs the main program.
287 If CONFIRM is non-nil, prompt for user confirmation of the command."
289 (ada-build-run-cmd 'run_cmd confirm "run command"))
291 (defun ada-build-show-main ()
292 "Show current project main program filename."
294 (message "Ada mode main: %s"(ada-prj-get 'main)))
297 (add-to-list 'ada-prj-default-list 'ada-build-default-prj)