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
Community
  • 1
  • 1
ackrause
  • 442
  • 5
  • 11
  • I'm not completely clear on what you need. Can a deployed Matlab application use [`matlabroot`](http://www.mathworks.com/help/matlab/ref/matlabroot.html)? 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. – horchler Jul 25 '13 at 21:18
  • 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. – ackrause Jul 26 '13 at 18:04
  • 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`](http://mathworks.com/help/matlab/ref/which.html) (with `'-all'` flag maybe) or maybe [`fileattrib`](http://mathworks.com/help/matlab/ref/fileattrib.html). – horchler Jul 26 '13 at 18:39
  • `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. – ackrause Jul 26 '13 at 20:42
  • 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](http://www.mathworks.com/matlabcentral/answers/)? It seems like something that one should be able to obtain. – horchler Jul 26 '13 at 21:11
  • There's also `lsof` on OS X and and some other forms of UNIX and `/proc//` on Linux that might be helpful. – horchler Jul 26 '13 at 21:13
  • Could really use some feedback on the existing answers, as it's hard for me to see which one deserves the bounty. – Dennis Jaheruddin Jan 20 '15 at 11:31

4 Answers4

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.

Sam Roberts
  • 23,951
  • 1
  • 40
  • 64
  • 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? – Dennis Jaheruddin Jan 19 '15 at 08:56
  • @DennisJaheruddin added more info that might answer your question more directly. – Sam Roberts Jan 19 '15 at 11:00
  • 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" – Dennis Jaheruddin Jan 19 '15 at 11:04
  • I would have preferred to be more sure before awarding the bounty,but I guess you deserve the benefit of the doubt! – Dennis Jaheruddin Jan 21 '15 at 09:49
  • 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. – Sam Roberts Jan 21 '15 at 09:59
  • Your system('path') solution worked for me for a compiled Windows application, thanks for the help – Guy Starbuck Jul 27 '17 at 16:01
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}" $*
Community
  • 1
  • 1
Janus
  • 5,421
  • 2
  • 26
  • 37
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.

BerndGit
  • 1,530
  • 3
  • 18
  • 47
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'));        
Marianne
  • 121
  • 4
  • 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. – Marianne Jul 11 '16 at 20:51
  • Dear Marianne, what about a solution for Windows ? – FabioSpaghetti May 16 '20 at 22:58