Fix warnings when flycheck is unavailable and some minor code
[arduino-mode.git] / ede-arduino.el
blob0262ecb38d6d589cf76a9a9739ed98e23fa0e12d
1 ;;; ede-arduino.el --- EDE support for arduino projects / sketches -*- lexical-binding: t; -*-
2 ;;
3 ;; Copyright (C) 2012 Eric M. Ludlam
4 ;;
5 ;; Author: Eric M. Ludlam <eric@siege-engine.com>
6 ;;
7 ;; This program is free software; you can redistribute it and/or
8 ;; modify it under the terms of the GNU General Public License as
9 ;; published by the Free Software Foundation, either version 3 of the
10 ;; License, or (at your option) any later version.
12 ;; This program is distributed in the hope that it will be useful, but
13 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ;; General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with this program. If not, see http://www.gnu.org/licenses/.
20 ;;; Commentary:
22 ;; EDE support for arduino projects.
24 ;; For most basic configurations, you will still need to use the
25 ;; arduino IDE to set and change preferences. Use the command
26 ;; 'ede-arduino-sync' to syncrhonize with changes made in the arduino
27 ;; IDE.
30 ;; To download an arduino mode for your code, see this mode:
31 ;; https://github.com/bookest/arduino-mode
33 (require 'ede)
35 ;;; Code:
36 (defcustom ede-arduino-makefile-name "Makefile"
37 "File name to use for generated Makefile."
38 :group 'ede
39 :type 'file)
41 (defcustom ede-arduino-make-command "make"
42 "Command used to run Makefiles."
43 :group 'ede
44 :type 'file)
46 (defcustom ede-arduino-container-prefix nil
47 "The location of the arduino installs container prefix."
48 :group 'arduino
49 :type 'string)
51 ;;;###autoload
52 (defcustom ede-arduino-preferences-file "~/.arduino/preferences.txt"
53 "The location of personl preferences for the arduino IDE.
54 Note: If this changes, we need to also update the autoload feature."
55 :group 'arduino
56 :type 'string)
58 (defcustom ede-arduino-boards-file "hardware/arduino/avr/boards.txt"
59 "The location of the arduino boards file."
60 :group 'arduino
61 :type 'string)
63 (defcustom ede-arduino-avrdude-baudrate nil
64 "Override the board specific baud rates."
65 :group 'arduino
66 :type 'string)
69 ;;; Arduino Preferences
71 ;; Derive data from the arduino IDE's preferences.
73 ;;;###autoload
74 (defclass ede-arduino-prefs ()
75 ((timestamp :initform nil)
76 (prefssize :initform nil)
77 (board :initform "uno")
78 (port :initform "/dev/ttyUSB1")
79 (sketchbook :initform "~/Arduino")
80 (boardobj :initform nil))
81 "Class containing arduino preferences.")
83 (defvar ede-arduino-active-prefs nil
84 "The currently active preferences for Arduino development.")
86 (defun ede-arduino-sync ()
87 "Synchronize arduino development preferences with the arduino IDE.
88 Synchronization pulls preferences from `ede-arduino-preferences-file'
89 for use in Emacs. It does not copy preferences or changes made in
90 Emacs back to the Arduino IDE."
91 (interactive)
92 (when (not (file-exists-p ede-arduino-preferences-file))
93 (if (y-or-n-p "Can't find arduino preferences. Start IDE to configure? ")
94 (ede-arduino)
95 (error "EDE cannot build/upload arduino projects without preferences from the arduino IDE")))
96 (ede-arduino-read-prefs ede-arduino-preferences-file)
97 ede-arduino-active-prefs)
99 (defun ede-arduino-read-prefs (prefsfile)
100 "Read in arduino preferences from the PREFSFILE."
101 (let* ((buff (get-file-buffer prefsfile))
102 (stats (file-attributes prefsfile))
103 (size (nth 7 stats))
104 (mod (nth 5 stats))
105 (board nil)
106 (kill nil))
108 (when (not ede-arduino-active-prefs)
109 (setq ede-arduino-active-prefs (make-instance 'ede-arduino-prefs)))
111 ;; Only update the prefs if the prefs file changed.
112 (when (or (not (oref ede-arduino-active-prefs timestamp))
113 (/= (or (oref ede-arduino-active-prefs prefssize) 0) size)
114 (not (equal (oref ede-arduino-active-prefs timestamp) mod)))
115 (when (not buff)
116 (setq buff (find-file-noselect prefsfile)
117 kill t))
118 (with-current-buffer buff
119 (save-excursion
120 (goto-char (point-min))
121 (when (not (re-search-forward "^serial.port=" nil t))
122 (error "Cannot find serial.port from the arduino preferences"))
123 (oset ede-arduino-active-prefs port
124 (buffer-substring-no-properties (point) (point-at-eol)))
126 (goto-char (point-min))
127 (when (not (re-search-forward "^board=" nil t))
128 (error "Cannot find board from the arduino preferences"))
129 (setq board (buffer-substring-no-properties (point) (point-at-eol)))
130 (oset ede-arduino-active-prefs board board)
132 (goto-char (point-min))
133 (when (not (re-search-forward "^sketchbook.path=" nil t))
134 (error "Cannot find sketchbook.path from the arduino preferences"))
135 (oset ede-arduino-active-prefs sketchbook
136 (file-name-as-directory
137 (expand-file-name
138 (buffer-substring-no-properties (point) (point-at-eol)))))
140 (when kill (kill-buffer buff))
142 (oset ede-arduino-active-prefs boardobj (ede-arduino-board-data board))
143 (oset ede-arduino-active-prefs prefssize size)
144 (oset ede-arduino-active-prefs timestamp mod))))))
146 ;;; Arduino Intuition
148 ;; Examine the environment to find arduino library locations
149 ;; so we can call the utilities.
151 (defcustom ede-arduino-arduino-command "arduino"
152 "The command used for starting the arduino IDE.
153 The IDE is actually a script, so the purpose here is only to look up
154 where the arduino APPDIR is.
156 If you are customizing this variable, consider the short-cut of just
157 customizing the `ede-arduino-appdir' variable instead."
158 :group 'arduino
159 :type 'string)
161 (defcustom ede-arduino-appdir nil
162 "The location of the arduino build environment's application.
163 This is also where Arduino.mk will be found."
164 :group 'arduino
165 :type 'directory)
167 (defun ede-arduino ()
168 "Launch the arduino IDE."
169 (interactive)
170 (let ((b (get-buffer-create "*Arduino IDE*"))
171 (cd default-directory))
172 (with-current-buffer b
173 (setq default-directory cd)
174 (erase-buffer))
175 (apply #'start-process "arduino" b ede-arduino-arduino-command nil)))
177 (defun ede-arduino-find-install (&optional full-path)
178 "Return the `FULL-PATH' where arduino IDE code is installed.
180 If `full-path' is set return a full path including container prefix,
181 if configured"
182 (cond
183 ((and ede-arduino-appdir
184 (file-exists-p (concat ede-arduino-container-prefix ede-arduino-appdir)))
185 (if full-path
186 (concat ede-arduino-container-prefix ede-arduino-appdir)
187 ede-arduino-appdir))
188 ((and ede-arduino-appdir (file-exists-p ede-arduino-appdir))
189 ede-arduino-appdir)
191 ;; Derive by looking up the arduino script.
192 (let ((arduinofile ede-arduino-arduino-command))
193 (when (not (file-exists-p arduinofile))
194 ;; Look up where it might be...
195 (setq arduinofile (locate-file arduinofile exec-path))
197 (when (not (file-exists-p arduinofile))
198 (error "Cannot find arduino command location"))
200 (let ((buff (get-file-buffer arduinofile))
201 (kill nil))
202 (when (not buff)
203 (setq buff (find-file-noselect arduinofile)
204 kill t))
205 (with-current-buffer buff
206 (save-excursion
207 (goto-char (point-min))
209 (when (not (re-search-forward "APPDIR=" nil t))
210 (error "Cannot find APPDIR from the arduino command"))
212 (prog1
213 (setq ede-arduino-appdir
214 (buffer-substring-no-properties (point) (point-at-eol)))
215 (when kill (kill-buffer buff)))))))))))
217 (defun ede-arduino-Arduino.mk ()
218 "Return the location of Arduino's makefile helper."
219 (expand-file-name "Arduino.mk" (ede-arduino-find-install)))
221 (defun ede-arduino-Arduino-Version ()
222 "Return the version of the installed Arduino."
223 (let ((vfile (expand-file-name "lib/version.txt" (ede-arduino-find-install t))))
224 (let ((buff (get-file-buffer vfile))
225 (kill nil))
226 (when (not buff)
227 (setq buff (find-file-noselect vfile)
228 kill t))
229 (prog1
230 (with-current-buffer buff
231 (save-excursion
232 (goto-char (point-min))
233 (buffer-substring-no-properties (point) (point-at-eol))))
234 (if kill (kill-buffer buff))))))
236 (defun ede-arduino-boards.txt ()
237 "Return the location of Arduino's boards.txt file."
238 (expand-file-name ede-arduino-boards-file (ede-arduino-find-install t)))
240 (defun ede-arduino-libdir (&optional library)
241 "Return the full file location of LIBRARY.
242 If LIBRARY is not provided as an argument, just return the library directory."
243 (let ((libdir (expand-file-name "libraries" (ede-arduino-find-install))))
244 (if library
245 (expand-file-name library libdir)
246 libdir)))
248 ;;; Arduino Board Reading
250 ;; Load data from boards.txt
251 ;;;###autoload
252 (defclass ede-arduino-board ()
253 ((name :initarg :name
254 :initform nil
255 :documentation
256 "The name of the arduino board represented by this object.")
257 (protocol :initarg :protocol
258 :initform nil
259 :documentation
260 "The protocol used to talk to the board.")
261 (speed :initarg :speed
262 :initform nil
263 :documentation
264 "The SPEED of the arduino board's serial upload.")
265 (maximum-size :initarg :maximum-size
266 :initform nil
267 :documentation
268 "The MAXIMUM_SIZE of the arduino board's uploadable target .")
269 (mcu :initarg :mcu
270 :initform nil
271 :documentation
272 "The MCU of the arduino board.")
273 (f_cpu :initarg :f_cpu
274 :initform nil
275 :documentation
276 "The F_CPU of the arduino board.")
277 (core :initarg :core
278 :initform nil
279 :documentation
280 "The core name for this board."))
281 "Class for containing key aspect of the arduino board.")
283 (defun ede-arduino-board-data (boardname)
284 "Read in the data from baords.txt for BOARDNAME.
285 Data returned is the intputs needed for the Makefile."
286 (let* ((buff (get-file-buffer (ede-arduino-boards.txt)))
287 (kill nil)
288 (name nil)
289 (protocol nil)
290 (speed nil)
291 (size nil)
292 (mcu nil)
293 (f_cpu nil)
294 (core nil))
296 (when (not buff)
297 (setq buff (find-file-noselect (ede-arduino-boards.txt))
298 kill t))
300 (with-current-buffer buff
301 (save-excursion
302 (goto-char (point-min))
303 (when (not (re-search-forward (concat "^" boardname ".name=") nil t))
304 (error "Cannot find %s.name looking up board" boardname))
305 (setq name (buffer-substring-no-properties (point) (point-at-eol)))
307 (goto-char (point-min))
308 (when (not (re-search-forward (concat "^" boardname ".upload.protocol=") nil t))
309 (error "Cannot find %s.upload.protocol looking up board" boardname))
310 (setq protocol (buffer-substring-no-properties (point) (point-at-eol)))
312 (goto-char (point-min))
313 (when (not (re-search-forward (concat "^" boardname ".upload.speed=") nil t))
314 (error "Cannot find %s.upload.speed looking up board" boardname))
315 (setq speed (buffer-substring-no-properties (point) (point-at-eol)))
317 (goto-char (point-min))
318 (when (not (re-search-forward (concat "^" boardname ".upload.maximum_size=") nil t))
319 (error "Cannot find %s.upload.maximum_size looking up board" boardname))
320 (setq size (buffer-substring-no-properties (point) (point-at-eol)))
322 (goto-char (point-min))
323 (when (not (re-search-forward (concat "^" boardname ".build.mcu=") nil t))
324 (error "Cannot find %s.build.mcu looking up board" boardname))
325 (setq mcu (buffer-substring-no-properties (point) (point-at-eol)))
327 (goto-char (point-min))
328 (when (not (re-search-forward (concat "^" boardname ".build.f_cpu=") nil t))
329 (error "Cannot find %s.build.f_cpu looking up board" boardname))
330 (setq f_cpu (buffer-substring-no-properties (point) (point-at-eol)))
332 (goto-char (point-min))
333 (when (not (re-search-forward (concat "^" boardname ".build.core=") nil t))
334 (error "Cannot find %s.build.core looking up board" boardname))
335 (setq core (buffer-substring-no-properties (point) (point-at-eol)))
337 (when kill (kill-buffer buff))
339 (make-instance 'ede-arduino-board ;; boardname
340 :name name
341 :protocol protocol
342 :speed speed
343 :maximum-size size
344 :mcu mcu
345 :f_cpu f_cpu
346 :core core)))))
348 ;;;###autoload
349 (defun ede-arduino-root (&optional dir basefile)
350 "Get the root project directory for DIR.
351 The only arduino sketches allowed are those configured by the arduino IDE
352 in their sketch directory.
354 If BASEFILE is non-nil, then convert root to the project basename also.
356 Consider expanding this at some later date."
357 (let* ((prefs (ede-arduino-sync))
358 ;; without expansion the comparison in the next step fails
359 ;; for relative files
360 (dir (expand-file-name dir))
361 (sketchroot (and prefs (oref prefs sketchbook))))
362 (when (and sketchroot
363 (< (length sketchroot) (length dir))
364 (string= sketchroot (substring dir 0 (length sketchroot))))
365 ;; The subdir in DIR just below sketchroot is always the root of this
366 ;; project.
367 (let* ((dirtail (substring dir (length sketchroot)))
368 (dirsplit (split-string dirtail "/" t))
369 (root (expand-file-name (car dirsplit) sketchroot)))
370 (when (file-directory-p root)
371 (if basefile
372 (let ((tmp (expand-file-name (concat (car dirsplit) ".pde") root)))
373 ;; Also check for the desired file in a buffer if the
374 ;; user just made the file but not saved it yet.
375 (when (or (not (file-exists-p tmp)) (not (get-file-buffer tmp)))
376 (setq tmp (expand-file-name (concat (car dirsplit) ".ino") root)))
377 tmp)
378 root))))))
380 ;;;###autoload
381 (defun ede-arduino-file (&optional dir)
382 "Get a file representing the root of this arduino project.
383 It is a file ending in .pde or .ino that has the same basename as
384 the directory it is in. Optional argument DIR is the directory
385 to check."
386 (ede-arduino-root dir t))
388 ;;;###autoload
389 (defun ede-arduino-load (dir &optional _rootproj)
390 "Return an Arduino project object if there is one.
391 Return nil if there isn't one.
392 Argument DIR is the directory it is created for.
393 ROOTPROJ is not used, sinc there is only one project for a directory tree."
394 (let* ((root (ede-arduino-root dir))
395 (proj (and root (ede-directory-get-open-project root)))
396 (_prefs (ede-arduino-sync)))
397 (if proj
398 (progn
399 (message "Opening existing project")
400 proj)
402 ;; Create a new project here.
403 (if root
404 (progn
405 (message "Creating new project")
406 (let* ((name (file-name-nondirectory (directory-file-name root)))
407 (pde (expand-file-name (concat name ".pde") root)))
408 (when (not (file-exists-p pde))
409 (setq pde (expand-file-name (concat name ".ino") root)))
410 (setq proj (ede-arduino-project name
411 :name name
412 :directory (file-name-as-directory dir)
413 :file pde
414 :targets nil)))
415 (ede-add-project-to-global-list proj))
416 (message "Project loading/creation failed")))))
418 ;;;###autoload
419 (require 'ede/auto) ; for `ede-project-autoload'
421 ;;;###autoload
422 (add-to-list
423 'ede-project-class-files
424 (ede-project-autoload :name "Arduino sketch"
425 :file 'ede-arduino
426 :proj-root-dirmatch
427 (ede-project-autoload-dirmatch
428 :fromconfig (expand-file-name ede-arduino-preferences-file)
429 :configregex "^sketchbook.path=\\([^\n]+\\)$"
430 :configregexidx 1)
431 :proj-file 'ede-arduino-file
432 :proj-root 'ede-arduino-root
433 :load-type 'ede-arduino-load
434 :class-sym 'ede-arduino-project
435 :safe-p t
436 :new-p t)
439 ;;; CLASSES
441 ;; The classes for arduino projects include arduino (PDE) files, plus C, CPP, and H files.
443 ;;;###autoload
444 (defclass ede-arduino-target (ede-target)
446 "EDE Arduino C files target. Includes PDE, C, C++ and anything else we find.")
448 ;;;###autoload
449 (defclass ede-arduino-project (ede-project)
450 ((keybindings :initform '(("U" . ede-arduino-upload)))
451 (menu :initform
453 [ "Upload Project to Board" ede-arduino-upload ]
454 [ "Serial Monitor" cedet-arduino-serial-monitor ]
455 "--"
456 [ "Edit Projectfile" ede-edit-file-target
457 (ede-buffer-belongs-to-project-p) ]
458 "--"
459 [ "Update Version" ede-update-version ede-object ]
460 [ "Version Control Status" ede-vc-project-directory ede-object ]
461 "--"
462 [ "Rescan Project Files" ede-rescan-toplevel t ]
464 "EDE Arduino project.")
466 ;;; TARGET MANAGEMENT
468 (cl-defmethod ede-find-target ((proj ede-arduino-project) _buffer)
469 "Find an EDE target in PROJ for BUFFER.
470 If one doesn't exist, create a new one for this directory."
471 (let* ((targets (oref proj targets))
472 (dir default-directory)
473 (ans (object-assoc dir :path targets))
475 (when (not ans)
476 (setq ans (make-instance 'ede-arduino-target ;; dir
477 :name (file-name-nondirectory
478 (directory-file-name dir))
479 :path dir
480 :source nil))
481 (object-add-to-list proj :targets ans))
482 ans))
484 ;;; COMMAND SUPPORT
486 (defun ede-arduino-upload ()
487 "Compile the current project, and upload the result to the board."
488 (interactive)
489 (project-compile-project (ede-current-project)
490 (concat ede-arduino-make-command " all upload")))
492 (require 'term)
494 (defun cedet-arduino-serial-monitor ()
495 "Start up a serial monitor for a running arduino board.
496 Uses `serial-term'."
497 (interactive)
498 (let ((prefs (ede-arduino-sync)))
499 ;; @TODO - read the setup function for something configuring the
500 ;; serial line w/ a baud rate, and use that.
501 (serial-term (oref prefs port) 9600)
502 ;; Always go to line mode, as arduino serial isn't typically used
503 ;; for input, just debugging output.
504 (term-line-mode)))
506 (cl-defmethod project-compile-project ((proj ede-arduino-project) &optional command)
507 "Compile the entire current project PROJ.
508 Argument COMMAND is the command to use when compiling."
509 ;; 1) Create the mini-makefile.
510 (ede-arduino-create-makefile proj)
511 ;; 2) Call MAKE
512 (compile (or command ede-arduino-make-command)))
514 (cl-defmethod project-compile-target ((_obj ede-arduino-target) &optional command)
515 "Compile the current target OBJ.
516 Argument COMMAND is the command to use for compiling the target."
517 (project-compile-project (ede-current-project) command))
519 (cl-defmethod project-debug-target ((_target ede-arduino-target))
520 "Run the current project derived from TARGET in a debugger."
521 (error "No Debugger support for Arduino"))
523 ;;; C/C++ support
524 (require 'semantic/db)
526 (cl-defmethod ede-preprocessor-map ((_this ede-arduino-target))
527 "Get the pre-processor map for some generic C code."
528 ;; wiring.h and pins_arduino.h have lots of #defines in them.
529 ;; TODO: realpath
530 (let* ((wiring_h (expand-file-name "hardware/arduino/cores/arduino/wiring.h"
531 (ede-arduino-find-install)))
532 (table (when (and wiring_h (file-exists-p wiring_h))
533 (semanticdb-file-table-object wiring_h)))
534 (filemap '(("HIGH" . "0x1")
535 ("LOW" . "0x0"))))
536 (when table
537 (when (semanticdb-needs-refresh-p table)
538 (semanticdb-refresh-table table))
539 (setq filemap (append filemap (oref table lexical-table))))
540 filemap))
542 (cl-defmethod ede-system-include-path ((_this ede-arduino-target))
543 "Get the system include path used by project THIS."
544 (let* ((_prefs (ede-arduino-sync))
545 (iphardware (expand-file-name "hardware/arduino/cores/arduino"
546 (ede-arduino-find-install)))
547 (libs (ede-arduino-guess-libs))
548 (iplibs (mapcar
549 (lambda (lib)
550 (expand-file-name (concat "libraries/" lib)
551 (ede-arduino-find-install)))
552 libs)))
553 (cons iphardware iplibs)))
555 (defun ede-arduino-guess-sketch ()
556 "Return the file that is the core of the current project sketch."
557 (let* ((proj ede-object-project)
558 (sketch (expand-file-name (concat (oref proj name) ".pde")
559 (oref proj directory))))
560 (if (file-exists-p sketch)
561 sketch
562 (setq sketch (expand-file-name (concat (oref proj name) ".ino")
563 (oref proj directory)))
564 (if (file-exists-p sketch)
565 sketch
566 (error "Cannot guess primary sketch file for project %s"
567 (eieio-object-name proj))))))
569 ;;; Makefile Creation
571 ;; Use SRecode, and the ede-srecode tool to build our Makefile.
572 (require 'ede/srecode)
574 (cl-defmethod ede-arduino-create-makefile ((proj ede-arduino-project))
575 "Create an arduino based Makefile for project PROJ."
576 (let* ((mfilename (expand-file-name ede-arduino-makefile-name
577 (oref proj directory)))
578 (prefs (ede-arduino-sync))
579 (board (oref prefs boardobj))
580 (vers (ede-arduino-Arduino-Version))
581 (sketch (ede-arduino-guess-sketch))
582 (orig-buffer nil)
583 ;; (buff-to-kill nil)
585 (when (and (string= (file-name-extension sketch) "ino")
586 (version< vers "1.0"))
587 (error "Makefile doesn't support .ino files until Arduino 1.0"))
588 (when (and (string= (file-name-extension sketch) "pde")
589 (version<= "1.0" vers))
590 (error "Makefile doesn't support .pde files after Arduino 1.0"))
592 (setq orig-buffer (get-file-buffer mfilename))
593 (with-current-buffer
594 ;; (setq buff-to-kill
595 (find-file-noselect mfilename)
596 (save-excursion
597 (goto-char (point-min))
598 (if (and (not (eobp))
599 (not (looking-at "# Automatically Generated \\w+ by EDE.")))
600 (if (not (y-or-n-p (format "Really replace %s? " mfilename)))
601 (error "Not replacing Makefile"))
602 (message "Replaced EDE Makefile"))
603 (erase-buffer)
604 (ede-srecode-setup)
605 ;; Insert a giant pile of stuff that is common between
606 ;; one of our Makefiles, and a Makefile.in
607 (ede-srecode-insert
608 "arduino:ede-empty"
609 "TARGET" (oref proj name)
610 "ARDUINO_LIBS" (mapconcat #'identity (ede-arduino-guess-libs) " ")
611 "MCU" (oref board mcu)
612 "F_CPU" (oref board f_cpu)
613 "PORT" (oref prefs port)
614 "AVRDUDE_ARD_BAUDRATE" (or ede-arduino-avrdude-baudrate (oref board speed))
615 "AVRDUDE_ARD_PROGRAMMER" (oref board protocol)
616 "ARDUINO_MK" (ede-arduino-Arduino.mk)
617 "ARDUINO_HOME" (ede-arduino-find-install)))
618 (save-buffer)
619 (when (not orig-buffer) (kill-buffer (current-buffer))))))
621 ;;; Arduino Sketch Code Inspector
623 ;; Inspect the code in an arduino sketch, and guess things, like which libraries to include.
625 (defun ede-arduino-guess-libs ()
626 "Guess which libraries this sketch use."
627 (interactive)
628 (let* ((libs nil)
629 (sketch (ede-arduino-guess-sketch))
630 (sketch-buffer (find-file-noselect sketch))
631 (arduino-libraries (with-current-buffer sketch-buffer
632 (if (boundp 'arduino-libraries)
633 arduino-libraries
634 nil))))
635 (cond
636 (arduino-libraries
637 (dolist (lib (split-string arduino-libraries))
638 (push lib libs)))
640 (let* ((orig-buffer (get-file-buffer sketch))
641 (buff nil)
642 (tmp nil))
643 (with-current-buffer
644 (setq buff (find-file-noselect sketch))
645 (save-excursion
646 (goto-char (point-min))
647 (while (re-search-forward "#include <\\([[:word:]_]+\\).h>" nil t)
648 (setq tmp (match-string 1))
649 (unless (file-exists-p (concat tmp ".h"))
650 ;; TODO: realpath
651 (let* ((lib (match-string 1))
652 (libdir (ede-arduino-libdir lib))
653 (util (expand-file-name "utility" libdir)))
654 ;; Some libraries need a utility added to the library list.
655 (when (file-exists-p util)
656 (push (concat lib "/utility") libs))
657 ;; Push real lib after the utility
658 (push lib libs))))))
659 (when (not orig-buffer) (kill-buffer buff)))))
660 libs))
662 (provide 'ede-arduino)
664 ;;; ede-arduino.el ends here