tags:

views:

35

answers:

0

The Octave documentation on this subject is both intimidating and sparse.

I did not know where else to document the solution I found, so I am posting here. I apologize if that's inappropriate, but I want to help the next guy.

The following solution is for a simple windows distributable.

Use Case:
A solution is developed in Octave 3.2.4, and needs to be distributed to end-users with few computer skills. Installing and explaining Octave is impossible, the solution must be "one-click" or "brain-dead-simple."

Known Issues:
imread fails in 3.2.4 because file_in_path.m is wrong. You will need to update the file file_in_path.m to the following (just replace it):

function name=file_in_path(p,file)
  idx=[1 findstr(p,pathsep) length(p)+1];
  for i=1:length(idx)-1
    if idx(i+1)-idx(i)<=1
      dir=strcat(pwd,"/");
    else
      dir=p(idx(i)+1:idx(i+1)-1);
    end
    name = fullfile(dir, file);
    fid = fopen(name,"r");
    if fid >= 0
      fclose(fid);
      return
    end
  end
  fid = fopen(file,"r");
  if fid >= 0,
    fclose(fid);
    name=file;
    return
  end
  name=[]; 

Solution:
Create a distributable exe using mkoctfile, and package this exe with the core Octave files, and other .oct and .m files as necessary.

Step 1: Create a stand-alone executable.

You can see code that works here: http://www.gnu.org/software/octave/doc/interpreter/Standalone-Programs.html

Particularly the file "embedded.cc".

I have simplified that file as follows:

#include <iostream>
#include <octave/oct.h>
#include <octave/octave.h>
#include <octave/parse.h>

int
main (int argc, char *argvc[])
{
  string_vector argv (2);
  argv(0) = "embedded";
  argv(1) = "-q";

  octave_main (2, argv.c_str_vec(), 1);

  octave_value_list in = octave_value (argvc[1]);
  octave_value_list out = feval ("your_custom_m_file", in);

  if (!error_state && out.length () > 0)
    {
    }
    else
    {
        std::cout << "invalid\n";
    }

  return 0;
}

Build this file with the command

mkoctfile --link-stand-alone embedded.cc -o embedded

It may throw warnings, but as long as it throws no errors, you should be fine. The file embedded.exe will be built, and can be run. The only issue is that it will lack all the goodies that make octave awesome. You will have to provide those.

Step 2: Create a distribution folder

You will need to create a copy of many of the Octave files. I suggest a directory specifically for this. At a minimum, you will need a copy of all or most of the DLLs in \bin. Additionally, place your distributable executable in this directory.

Step 3: Other files whack-a-mole

You will now need to find out what other files will be necessary to run your .m script. You can simplify this step by copying \oct\i686-pc-mingw32*.oct and \share\octave\3.2.4\m\\.m to the distribution directory, although this will be overkill, and will not actually prevent the whack-a-mole step.

Now, you must play whack-a-mole or the time-honored tradition of "where my includes be at, yo?"

  1. Open a cmd prompt and navigate to your distribution folder.
  2. Get rid of any useful PATH strings. Your customers won't have them.
  3. Attempt to run the program embedded.exe. You will get an error such as the following:

    embedded.exe
    error: `max' undefined near line 83 column 22
    error: evaluating argument list element number 1
    error: evaluating argument list element number 1
    error: called from:
    error: T:\sms\Development\research\c2\disttest\strcat.m at line 83, column 3
    error: T:\sms\Development\research\c2\disttest\file_in_path.m at line 5, column 10
    error: T:\sms\Development\research\c2\disttest\imread.m at line 50, column 6

4A. Search in your Octave installation for "max". It will either be a .oct or a .m file. In this case, it is a .oct file, max.oct. Copy it to your distribution directory.

4B. You search for something obvious like "min", and get no results. This is because the Loadable Function "min" is in the .oct file "max.oct". Make a copy of max.oct, and rename it to min.oct. It will work now. How do you know where the functions are? I'm not sure. Most of them are in obvious places like "max.oct" for min, and "fft2.oct" for "ifft2.oct". Good luck with all that.

  1. Repeat until your executable runs.