Apart from using a wrapper, is there any way to use getopts-style arguments (e.g., -v or -n 3 or --some_parameter=7) in matlab programs compiled using mcc?

2 Answers

3
gnovice On Best Solutions

If you want to create getopt-like command-line functionality for your MATLAB programs (compiled or not), then using an inputParser object (typically the best approach to input handling) might not be your best option. The inputParser functionality is geared well towards function arguments that follow a specific ordering (i.e. positioning within the argument list) and which follow the "parameter/value pair" format. Typical getopt style functionality involves option lists that are not required to follow a specific ordering and have both "option only" (e.g. -v) or "option with argument" (e.g. -n 3 or --some_parameter=7) formats.

You'll likely need to add your own input parsing routines at the very beginning of your compiled program. As mentioned here and here, when you use command syntax to call your program, the inputs are all passed as a series of character vectors. If you define a function with a variable input argument list like so:

function getopt_example(varargin)

Then calling the function as follows:

getopt_example -v -n 3 --some_parameter=7

will result in varargin having the following contents:

  1×4 cell array

    {'-v'}    {'-n'}    {'3'}    {'--some_parameter=7'}

It will then be necessary to iterate over this cell array, parsing the options and setting/storing arguments accordingly (after converting them from character vectors to numeric values as needed). There are many ways you could implement this, depending on what option formats you want to allow. Here's an example of one way to parse the type of sample arguments you mention above:

function getopt_example(varargin)

  % Define opts as {'name', has an argument, default value}:
  opts = {'v', false, false; ...              % No argument, default unset
          'n', true, 1; ...                   % double argument, default 1
          'some_parameter', true, uint8(0)};  % uint8 argument, default 0
  args = {};  % Captures any other arguments

  % Parse input argument list:
  inputIndex = 1;
  while (inputIndex <= nargin)

    opt = varargin{inputIndex};
    if strcmp(opt(1), '-') || strcmp(opt(1:2), '--')  % A command-line option

      % Get option and argument strings:
      opt = strip(opt, 'left', '-');
      [opt, arg] = strtok(opt, '=');
      [isOpt, optIndex] = ismember(opt, opts(:, 1));
      assert(isOpt, 'Invalid input option!');

      if opts{optIndex, 2}  % Has an argument

        if isempty(arg)  % Argument not included with '='
          assert(inputIndex < nargin, 'Missing input argument!');
          arg = varargin{inputIndex+1};
          inputIndex = inputIndex+2;
        else  % Argument included with '='
          arg = arg(2:end);
          assert(~isempty(arg), 'Missing input argument!');
          inputIndex = inputIndex+1;
        end

        % Convert argument to appropriate type:
        argType = class(opts{optIndex, 3});
        if ~strcmp(argType, 'char')
          arg = cast(str2double(arg), argType);
          assert(~isnan(arg), 'Invalid input option format!');
        end
        opts{optIndex, 3} = arg;

      else  % Has no argument

        opts{optIndex, 3} = true;
        inputIndex = inputIndex+1;

      end

    else  % A command-line argument

      args = [args {opt}];
      inputIndex = inputIndex+1;

    end

  end

  % Display results:
  disp(opts(:, [1 3]));
  disp(args);

end

The opts cell array initially stores the possible options, if they have an associated argument, and what the default value is. After parsing the input arguments, the default values will be overwritten by any values passed to the function. The args cell array captures any arguments that don't match any options. Here are some sample inputs and results:

>> getopt_example -v -n 3 --some_parameter=7  % Sample inputs
    'v'                 [1]
    'n'                 [3]
    'some_parameter'    [7]

>> getopt_example -n 3 --some_parameter=7  % Omit -v option
    'v'                 [0]
    'n'                 [3]
    'some_parameter'    [7]

>> getopt_example -v -n --some_parameter=7  % Omit argument for -n option
Error using getopt_example (line 38)
Invalid input option format!

>> getopt_example -v -b --some_parameter=7  % Pass invalid -b option
Error using getopt_example (line 20)
Invalid input option!

>> getopt_example -v -n 3 --some_parameter=7 a1  % Pass additional argument a1
    'v'                 [1]
    'n'                 [3]
    'some_parameter'    [7]

    'a1'
1
peterfranciscook On

It sounds like you are looking for an inputParser object.

edited based on comment about link-only answer.

Here's some example usage for a function which has 2 required inputs & 2 optional parameters:

function hObj = dasImagePrototype(hAx, dasStruct, varargin)

% ...

defaultDepthUnit = getpref('HOTB', 'units_unitSystem', 1);

p = inputParser;
p.addRequired('hAx', @(x) isa(x, 'matlab.graphics.axis.Axes'))
p.addRequired('dasStruct', @(x) isstruct(x) && isfield(x,'psd'))
p.addParameter('depthUnit', defaultDepthUnit, @(x) ismember(x,1:2))
p.addParameter('whichFbe', 1, @(x) floor(x)==x && x>0)
p.parse(hAx, dasStruct, varargin{:})

% access hAx & dasStruct directly since they're `Required` inputs
% but we still pass them to the input parser anyways to validate
hObj.hAx = hAx;
hObj.dasStruct = dasStruct; 

% note that since depthUnit & whichFbe are `Parameter` and not 
% `Required` inputs, we need to access them from the p object
hObj.depthUnit = p.Results.depthUnit;
hObj.whichFbe = p.Results.whichFbe;