Get the location of a deployed Matlab application at runtime for Mac and Linux
Asked Answered
D

4

10

I have some standalone Matlab programs that for different reasons need to access files in the directory they're located (either to launch another program or to read some XML files there). I have the following function that works for Windows:

function execDir = get_deployed_exec_dir()
% Returns the directory of the currently running executable, if deployed,
% an empty string if not deployed (or if unable to determine the directory)
execDir = '';
if isdeployed
    [status, execDir] = system('path');
    if status == 0
        execDir = char(regexpi(execDir, 'Path=(.*?);', 'tokens', 'once'));
    end
end

To get it to work for Linux and Mac I figured I could replace system('path') with system('echo $PATH') and alter the regular expression to fit Unix syntax, but unlike with Windows the directory of the currently running executable doesn't seem to be automatically added to the front of the path variable. Is there a way within Matlab to get the directory of the currently running executable (I know there is for the script, but that doesn't seem to work properly when deployed), or should I edit the script that sets up the MCR before running the application to set a variable that my code can read with the system command?

For concreteness, somewhere on the user's computer is the folder EXECFOLDER, with the structure:

EXECFOLDER
| exec1
| exec2
| run_exec1.sh
| run_exec2.sh
| data.xml

I want to figure out the path to EXECFOLDER regardless of where the user is running run_exec1.sh (script that sets up the MCR and calls exec1), so that exec1 can read from data.xml and execute exec2.

Summary Of Attempts:

  • system('echo $PATH'): executable directory is not on the path in Mac and Linux
  • matlabroot: location of the MCR
  • pwd: user's current folder, which may differ from the executable's location when it's run with a full path
  • dbstack: location of unpackaged .m file
  • which: location of unpackaged .m file
  • fileattrib: location of unpackaged .m file
Dominicadominical answered 25/7, 2013 at 18:59 Comment(7)
I'm not completely clear on what you need. Can a deployed Matlab application use matlabroot? And what is the state of pwd when the program launches? There are of course the *NIX commands which and whereis, but these seem heavy-handed.Bonanno
In a deployed application, matlabroot provides you with the location of the MCR being used. pwd gives you the location the user is in in the terminal (where they called the application), but for our program people tend to navigate to where their data is and call the program using it's full path, so where the executables actually are is different from the user's current directory. I was wondering if there's a way in Matlab to get that information without having to set up an environment variable in the Bash script you use to start up the program.Dominicadominical
I can't test this, but I think I have a better idea of what you're asking. With respect to the MCR, the deployed applications work kind of like M-file functions with respect to Matlab. In that case could you call stack = dbstack('-completenames') fullpath = stack.Name to get the full path of the currently running program? Other things to try might be Matlab's which (with '-all' flag maybe) or maybe fileattrib.Bonanno
dbstack, which, and fileattrib all seem to give me the location where the .m files are unpackaged for the MCR to run, rather than their original location in the executable. I'm beginning to think that that might be as good as you can do within Matlab code itself due to the way it's run.Dominicadominical
No idea then. You can run pretty much any *NIX command via the system and unix function, so you may need to find a solution there (e.g., which, whereis, and maybe even some form of ps). Have you asked this question over at MatlabCentral? It seems like something that one should be able to obtain.Bonanno
There's also lsof on OS X and and some other forms of UNIX and /proc/<PID>/ on Linux that might be helpful.Bonanno
Could really use some feedback on the existing answers, as it's hard for me to see which one deserves the bounty.Apomorphine
K
4

Does the function ctfroot do what you need?

ctfroot is a command from MATLAB Compiler. From the documentation:

root = ctfroot returns a string that is the name of the folder where the deployable archive for the deployed application is expanded.

You probably want to use the command ctfroot only within an if isdeployed block.

Edit

If you need the location of the executable, rather than the location to which it is expanded, you can use the following function:

function currentDir = getcurrentdir
if isdeployed % Stand-alone mode.
    [status, result] = system('path');
    currentDir = char(regexpi(result, 'Path=(.*?);', 'tokens', 'once'));
else % MATLAB mode.
    currentDir = pwd;
end

This works as the path to the executable is added to the PATH variable as the first entry by the executable at runtime.

Alternatively, you can create a MEX file that will perform a similar job. See this MathWorks support answer for more details, and for an example MEX file.

