1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
|
;;; matlab--access.el --- MATLAB access -*- lexical-binding: t -*-
;; URL: https://github.com/mathworks/Emacs-MATLAB-Mode
;; SPDX-License-Identifier: GPL-3.0-or-later
;;
;; Author: John Ciolfi <john.ciolfi.32@gmail.com>
;; Copyright (C) 2001-2025 Free Software Foundation, Inc.
;;
;; This file is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published
;; by the Free Software Foundation, either version 3 of the License,
;; or (at your option) any later version.
;;
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this file. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; Access to the MATLAB installation:
;; `matlab--platform' - "glnxa64", "maca64", "win64", etc.
;; `matlab--get-abs-matlab-exe' - full path to the MATLAB executable
;; `matlab--get-mlint-exe' - path to the MLint executable, which
;; should be an absolute path, but not
;; guaranteed
;; These should only be used by other matlab*.el files.
;;
;; In 2025, code which was written years back was moved from other files
;; to this file.
;;; Code:
(require 'cl-macs)
;;; matlab--platform
(defvar matlab--platform
;; See
;; >> lower(computer)
;; MATLABROOT/bin/util/arch.sh (or arch.bat)
(cond ((eq system-type 'darwin)
(cond
((string-match "^arm" system-configuration) ;; e.g. arm-apple-darwin20.3.0
"maca64")
((string-match "^x86_64" system-configuration)
"maci64")
((string-match "^i386" system-configuration)
(let ((mt (getenv "MACHTYPE")))
(if (and (stringp mt) (string= "x86_32" mt))
;; This hack is bad since an Emacs started from
;; the doc doesn't have this variable, thus by defaulting
;; to checking the 32 bit (not common anymore) version,
;; we'll get the right answer most of the time.
"maci" "maci64")))
(t
"mac")))
((eq system-type 'gnu/linux)
(cond ((string-match "64\\|i686" system-configuration)
"glnxa64")
(t "glnx86")))
((eq system-type 'solaris)
"sol2")
((eq system-type 'hpux)
"hpux")
((eq system-type 'windows-nt)
;; Thought about checking the env PROCESSOR_ARCHITEW6432,
;; but this said AMD on my Intel, which seemed suspicious.
(let ((proc (getenv "PROCESSOR_IDENTIFIER")))
(if (and (stringp proc) (string-match "64" proc))
"win64"
"win32")))
(t "unknown"))
"MATLAB platform. See >> lower(computer).")
;;; MATLAB command (full path to matlab executable)
(defgroup matlab-shell nil
"MATLAB shell mode."
:prefix "matlab-shell-"
:group 'matlab)
(defcustom matlab-shell-command "matlab"
"The MATLAB command executable used to start MATLAB.
This can be:
- the name of the MATLAB command (e.g. \"matlab\") which is
found on the system PATH.
- an absolute path to the matlab executable. For example,
\"/<path-to-MATLAB-install-dir>/bin/matlab\"
If matlab-shell-command is set to \"matlab\" and \"matlab\" is not
on the system PATH, `matlab-shell' will look for the matlab
command executable in the default MATLAB installation locations."
:type 'string
:group 'matlab-shell)
;;; matlab executable and matlabroot
(defvar matlab--default-matlab-exe
'((gnu/linux . "/usr/local/MATLAB/R*/bin/matlab")
(darwin . "/Applications/MATLAB_R*.app/bin/matlab")
(windows-nt . "C:/Program Files/MATLAB/R*/bin/matlab.exe"))
"Standard MATLAB command installation locations, SYSTEM => GLOB.")
(defun matlab--matlab-exe-not-found (no-help-window &optional default-loc)
"Signal error, MATLAB command not on system PATH or in optional DEFAULT-LOC.
If NO-HELP-WINDOW is t, do not show the help window"
(let ((msg (format "Unable to locate \"%s\" on the system PATH%s"
matlab-shell-command
(if default-loc
(format " or in the default installation location, %s"
default-loc)
""))))
(when (not no-help-window)
(let ((help-buf-name "*matlab-shell-help*"))
(with-current-buffer (get-buffer-create help-buf-name)
(with-help-window help-buf-name
(insert msg "
To fix, update your system PATH to include
\"/<path-to-MATLAB-install>/bin\"
To verify matlab is on your path, run \"matlab -h\" in a terminal.
Alternatively, you can provide the full path to the
MATLAB command executable by customizing option
`matlab-shell-command'\n")))))
(user-error "%s" msg)))
(cl-defun matlab--get-abs-matlab-exe (&optional no-error)
"Absolute path to the MATLAB executable.
When `matlab-shell-command' is an absolute path, then this will
be resolved to its true name. Otherwise, `matlab-shell-command'
is found using `executable-find'. If `matlab-shell-command' is
\"matlab\" and not the system PATH, this will return the latest
MATLAB installed command found using
`matlab--default-matlab-exe'.
If NO-ERROR is t, and matlab command is not found, nil is return,
otherwise an error is signaled."
(condition-case err
(let (abs-matlab-exe)
(cond
;;Case: the path to the matlab executable was provided, validate it exists and
;; return it.
((file-name-absolute-p matlab-shell-command)
(when (not (file-exists-p matlab-shell-command))
(user-error "Invalid setting for `matlab-shell-command', %s does not exist"
matlab-shell-command))
(when (not (file-executable-p matlab-shell-command))
(user-error "Invalid setting for `matlab-shell-command', %s is not executable"
matlab-shell-command))
;; Use the path provided. Consider the case where a launcher script is provided and the
;; launcher script is symlink'd. In this case, we shouldn't resolve the symlinks, i.e.
;; using file-truename would break this case.
(setq abs-matlab-exe matlab-shell-command))
;; Case: set to a relative path
;;
((when (file-name-directory matlab-shell-command)
(user-error "Relative paths are not supported for `matlab-shell-command', %s"
matlab-shell-command)))
;; Case: "matlab" (or something similar), locate it on the executable path
;; else locate in standard install locations.
(t
(let ((remote (file-remote-p default-directory)))
(if remote
(if (setq abs-matlab-exe (executable-find matlab-shell-command t))
(setq abs-matlab-exe (concat remote abs-matlab-exe))
(user-error "Unable to locate matlab executable on %s
See https://github.com/mathworks/Emacs-MATLAB-Mode/doc/remote-matlab-emacs.org for tips" remote))
;; else look local
(setq abs-matlab-exe (executable-find matlab-shell-command))
(when (not abs-matlab-exe)
(if (string= matlab-shell-command "matlab")
;; Get latest matlab command exe from the default installation location.
(let* ((default-loc (cdr (assoc system-type matlab--default-matlab-exe)))
(default-matlab (when default-loc
(car (last (sort
(file-expand-wildcards default-loc)
#'string<))))))
(when (not default-matlab)
(matlab--matlab-exe-not-found no-error default-loc))
(when (not (file-executable-p default-matlab))
(user-error "%s is not executable" default-matlab))
(setq abs-matlab-exe default-matlab))
;; else unable to locate it
(matlab--matlab-exe-not-found no-error)))))))
;; Return existing absolute path to the MATLAB command executable
abs-matlab-exe)
(error (when (not no-error) (error "%s" (error-message-string err))))))
(defun matlab--get-matlabroot ()
"Return the MATLABROOT from `matlab--get-abs-matlab-exe'.
The returned MATLABROOT does not have a trailing slash.
Returns nil if unable to determine the MATLABROOT."
;; strip "/bin/matlab" from /path/to/matlabroot/bin/matlab
(let ((abs-matlab-exe (matlab--get-abs-matlab-exe 'no-error)))
(when abs-matlab-exe
(let ((bin-dir (directory-file-name (file-name-directory abs-matlab-exe))))
;; matlabroot no slash
(directory-file-name (file-name-directory bin-dir))))))
;;; emacsclient
(defun matlab--find-emacsclient ()
"Locate the emacsclient corresponding for current Emacs.
Emacs binary is defined by variable `invocation-name' in variable
`invocation-directory'"
(let ((ec "emacsclient"))
(cond
;; Mac
((equal system-type 'darwin)
(if (file-exists-p (concat invocation-directory "emacsclient")) ;; running the default emacs?
(setq ec (concat invocation-directory "emacsclient"))
;; On Mac, one can install into
;; /Applications/Emacs.app/Contents/MacOS/Emacs
;; /Applications/Emacs.app/Contents/MacOS/bin/emacsclient
(if (file-exists-p (concat invocation-directory "bin/emacsclient"))
(setq ec (concat invocation-directory "bin/emacsclient")))))
;; Windows
((equal system-type 'windows-nt)
(if (file-exists-p (concat invocation-directory "emacsclientw.exe"))
(setq ec (concat invocation-directory "emacsclientw.exe"))
(error "Unable to locate emacsclientw.exe. It should be in %s" invocation-directory)))
;; Linux or other UNIX system
(t
;; Debian 9 can be setup to have:
;; /usr/bin/emacs
;; /usr/bin/emacsclient
;; /usr/bin/emacs24
;; /usr/bin/emacsclient.emacs24
;; /usr/bin/emacs25
;; /usr/bin/emacsclient.emacs25
(if (and (equal invocation-name "emacs")
(file-exists-p (concat invocation-directory "emacsclient")))
(setq ec (concat invocation-directory "emacsclient"))
(if (file-exists-p (concat invocation-directory "emacsclient." invocation-name))
(setq ec (concat invocation-directory "emacsclient." invocation-name))))))
;; Return, ec, the emacsclient to use
ec))
;;; mlint
(defgroup mlint nil
"MLint minor mode."
:prefix "mlint-"
:group 'matlab)
(defcustom mlint-programs (list "mlint")
"*List of possible mlint programs.
First entry in the list that exists is used.
The \"mlint\" entry means use mlint next to the
matlab executable defined by `matlab-shell-command'.
Other entries should be absolute paths."
:group 'mlint
:type '(repeat (file :tag "MLint Program: ")))
(defun matlab--get-mlint-exe ()
"Return MLint executable or nil if not found.
The returned executable will be the full path to mlint. If we resolved
the \"mlint\" entry in `mlint-programs', in which case this is the mlint
next to the matlab found by `matlab--get-abs-matlab-exe'. If we
resolved another entry in `mlint-programs', we'll use that and by
convention that entry should be an absolute path, but that's not
guaranteed. Nil is returned if mlint is not found."
(let (mlint-exe)
(cl-loop for mlint in mlint-programs do
(if (string= mlint "mlint")
(let ((matlab-exe (matlab--get-abs-matlab-exe 'no-error)))
(when matlab-exe
(setq mlint-exe
(replace-regexp-in-string "matlab\\(\\.exe\\)?\\'"
(concat matlab--platform "/mlint\\1")
matlab-exe))
(cl-return)))
(when (file-executable-p mlint)
;; We can't use file-truename on mlint because that would resolve
;; symbolic links.
(setq mlint-exe mlint)
(cl-return))))
mlint-exe))
(provide 'matlab--access)
;;; matlab--access.el ends here
;; LocalWords: SPDX gmail maca MLint darwin maci MACHTYPE stringp linux glnx hpux nt env ARCHITEW
;; LocalWords: defcustom usr defun buf symlink'd truename setq cdr emacsclient ec emacsclientw
|