]> code.delx.au - gnu-emacs/blobdiff - lisp/cedet/ede/project-am.el
Merge from emacs-23
[gnu-emacs] / lisp / cedet / ede / project-am.el
index 3eb1f9c21839e976a8cd475cacc6d4c8d492b126..ac3e8bfc6eb85163d0c8a1662bf780aef7d53f23 100644 (file)
@@ -1,6 +1,6 @@
 ;;; project-am.el --- A project management scheme based on automake files.
 
-;; Copyright (C) 1998, 1999, 2000, 2003, 2005, 2007, 2008, 2009, 2010
+;; Copyright (C) 1998, 1999, 2000, 2003, 2005, 2007, 2008, 2009, 2010, 2011
 ;;   Free Software Foundation, Inc.
 
 ;; Author: Eric M. Ludlam <zappo@gnu.org>
 ;; fashion.
 ;;
 ;; project-am uses the structure defined in all good GNU projects with
-;; the Automake file as it's base template, and then maintains that
+;; the Automake file as its base template, and then maintains that
 ;; information during edits, automatically updating the automake file
 ;; where appropriate.
 
-
-;; (eval-and-compile
-;;   ;; Compatibility for makefile mode.
-;;   (condition-case nil
-;;       (require 'makefile "make-mode")
-;;     (error (require 'make-mode "make-mode")))
-
-;;   ;; Requiring the .el files prevents incomplete builds.
-;;   (require 'eieio "eieio.el")
-;;   (require 'ede "ede.el"))
-
 (require 'make-mode)
 (require 'ede)
 (require 'ede/make)
 (require 'ede/makefile-edit)
+(require 'semantic/find) ;; for semantic-find-tags-by-...
+(require 'ede/autoconf-edit)
 
 (declare-function autoconf-parameters-for-macro "ede/autoconf-edit")
+(declare-function ede-shell-run-something "ede/shell")
 (eval-when-compile (require 'compile))
 
 ;;; Code:
     ;; ("ltlibcustom" project-am-lib ".*?_LTLIBRARIES" t)
     )
   "Alist of type names and the type of object to create for them.
-Each entry is of th form:
+Each entry is of the form:
   (EMACSNAME CLASS AUTOMAKEVAR INDIRECT)
 where EMACSNAME is a name for Emacs to use.
 CLASS is the EDE target class to represent the target.
@@ -113,6 +105,23 @@ AUTOMAKEVAR is the Automake variable to identify.  This cannot be a
 INDIRECT is optional.  If it is non-nil, then the variable in
 question lists other variables that need to be looked up.")
 
+
+(defconst project-am-meta-type-alist
+  '((project-am-program "_PROGRAMS$" t)
+    (project-am-lib "_\\(LIBS\\|LIBRARIES\\|LTLIBRARIES\\)$" t)
+
+    ;; direct primary target use a dummy object (man target)
+    ;; update to: * 3.3 Uniform  in automake-1.11 info node.
+    (project-am-man "_\\(DATA\\|HEADERS\\|PYTHON\\|JAVA\\|SCRIPTS\\|MANS\\|TEXINFOS\\)$" nil)
+    )
+  "Alist of meta-target type, each entry has form:
+     (CLASS REGEXPVAR INDIRECT)
+where CLASS is the EDE target class for target.
+REGEXPVAR is the regexp used in `semantic-find-tags-by-name-regexp'.
+INDIRECT is optional. If it is non-nil, then the variable in it have
+other meta-variable based on this name.")
+
+
 (defclass project-am-target (ede-target)
   nil
   "Base target class for everything in project-am.")
@@ -291,16 +300,6 @@ buffer being in order to provide a smart default target type."
       ;; Rescan the object in this makefile.
       (project-rescan ede-object))))
 
-;(defun project-am-rescan-toplevel ()
-;  "Rescan all projects in which the current buffer resides."
-;  (interactive)
-;  (let* ((tlof (project-am-find-topmost-level default-directory))
-;       (tlo (project-am-load tlof))
-;       (ede-deep-rescan t))  ; scan deep in this case.
-;    ;; tlo is the top level object for whatever file we are in
-;    ;; or nil.  If we have an object, call the rescan method.
-;    (if tlo (project-am-rescan tlo))))
-
 ;;
 ;; NOTE TO SELF
 ;;
@@ -406,6 +405,7 @@ Argument COMMAND is the command to use for compiling the target."
 
 (defmethod project-run-target ((obj project-am-objectcode))
   "Run the current project target in comint buffer."
+  (require 'ede/shell)
   (let ((tb (get-buffer-create " *padt*"))
        (dd (oref obj path))
        (cmd nil))
@@ -429,45 +429,17 @@ Argument COMMAND is the command to use for compiling the target."
 
 ;;; Project loading and saving
 ;;
-(defun project-am-load (project &optional rootproj)
-  "Read an automakefile PROJECT into our data structure.
-Make sure that the tree down to our makefile is complete so that there
-is cohesion in the project.  Return the project file (or sub-project).
+(defun project-am-load (directory &optional rootproj)
+  "Read an automakefile DIRECTORY into our data structure.
 If a given set of projects has already been loaded, then do nothing
 but return the project for the directory given.
 Optional ROOTPROJ is the root EDE project."
-  ;; @TODO - rationalize this to the newer EDE way of doing things.
-  (setq project (expand-file-name project))
-  (let* ((ede-constructing t)
-        (fn (project-am-find-topmost-level (file-name-as-directory project)))
-        (amo nil)
-        (trimmed (if (string-match (regexp-quote fn)
-                                   project)
-                     (replace-match "" t t project)
-                   ""))
-        (subdir nil))
-    (setq amo (object-assoc (expand-file-name "Makefile.am" fn)
-                           'file ede-projects))
-    (if amo
-       (error "Synchronous error in ede/project-am objects")
-      (let ((project-am-constructing t))
-       (setq amo (project-am-load-makefile fn))))
-    (if (not amo)
-       nil
-      ;; Now scan down from amo, and find the current directory
-      ;; from the PROJECT file.
-      (while (< 0 (length trimmed))
-       (if (string-match "\\([a-zA-Z0-9.-]+\\)/" trimmed)
-           (setq subdir (match-string 0 trimmed)
-                 trimmed (replace-match "" t t trimmed))
-         (error "Error scanning down path for project"))
-       (setq amo (project-am-subtree
-                  amo
-                  (expand-file-name "Makefile.am"
-                                    (expand-file-name subdir fn)))
-             fn (expand-file-name subdir fn)))
-      amo)
-    ))
+  (let* ((ede-constructiong t)
+        (amo (object-assoc (expand-file-name "Makefile.am" directory)
+                           'file ede-projects)))
+    (when (not amo)
+      (setq amo (project-am-load-makefile directory)))
+    amo))
 
 (defun project-am-find-topmost-level (dir)
   "Find the topmost automakefile starting with DIR."
@@ -488,17 +460,19 @@ Kill the makefile if it was not loaded before the load."
          (fb nil)
          (kb (get-file-buffer fn)))
      (if (not (file-exists-p fn))
-       nil
-      (save-excursion
-       (if kb (setq fb kb)
-         ;; We need to find-file this thing, but don't use
-         ;; any semantic features.
-         (let ((semantic-init-hook nil))
-           (setq fb (find-file-noselect fn)))
-         )
-       (set-buffer fb)
-       (prog1 ,@forms
-         (if (not kb) (kill-buffer (current-buffer))))))))
+        nil
+       (save-excursion
+        (if kb (setq fb kb)
+          ;; We need to find-file this thing, but don't use
+          ;; any semantic features.
+          (let ((semantic-init-hook nil)
+                (recentf-exclude '( (lambda (f) t) ))
+                )
+            (setq fb (find-file-noselect fn)))
+          )
+        (set-buffer fb)
+        (prog1 ,@forms
+          (if (not kb) (kill-buffer (current-buffer))))))))
 (put 'project-am-with-makefile-current 'lisp-indent-function 1)
 
 (add-hook 'edebug-setup-hook
@@ -507,14 +481,18 @@ Kill the makefile if it was not loaded before the load."
              (form def-body))))
 
 
-(defun project-am-load-makefile (path)
+(defun project-am-load-makefile (path &optional suggestedname)
   "Convert PATH into a project Makefile, and return its project object.
-It does not check for existing project objects.  Use `project-am-load'."
+It does not check for existing project objects.  Use `project-am-load'.
+Optional argument SUGGESTEDNAME will be the project name.
+This is used when subprojects are made in named subdirectories."
   (project-am-with-makefile-current path
     (if (and ede-object (project-am-makefile-p ede-object))
        ede-object
       (let* ((pi (project-am-package-info path))
-            (pn (or (nth 0 pi) (project-am-last-dir fn)))
+            (sfn (when suggestedname
+                   (project-am-last-dir suggestedname)))
+            (pn (or sfn (nth 0 pi) (project-am-last-dir fn)))
             (ver (or (nth 1 pi) "0.0"))
             (bug (nth 2 pi))
             (cof (nth 3 pi))
@@ -532,21 +510,6 @@ It does not check for existing project objects.  Use `project-am-load'."
        ampf))))
 
 ;;; Methods:
-(defmethod ede-find-target ((amf project-am-makefile) buffer)
-  "Fetch the target belonging to BUFFER."
-  (or (call-next-method)
-      (let ((targ (oref amf targets))
-           (sobj (oref amf subproj))
-           (obj nil))
-       (while (and targ (not obj))
-         (if (ede-buffer-mine (car targ) buffer)
-             (setq obj (car targ)))
-         (setq targ (cdr targ)))
-       (while (and sobj (not obj))
-         (setq obj (project-am-buffer-object (car sobj) buffer)
-               sobj (cdr sobj)))
-       obj)))
-
 (defmethod project-targets-for-file ((proj project-am-makefile))
   "Return a list of targets the project PROJ."
   (oref proj targets))
@@ -556,44 +519,110 @@ It does not check for existing project objects.  Use `project-am-load'."
 CURRPROJ is the current project being scanned.
 DIR is the directory to apply to new targets."
   (let* ((otargets (oref currproj targets))
+        ;; `ntargets' results in complete targets list
+        ;; not only the new targets by diffing.
         (ntargets nil)
         (tmp nil)
         )
-      (mapc
-       ;; Map all the different types
-       (lambda (typecar)
-        (let ((macro (nth 2 typecar))
-              (class (nth 1 typecar))
-              (indirect (nth 3 typecar))
-              ;(name (car typecar))
-              )
-          (if indirect
-              ;; Map all the found objects
-              (mapc (lambda (lstcar)
-                      (setq tmp (object-assoc lstcar 'name otargets))
-                      (when (not tmp)
-                        (setq tmp (apply class lstcar :name lstcar
-                                         :path dir nil)))
-                      (project-rescan tmp)
-                      (setq ntargets (cons tmp ntargets)))
-                    (makefile-macro-file-list macro))
-            ;; Non-indirect will have a target whos sources
-            ;; are actual files, not names of other targets.
-            (let ((files (makefile-macro-file-list macro)))
-              (when files
-                (setq tmp (object-assoc macro 'name otargets))
-                (when (not tmp)
-                  (setq tmp (apply class macro :name macro
-                                   :path dir nil)))
-                (project-rescan tmp)
-                (setq ntargets (cons tmp ntargets))
-                ))
+
+    (mapc
+     ;; Map all the different types
+     (lambda (typecar)
+       (let ((macro (nth 2 typecar))
+            (class (nth 1 typecar))
+            (indirect (nth 3 typecar))
             )
-          ))
-       project-am-type-alist)
-      ntargets))
+        (if indirect
+            ;; Map all the found objects
+            (mapc (lambda (lstcar)
+                    (setq tmp (object-assoc lstcar 'name otargets))
+                    (when (not tmp)
+                      (setq tmp (apply class lstcar :name lstcar
+                                       :path dir nil)))
+                    (project-rescan tmp)
+                    (setq ntargets (cons tmp ntargets)))
+                  (makefile-macro-file-list macro))
+          ;; Non-indirect will have a target whos sources
+          ;; are actual files, not names of other targets.
+          (let ((files (makefile-macro-file-list macro)))
+            (when files
+              (setq tmp (object-assoc macro 'name otargets))
+              (when (not tmp)
+                (setq tmp (apply class macro :name macro
+                                 :path dir nil)))
+              (project-rescan tmp)
+              (setq ntargets (cons tmp ntargets))
+              ))
+          )
+        ))
+     project-am-type-alist)
+
+    ;; At now check variables for meta-target regexp
+    ;; We have to check ntargets to avoid useless rescan.
+    ;; Also we have check otargets to prevent duplication.
+    (mapc
+     (lambda (typecar)
+       (let ((class (nth 0 typecar))
+            (metaregex (nth 1 typecar))
+            (indirect (nth 2 typecar)))
+        (if indirect
+            ;; Map all the found objects
+            (mapc
+             (lambda (lstcar)
+               (unless (object-assoc lstcar 'name ntargets)
+                 (or
+                  (setq tmp (object-assoc lstcar 'name otargets))
+                  (setq tmp (apply class lstcar :name lstcar
+                                   :path dir nil)))
+                 (project-rescan tmp)
+                 (setq ntargets (cons tmp ntargets))))
+             ;; build a target list to map over
+             (let (atargets)
+               (dolist (TAG
+                        (semantic-find-tags-by-name-regexp
+                         metaregex (semantic-find-tags-by-class
+                                    'variable (semantic-fetch-tags))))
+                 ;; default-value have to be a list
+                 (when (cadr (assoc ':default-value TAG))
+                   (setq atargets
+                         (append
+                          (nreverse (cadr (assoc ':default-value TAG)))
+                          atargets))))
+               (nreverse atargets)))
+
+          ;; else not indirect, TODO: FIX various direct meta type in a sane way.
+          (dolist (T (semantic-find-tags-by-name-regexp
+                      metaregex (semantic-find-tags-by-class
+                                 'variable (semantic-fetch-tags))))
+            (unless (setq tmp (object-assoc (car T) 'name ntargets))
+              (or (setq tmp (object-assoc (car T) 'name otargets))
+                  ;; we are really new
+                  (setq tmp (apply class (car T) :name (car T)
+                                   :path dir nil)))
+              (project-rescan tmp)
+              (setq ntargets (cons tmp ntargets))))
+          )))
+     project-am-meta-type-alist)
+    ntargets))
+
+(defun project-am-expand-subdirlist (place subdirs)
+  "Store in PLACE the SUBDIRS expanded from variables.
+Strip out duplicates, and recurse on variables."
+  (mapc (lambda (sp)
+         (let ((var (makefile-extract-varname-from-text sp)))
+           (if var
+               ;; If it is a variable, expand that variable, and keep going.
+               (project-am-expand-subdirlist
+                place (makefile-macro-file-list var))
+             ;; Else, add SP in if it isn't a dup.
+             (if (member sp (symbol-value place))
+                 nil ; don't do it twice.
+               (set place (cons sp (symbol-value place))) ;; add
+               ))))
+       subdirs)
+  )
 
-(defmethod project-rescan ((this project-am-makefile))
+(defmethod project-rescan ((this project-am-makefile) &optional suggestedname)
   "Rescan the makefile for all targets and sub targets."
   (project-am-with-makefile-current (file-name-directory (oref this file))
     ;;(message "Scanning %s..." (oref this file))
@@ -603,10 +632,10 @@ DIR is the directory to apply to new targets."
           (bug (nth 2 pi))
           (cof (nth 3 pi))
           (osubproj (oref this subproj))
-          (csubproj (or
-                     ;; If DIST_SUBDIRS doesn't exist, then go for the
-                     ;; static list of SUBDIRS.  The DIST version should
-                     ;; contain SUBDIRS plus extra stuff.
+          ;; 1/30/10 - We need to append these two lists together,
+          ;; then strip out duplicates.  Expanding this list (via
+          ;; references to other variables should also strip out dups
+          (csubproj (append
                      (makefile-macro-file-list "DIST_SUBDIRS")
                      (makefile-macro-file-list "SUBDIRS")))
           (csubprojexpanded nil)
@@ -617,79 +646,57 @@ DIR is the directory to apply to new targets."
           (tmp nil)
           (ntargets (project-am-scan-for-targets this dir))
           )
-
-      (and pn (string= (directory-file-name
-                       (oref this directory))
-                      (directory-file-name
-                       (project-am-find-topmost-level
-                        (oref this directory))))
-          (oset this name pn)
-          (and pv (oset this version pv))
-          (and bug (oset this mailinglist bug))
-          (oset this configureoutputfiles cof))
-
-;      ;; LISP is different.  Here there is only one kind of lisp (that I know of
-;      ;; anyway) so it doesn't get mapped when it is found.
-;      (if (makefile-move-to-macro "lisp_LISP")
-;        (let ((tmp (project-am-lisp "lisp"
-;                                    :name "lisp"
-;                                    :path dir)))
-;          (project-rescan tmp)
-;          (setq ntargets (cons tmp ntargets))))
-;
+      (if suggestedname
+         (oset this name (project-am-last-dir suggestedname))
+       ;; Else, setup toplevel project info.
+       (and pn (string= (directory-file-name
+                         (oref this directory))
+                        (directory-file-name
+                         (project-am-find-topmost-level
+                          (oref this directory))))
+            (oset this name pn)
+            (and pv (oset this version pv))
+            (and bug (oset this mailinglist bug))
+            (oset this configureoutputfiles cof)))
       ;; Now that we have this new list, chuck the old targets
       ;; and replace it with the new list of targets I just created.
       (oset this targets (nreverse ntargets))
       ;; We still have a list of targets.  For all buffers, make sure
       ;; their object still exists!
-
       ;; FIGURE THIS OUT
-
-      (mapc (lambda (sp)
-             (let ((var (makefile-extract-varname-from-text sp))
-                   )
-               (if (not var)
-                   (setq csubprojexpanded (cons sp csubprojexpanded))
-                 ;; If it is a variable, expand that variable, and keep going.
-                 (let ((varexp (makefile-macro-file-list var)))
-                   (dolist (V varexp)
-                     (setq csubprojexpanded (cons V csubprojexpanded)))))
-               ))
-           csubproj)
-
+      (project-am-expand-subdirlist 'csubprojexpanded csubproj)
       ;; Ok, now lets look at all our sub-projects.
       (mapc (lambda (sp)
-             (let* ((subdir (file-name-as-directory
-                             (expand-file-name
-                              sp (file-name-directory (oref this :file)))))
-                    (submake (expand-file-name
-                              "Makefile.am"
-                              subdir)))
-               (if (string= submake (oref this :file))
-                   nil ;; don't recurse.. please!
-
-                 ;; For each project id found, see if we need to recycle,
-                 ;; and if we do not, then make a new one.  Check the deep
-                 ;; rescan value for behavior patterns.
-                 (setq tmp (object-assoc
-                            submake
-                            'file osubproj))
-                 (if (not tmp)
-                     (setq tmp
-                           (condition-case nil
-                               ;; In case of problem, ignore it.
-                               (project-am-load-makefile subdir)
-                             (error nil)))
-                   ;; If we have tmp, then rescan it only if deep mode.
-                   (if ede-deep-rescan
-                       (project-rescan tmp)))
-                 ;; Tac tmp onto our list of things to keep, but only
-                 ;; if tmp was found.
-                 (when tmp
-                   ;;(message "Adding %S" (object-print tmp))
-                   (setq nsubproj (cons tmp nsubproj)))))
-             )
-           (nreverse csubprojexpanded))
+             (let* ((subdir (file-name-as-directory
+                             (expand-file-name
+                              sp (file-name-directory (oref this :file)))))
+                    (submake (expand-file-name
+                              "Makefile.am"
+                              subdir)))
+               (if (string= submake (oref this :file))
+                   nil ;; don't recurse.. please!
+                 ;; For each project id found, see if we need to recycle,
+                 ;; and if we do not, then make a new one.  Check the deep
+                 ;; rescan value for behavior patterns.
+                 (setq tmp (object-assoc
+                            submake
+                            'file osubproj))
+                 (if (not tmp)
+                     (setq tmp
+                           (condition-case nil
+                               ;; In case of problem, ignore it.
+                               (project-am-load-makefile subdir subdir)
+                             (error nil)))
+                   ;; If we have tmp, then rescan it only if deep mode.
+                   (if ede-deep-rescan
+                       (project-rescan tmp subdir)))
+                 ;; Tac tmp onto our list of things to keep, but only
+                 ;; if tmp was found.
+                 (when tmp
+                   ;;(message "Adding %S" (object-print tmp))
+                   (setq nsubproj (cons tmp nsubproj)))))
+             )
+           (nreverse csubprojexpanded))
       (oset this subproj nsubproj)
       ;; All elements should be updated now.
       )))
@@ -698,12 +705,16 @@ DIR is the directory to apply to new targets."
 (defmethod project-rescan ((this project-am-program))
   "Rescan object THIS."
   (oset this :source (makefile-macro-file-list (project-am-macro this)))
+  (unless (oref this :source)
+    (oset this :source (list (concat (oref this :name) ".c"))))
   (oset this :ldadd (makefile-macro-file-list
                     (concat (oref this :name) "_LDADD"))))
 
 (defmethod project-rescan ((this project-am-lib))
   "Rescan object THIS."
-  (oset this :source (makefile-macro-file-list (project-am-macro this))))
+  (oset this :source (makefile-macro-file-list (project-am-macro this)))
+  (unless (oref this :source)
+    (oset this :source (list (concat (file-name-sans-extension (oref this :name)) ".c")))))
 
 (defmethod project-rescan ((this project-am-texinfo))
   "Rescan object THIS."
@@ -728,19 +739,6 @@ DIR is the directory to apply to new targets."
 (defmethod project-rescan ((this project-am-extra-dist))
   "Rescan object THIS."
   (oset this :source (makefile-macro-file-list "EXTRA_DIST")))
-  ;; NOTE: The below calls 'file' then checks that it is some sort of
-  ;; text file.  The  file command may not be available on all platforms
-  ;; and some files may not exist yet.  (ie - auto-generated)
-
-  ;;(mapc
-  ;; (lambda (f)
-  ;;   ;; prevent garbage to be parsed, could we use :aux ?
-  ;;   (if (and (not (member f (oref this :source)))
-  ;;         (string-match-p "ASCII\\|text"
-  ;;                         (shell-command-to-string
-  ;;                          (concat "file " f))))
-  ;;    (oset this :source (cons f (oref this :source)))))
-  ;; (makefile-macro-file-list "EXTRA_DIST")))
 
 (defmethod project-am-macro ((this project-am-objectcode))
   "Return the default macro to 'edit' for this object type."
@@ -810,22 +808,24 @@ nil means that this buffer belongs to no-one."
 
 (defmethod ede-buffer-mine ((this project-am-objectcode) buffer)
   "Return t if object THIS lays claim to the file in BUFFER."
-  (member (file-name-nondirectory (buffer-file-name buffer))
+  (member (file-relative-name (buffer-file-name buffer) (oref this :path))
          (oref this :source)))
 
 (defmethod ede-buffer-mine ((this project-am-texinfo) buffer)
   "Return t if object THIS lays claim to the file in BUFFER."
-  (let ((bfn (buffer-file-name buffer)))
-    (or (string= (oref this :name)  (file-name-nondirectory bfn))
-       (member (file-name-nondirectory bfn) (oref this :include)))))
+  (let ((bfn (file-relative-name (buffer-file-name buffer)
+                                (oref this :path))))
+    (or (string= (oref this :name)  bfn)
+       (member bfn (oref this :include)))))
 
 (defmethod ede-buffer-mine ((this project-am-man) buffer)
   "Return t if object THIS lays claim to the file in BUFFER."
-  (string= (oref this :name) (buffer-file-name buffer)))
+  (string= (oref this :name)
+          (file-relative-name (buffer-file-name buffer) (oref this :path))))
 
 (defmethod ede-buffer-mine ((this project-am-lisp) buffer)
   "Return t if object THIS lays claim to the file in BUFFER."
-  (member (file-name-nondirectory (buffer-file-name buffer))
+  (member (file-relative-name (buffer-file-name buffer) (oref this :path))
          (oref this :source)))
 
 (defmethod project-am-subtree ((ampf project-am-makefile) subdir)
@@ -956,7 +956,6 @@ Kill the Configure buffer if it was not already in a buffer."
     (cond
      ;; Try configure.in or configure.ac
      (conf-in
-      (require 'ede/autoconf-edit)
       (project-am-with-config-current conf-in
        (let ((aci (autoconf-parameters-for-macro "AC_INIT"))
              (aia (autoconf-parameters-for-macro "AM_INIT_AUTOMAKE"))
@@ -982,7 +981,7 @@ Kill the Configure buffer if it was not already in a buffer."
                                (t acf))))
            (if (> (length outfiles) 1)
                (setq configfiles outfiles)
-             (setq configfiles (split-string (car outfiles) " " t)))
+             (setq configfiles (split-string (car outfiles) "\\s-" t)))
            )
          ))
       )
@@ -1007,6 +1006,18 @@ Calculates the info with `project-am-extract-package-info'."
     (when top (setq dir (oref top :directory)))
     (project-am-extract-package-info dir)))
 
+;; for simple per project include path extension
+(defmethod ede-system-include-path ((this project-am-makefile))
+  "Return `project-am-localvars-include-path', usually local variable
+per file or in .dir-locals.el or similar."
+  (bound-and-true-p project-am-localvars-include-path))
+
+(defmethod ede-system-include-path ((this project-am-target))
+  "Return `project-am-localvars-include-path', usually local variable
+per file or in .dir-locals.el or similar."
+  (bound-and-true-p project-am-localvars-include-path))
+
+
 (provide 'ede/project-am)
 
 ;; arch-tag: 528db935-f186-4240-b647-e305c5b784a2