Makefiles generated by jmaker didn't work if generated classes didn't go
in the same directory than sources.
Here is a modification that had two variables and a function.
- jmaker-dest-dir : directory where sources are to be compiled.
- jmaker-source-path : directories where sources can be found.
- jmaker-dir-package-part (&optional directory path-list) "return
the package part from a directory name and a source path list."
jmaker-dir-package-part() is used in template to generated full path
name to compiled classes.
to use it with jde:
make jmaker-dest-dir points to jmaker-dest-dir
and jmaker-source-path points to jde-db-source-directories
Eric.
-----------------------------------------------------------------------------------------
(require 'jde)
(require 'tempo)
(defconst jmaker-version "$Revision: 1.10 $"
"jmaker version number.")
(defgroup jmaker nil
"Java Makefile Maker Environment"
:group 'tools
:prefix "jmaker-")
(defcustom jmaker-dest-dir ""
"Directory where source files are to be compiled"
:group 'jmaker
:type 'string)
(defcustom jmaker-source-path ""
"List of source directory paths."
:group 'jmaker
:type '(repeat (file :tag "Path")))
(defcustom jmaker-makefile-buffer-template
'(
"\"####\" 'n"
"\"#### Java Makefile automatically generated by jmaker \""
"(jmaker-version-number) 'n"
"\"#### Creation date: \" (current-time-string) 'n"
"\"####\" 'n"
"'n"
"\"#### Java compiler settings\" 'n"
"\"JAVAC = \" jde-compiler 'n"
"\"JAVAC_FLAGS = \" (jde-get-compile-options) 'n"
"\"DEST_DIR = \" (jmaker-relative-dest-dir) 'n"
"\"PACKAGE_DIR = \" (jmaker-dir-package-part) 'n"
"'n"
"\"#### Build Rules\" 'n"
"\"$(DEST_DIR)$(PACKAGE_DIR)%.class: %.java\" 'n"
"\"\\t$(JAVAC) $(JAVAC_FLAGS) $<\" 'n"
"'n"
"\"#### Global target\" 'n"
"(jmaker-all-target)"
"'n"
"\"#### Single targets\" 'n"
"(jmaker-file-targets)"
"'n"
"\"#### Cleanup\" 'n"
"\"clean:\" 'n"
"\"\\t$(RM) *.class\" 'n"
"'n"
"\"#### Rebuild\" 'n"
"\"build:\\tclean all\" 'n"
"'n"
"\"#### Usage\" 'n"
"\"help:\" 'n"
"\"\\t@echo \\\"Usage: make [all|<single
target>|clean|build|help]\\\"\" 'n"
"\"\\t@echo \\\" all - build all as needed
(default)\\\"\" 'n"
"\"\\t@echo \\\" <single target> - build the given file as
needed\\\"\" 'n"
"\"\\t@echo \\\" clean - remove all .class files\\\"\"
'n"
"\"\\t@echo \\\" build - build all inconditionnally\\\"\"
'n"
"\"\\t@echo \\\" help - display this help\\\"\" 'n"
"'n"
)
"*Template for Java Makefile.
Setting this variable defines a template instantiation
command `jmaker-insert-makefile', as a side-effect."
:group 'jmaker
:type '(repeat string)
:set '(lambda (sym val)
(defalias 'jmaker-insert-makefile
(tempo-define-template "jmaker-makefile-buffer-template"
(jde-gen-read-template val)
nil
"Insert a Java Makefile in the
current buffer."))
(set-default sym val)))
(defcustom jmaker-meta-makefile-buffer-template
'(
"\"####\" 'n"
"\"#### Java meta Makefile automatically generated by jmaker \""
"(jmaker-version-number) 'n"
"\"#### Creation date: \" (current-time-string) 'n"
"\"####\" 'n"
"'n"
"\"#### Sub-Makefiles targets\" 'n"
"(jmaker-sub-makefile-targets)"
"'n"
"\"#### Usage\" 'n"
"\"help:\" 'n"
"\"\\t@echo \\\"Usage: make [all|<single target>|help]\\\"\" 'n"
"\"\\t@echo \\\" all - build all as needed
(default)\\\"\" 'n"
"\"\\t@echo \\\" <single target> - build the given target as
needed\\\"\" 'n"
"\"\\t@echo \\\" help - display this help\\\"\" 'n"
"'n"
)
"*Template for Java meta Makefile.
Setting this variable defines a template instantiation
command `jmaker-insert-meta-makefile', as a side-effect."
:group 'jmaker
:type '(repeat string)
:set '(lambda (sym val)
(defalias 'jmaker-insert-meta-makefile
(tempo-define-template
"jmaker-meta-makefile-buffer-template"
(jde-gen-read-template val)
nil
"Insert a Java Makefile.meta in the
current buffer."))
(set-default sym val)))
(defun jmaker-customize ()
"Show the jmaker customization global options panel."
(interactive)
(customize-group "jmaker"))
(defun jmaker-version-number ()
"Returns jmaker version number."
(string-match "[0123456789.]+" jmaker-version)
(match-string 0 jmaker-version))
(defun jmaker-display-version ()
"Displays jmaker version."
(interactive)
(message "Using 'jmaker' version %s." (jmaker-version-number)))
(defun jmaker-relative-dest-dir ()
"return the compilation destination directory relative toward current
directory"
(file-relative-name jmaker-dest-dir default-directory)
)
(defun jmaker-dir-package-part (&optional directory path-list)
"return the package part from a directory name and a source path
list."
(let* (
(dir (or directory default-directory))
(path (or path-list jmaker-source-path))
(expanded-file-name (file-name-as-directory (expand-file-name
dir)))
(m (string-match (concat "^" (regexp-quote (expand-file-name
(file-name-as-directory (car path)))) "\\(.*\\)") expanded-file-name))
(path-cdr (cdr path)))
(cond (m (file-name-directory (match-string 1 expanded-file-name)))
(path-cdr (jmaker-dir-package-part dir path-cdr))
(t nil))))
(defun jmaker-all-target ()
"Returns a Makefile string for the `all' target. It is build with the
name
of all `.java' files in the current directory. If the current directory
contains
Sample1.java and Sample2.java `jmaker-all-target' returns:
all: \
Sample1 \
Sample2
"
(concat "all:\t\\\n"
(mapconcat '(lambda (name) (concat "\t" name))
(jmaker-get-java-names)
" \\\n")
"\n"))
(defun jmaker-file-targets ()
"Returns a Makefile string for java file targets. It is build with the
name
of all `.java' files in the current directory. If the current directory
contains
Sample1.java and Sample2.java `jmaker-file-targets' returns:
Sample1: Sample1.class
Sample2: Sample2.class
"
(mapconcat '(lambda (name) (concat name ":\t"
(jmaker-relative-dest-dir) (jmaker-dir-package-part) name ".class\n"))
(jmaker-get-java-names)
""))
(defun jmaker-get-java-names ()
"Returns a list of all java file names without extension in the
current directory."
(mapcar 'file-name-sans-extension
(directory-files default-directory nil ".\\.java$")))
(defun jmaker-sub-makefile-targets ()
"Returns a string which contains `Makefile' rules to recursively make
all `Makefile'
files found in the subdirectories of `default-directory'. The result
looks like the
following:
\"all: \
test \
test.essai1 \
other
test: FORCE
cd test; $(MAKE)
test.essai1: FORCE
cd test/essai1; $(MAKE)
other: FORCE
cd other; $(MAKE)
FORCE:
\"
"
(let ((subdir-list (mapcar '(lambda (x) (directory-file-name
(file-name-directory x)))
(jmaker-get-makefiles-in-tree
default-directory))))
(concat "all:\t\\\n"
(mapconcat '(lambda (dir)
(concat "\t"
(jmaker-convert-directory-to-package dir)))
subdir-list
" \\\n")
"\n\n"
(mapconcat '(lambda (dir)
(concat (jmaker-convert-directory-to-package
dir)
":\tFORCE\n\tcd " dir "; $(MAKE)\n"))
subdir-list
"\n")
"\nFORCE:\n"
)
)
)
(defun jmaker-convert-directory-to-package (dir)
"Converts the given directory to a Java package form
by replacing '/' by '.' and removing extra '/' at end."
(mapconcat 'identity
(split-string dir "/")
"."))
(defun jmaker-get-makefiles-in-tree (root)
"Returns the list of `Makefile' files found in the subdirectories of
the
given `root' directory. Each file path is relative to the `root'
directory."
(message "Searching Makefiles, please wait...")
(jmaker-get-makefiles-in-tree-aux root root))
(defun jmaker-get-makefiles-in-tree-aux (root dir)
"Auxiliary function used by `jmaker-get-makefiles-in-tree'.
`root' is the top root directory. `dir' is a subdirectory in `root'
tree."
(let ((dir (file-name-as-directory dir)))
(mapcan '(lambda (f)
(let ((rel-f (concat dir f)))
(unless (or (string= f ".") (string= f "..")
(not (file-directory-p rel-f)))
(nconc
(and (file-readable-p (concat rel-f "/Makefile"))
(list (concat (file-relative-name rel-f root)
"/Makefile")))
(jmaker-get-makefiles-in-tree-aux root rel-f)))))
(directory-files dir))))
(defun jmaker-generate-makefile ()
"Generates a Java `Makefile' file which could be used to compile Java
files
in the current directory.
If the file `Makefile' already exists the command requires confirmation
to overwrite it."
(interactive)
(let ((makefile (concat (file-name-as-directory default-directory)
"Makefile")))
(and (file-exists-p makefile)
(or (y-or-n-p (format "File `%s' exists; overwrite? "
makefile))
(error "Canceled")))
(with-current-buffer (find-file-noselect makefile)
(makefile-mode)
(erase-buffer)
(jmaker-insert-makefile)
(goto-char (point-min))
(switch-to-buffer (current-buffer)))))
(defun jmaker-generate-meta-makefile (root)
"Generates the file `root'/Makefile.meta which could be used to
recursively make
all `Makefile' files found in the subdirectories of the given `root'
directory.
If the file `root'/Makefile.meta already exists the command requires
confirmation
to overwrite it."
(interactive "DDirectory: ")
(let ((makefile (concat (file-name-as-directory root)
"Makefile.meta")))
(and (file-exists-p makefile)
(or (y-or-n-p (format "File `%s' exists; overwrite? "
makefile))
(error "Canceled")))
(with-current-buffer (find-file-noselect makefile)
(makefile-mode)
(erase-buffer)
(jmaker-insert-meta-makefile)
(goto-char (point-min))
(switch-to-buffer (current-buffer)))))
(defvar jmaker-menu
(list "JMaker"
(list "New"
["Makefile..." jmaker-generate-makefile t]
["Meta-makefile..." jmaker-generate-meta-makefile t]
)
["Options..." jmaker-customize t]
["-" ignore nil]
(concat "jmaker " (jmaker-version-number))
)
"Menu for jmaker."
)
(if (not jde-xemacsp)
(easy-menu-do-define 'jmaker-menu
jde-mode-map
"Menu for jmaker."
jmaker-menu)
)
(provide 'jmaker)