Keare answered 15/1, 2015 at 14:5 Comment(6)
Is the place where it is 'expanded' the same as the place where it is located? And as I can't test it myself: does one consider this answer to be better or worse than the answer by @janus?Apomorphine
@DennisJaheruddin added more info that might answer your question more directly.Keare
I can't check it myself, but do you mean that this concern has been addressed? "but unlike with Windows the directory of the currently running executable doesn't seem to be automatically added to the front of the path variable"Apomorphine
I would have preferred to be more sure before awarding the bounty,but I guess you deserve the benefit of the doubt!Apomorphine
Sorry @DennisJaheruddin, I didn't get time to respond to your comment yesterday. I'm afraid I don't have convenient access to a non-Windows platform to test whether my solution works there (either the getCurrentDir solution or the MEX-file solution). It may be that Janus's answer is preferable on LInux/Mac, I don't know. Thanks for the bounty, but if you want to reassign it, no worries.Keare
Your system('path') solution worked for me for a compiled Windows application, thanks for the helpAbbie
T
2

Any progress on this?

What you need to do (for both platforms) is to access the 0th argument passed by the shell to the executable. One way of doing this could be to wrap the call to the executable in scripts and pass the location explicitly:

myapp.bat:

set scriptpath=%~d0%~p0
"%scriptpath%%~n0%.exe" --ExecutablePath="%scriptpath%" %*

Or, if you don't want the CMD window to stay around

myapp.bat:

set scriptpath=%~d0%~p0
start "%~n0" "%scriptpath%%~n0%.exe" --ExecutablePath="%scriptpath%" %*

Bash is actually harder (see this question), but something like this might work:

myapp.sh

#!/bin/bash
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
"${SCRIPTPATH}/myapp.o" --ExecutablePath="${SCRIPTPATH}" $*
Tejeda answered 29/11, 2013 at 7:41 Comment(1)
As I can't test it myself: does one consider this answer to be better or worse than the answer by @SamRoberts?Apomorphine
P
1

Maybe you need:

curr_dir = strrep(which(mfilename('fullpath')),mfilename,'')

which will provide you the dir of the .m file which is currently running.

Poriferous answered 14/1, 2015 at 9:56 Comment(0)
L
1

Mac: To get the location of an installed executable MyDeployedApplication.app on Mac from within the deployed app itself, try the following:

if isdeployed && ismac
    NameOfDeployedApp = 'MyDeployedApplication'; % do not include the '.app' extension
    [~, result] = system(['top -n100 -l1 | grep ' NameOfDeployedApp ' | awk ''{print $1}''']);
    result=strtrim(result);
    [status, result] = system(['ps xuwww -p ' result ' | tail -n1 | awk ''{print $NF}''']);
    if status==0
        diridx=strfind(result,[NameOfDeployedApp '.app']);
        realpwd=result(1:diridx-2);
    else
        msgbox({'realpwd not set:',result})
    end
else
    realpwd = pwd;
end

This solution uses the 'ps', 'grep', and 'top' terminal commands, assumes the user has a single instance of MyDeployedApplication.app currently running, and has been tested on MAC OS Yosemite 10.10.5 with MATLAB Compiler 2015a only.

Note: While pgrep worked to return the PID of the deployed, currently running application from outside of the application (directly in Terminal or in an open MATLAB session), it did not return anything from within the application. Hence the use of top and grep.

Linux: To get the path of the installed executable on Linux, change the syntax of Sam's answer to Linux style:

[status, result] = system('echo $PATH');
realpwd = char(regexpi(result, '(.*?):', 'tokens', 'once'));        
Lives answered 11/7, 2016 at 20:46 Comment(2)
Note: I am technically unable to respond to @dennis-jaheruddin 's outstanding question on sam-roberts's answer, so I'll put it here for now: the extra solution in Sam's edit section works for Windows but does not work for Mac, as the original questioner had found. This is because Mac does not add the executable path to the path variable when the deployed application launches. But even if it did, the command would need to be 'echo $PATH', not 'path' and the parsing that happens afterward would need to use a colon instead of a semicolon as Mac uses the semicolon as a delimiter, like Linux.Lives
Dear Marianne, what about a solution for Windows ?Estate

© 2022 - 2024 — McMap. All rights reserved.