简体   繁体   English

如何在不安装Octave的情况下创建简单的Octave可分发

[英]How do I create a simple Octave distributable without installing Octave

The Octave documentation on this subject is both intimidating and sparse. 关于这个主题的Octave文档既令人生畏又稀疏。

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. 在Octave 3.2.4中开发了一个解决方案,需要以很少的计算机技能分发给最终用户。 Installing and explaining Octave is impossible, the solution must be "one-click" or "brain-dead-simple." 安装和解释Octave是不可能的,解决方案必须是“一键式”或“脑死亡 - 简单”。

Known Issues: 已知的问题:
imread fails in 3.2.4 because file_in_path.m is wrong. imread在3.2.4中失败,因为file_in_path.m错误。 You will need to update the file file_in_path.m to the following (just replace it): 您需要将文件file_in_path.m更新为以下内容(只需替换它):

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. 解决方案:使用mkoctfile创建可分发的exe,并根据需要将此exe文件与核心Octave文件以及其他.oct和.m文件打包在一起。

Step 1: Create a stand-alone executable. 第1步:创建独立的可执行文件。

You can see code that works here: http://www.gnu.org/software/octave/doc/interpreter/Standalone-Programs.html 您可以在此处查看可用的代码: http//www.gnu.org/software/octave/doc/interpreter/Standalone-Programs.html

Particularly the file "embedded.cc". 特别是文件“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. 将构建embedded.exe文件,并且可以运行该文件。 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 第2步:创建分发文件夹

You will need to create a copy of many of the Octave files. 您需要创建许多Octave文件的副本。 I suggest a directory specifically for this. 我建议专门为此目录。 At a minimum, you will need a copy of all or most of the DLLs in \\bin. 至少,您需要\\ bin中所有或大多数DLL的副本。 Additionally, place your distributable executable in this directory. 此外,将可分发的可执行文件放在此目录中。

Step 3: Other files whack-a-mole 第3步:其他文件打击鼹鼠

You will now need to find out what other files will be necessary to run your .m script. 您现在需要找出运行.m脚本所需的其他文件。 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. 您可以通过将\\ oct \\ i686-pc-mingw32 * .oct和\\ share \\ octave \\ 3.2.4 \\ m \\ * \\ * .m复制到分发目录来简化此步骤,尽管这样做会有些过分,实际上并不会防止打鼹鼠的步骤。

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. 打开cmd提示符并导航到您的分发文件夹。
  2. Get rid of any useful PATH strings. 摆脱任何有用的PATH字符串。 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 embedded.exe
    error: `max' undefined near line 83 column 22 错误:'max'未定义在第83行第22列附近
    error: evaluating argument list element number 1 错误:评估参数列表元素编号1
    error: evaluating argument list element number 1 错误:评估参数列表元素编号1
    error: called from: 错误:来自:
    error: T:\\sms\\Development\\research\\c2\\disttest\\strcat.m at line 83, column 3 错误:第83行第3列的T:\\ sms \\ Development \\ research \\ c2 \\ disttest \\ strcat.m
    error: T:\\sms\\Development\\research\\c2\\disttest\\file_in_path.m at line 5, column 10 错误:第5行第10行的T:\\ sms \\ Development \\ research \\ c2 \\ disttest \\ file_in_path.m
    error: T:\\sms\\Development\\research\\c2\\disttest\\imread.m at line 50, column 6 错误:T:\\ sms \\ Development \\ research \\ c2 \\ disttest \\ imread.m在第50行第6列

  4. A Search in your Octave installation for "max". 在八度的安装搜索与“最大”。 It will either be a .oct or a .m file. 它将是.oct或.m文件。 In this case, it is a .oct file, max.oct. 在这种情况下,它是.oct文件,max.oct。 Copy it to your distribution directory. 将其复制到您的分发目录。

    B You search for something obvious like "min", and get no results. B你搜索明显像“min”这样的东西,并没有得到任何结果。 This is because the Loadable Function "min" is in the .oct file "max.oct". 这是因为可装载功能“min”位于.oct文件“max.oct”中。 Make a copy of max.oct, and rename it to min.oct. 制作max.oct的副本,并将其重命名为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". 他们中的大多数都在明显的地方,例如“max.oct”表示min,“fft2.oct”表示“ifft2.oct”。 Good luck with all that. 祝你好运。

  5. Repeat until your executable runs. 重复直到可执行文件运行。

Just to add that if you want to run a script instead of an m function, then the line of the embedded.cc: 只是要补充说,如果你想运行一个脚本而不是一个m函数,那么embedded.cc的行:

octave_value_list out = feval ("your_custom_m_file", in);

should be: 应该:

octave_value_list out = feval ("your_custom_m_script");

Also use 'which' to find where the missing functions are packed. 还可以使用'which'来查找丢失函数的打包位置。 For example for the min function: 例如对于min函数:

octave:22> which min

min is a function from the file C:\\Octave\\Octave3.6.2_gcc4.6.2\\lib\\octave\\3.6.2\\oct\\i686-pc-mingw32\\max.oct min是来自文件C:\\ Octave \\ Octave3.6.2_gcc4.6.2 \\ lib \\ octave \\ 3.6.2 \\ oct \\ i686-pc-mingw32 \\ max.oct的函数

Something I found when linking my custom m file into an Octave standalone: 将我的自定义m文件链接到Octave独立文件时我发现的东西:

  1. Needed #include <octave/toplev.h> 需要#include <octave/toplev.h>
  2. Replace return 0; 替换return 0; (as above) with clean_up_and_exit(0); (如上所述)with clean_up_and_exit(0);

Without these steps my program repeatedly crashed on exit. 没有这些步骤,我的程序在退出时反复崩溃。

Run mkoctfile --link-stand-alone embedded.cc -o embedded 运行mkoctfile --link-stand-alone embedded.cc -o embedded

from the octave solution and not from a batch file. 从八度解决方案而不是批处理文件。

Just saved you half day (-; 刚刚救了你半天( - ;

In the above solution in bullet 4 B: 在子弹4 B的上述解决方案中:

B You search for something obvious like "min", and get no results. B你搜索明显像“min”这样的东西,并没有得到任何结果。 This is because the Loadable Function "min" is in the .oct file "max.oct". 这是因为可装载功能“min”位于.oct文件“max.oct”中。 Make a copy of max.oct, and rename it to min.oct. 制作max.oct的副本,并将其重命名为min.oct。 It will work now. 它现在可以工作了。

This might not work if some function is being called from @folder function.m and also to avoid unnecessary duplicated files, just add the following code somewhere in your m file outside @folder 如果从@folder function.m调用某个函数并且还要避免不必要的重复文件,这可能不起作用,只需在@folder外的m文件中的某处添加以下代码

autoload ("min", "max.oct");

Likewise, it can be removed via 同样,它可以通过删除

autoload ("min", "max.oct", "remove");

Ensure that the path to max.oct is provided here. 确保在此处提供max.oct的路径。

The above understanding is based on a file PKG_ADD and PKG_DEL in the communications package located at \\Octave-4.0.1\\lib\\octave\\packages\\communications-1.2.1\\i686-w64-mingw32-api-v50+\\ 以上理解基于位于\\ Octave-4.0.1 \\ lib \\ octave \\ packages \\ communications-1.2.1 \\ i686-w64-mingw32-api-v50 + \\的通信包中的文件PKG_ADD和PKG_DEL。

Check out Stratego Octave Compiler . 查看Stratego Octave Compiler

(I've not tested it yet, but plan to do so in the next few days.) (我还没有测试过,但计划在接下来的几天内进行测试。)

I had that very same requirement (one-click, brain-dead-simple), so I made a setup that contained only curl.exe, the batch file below, an exe which was a .bat in disguise (simply calling the batch file below) and the .vbs script below (not writen by me). 我有同样的要求(一键,脑死亡简单),所以我做了一个只包含curl.exe的设置,下面的批处理文件,一个伪装成.bat的exe(只需调用批处理文件)下面的.vbs脚本)(不是由我写的)。 And of course my m-file. 当然还有我的m文件。

This will download Octave 4.2.1 as a portable program (32 bit, otherwise we'dd have to download again if the system turns out to be 32 bit), unpack using the vbs script, move the contents to the same folder as the batch file and run it in GUI mode. 这将下载Octave 4.2.1作为可移植程序(32位,否则我们必须再次下载,如果系统原来是32位),使用vbs脚本解压缩,将内容移动到与批处理相同的文件夹文件并以GUI模式运行。 Every next time the same script is called, it will only check if octave.bat is still there. 每次下次调用相同的脚本时,它只会检查octave.bat是否仍然存在。

Of course this results in a huge waste of disk space, downloading the 280MB zip, which unpacks to over 1GB (which I make even worse by not deleting the zip afterwards), and you're stuck with a cmd window that is not easy to hide. 当然这会造成巨大的磁盘空间浪费,下载280MB的zip,打开包装超过1GB(后来由于没有删除拉链,我的情况更糟),你被困在一个不容易的cmd窗口隐藏。

But it does offer the simplest solution I could find. 但它确实提供了我能找到的最简单的解决方案。 It is also less likely to break in the future (either with an update of your own, or an update from Octave). 它也不太可能在未来中断(无论是你自己的更新,还是来自Octave的更新)。 Some glorious day, mkoktfile will actually be easy to use and will solve dependencies on its own, but until that day this remains the least headache-inducing solution I could find. 有些辉煌的一天,mkoktfile实际上很容易使用并且会自己解决依赖关系,但直到那一天,这仍然是我能找到的最不吸引人的解决方案。 And aspirins are more expensive than someone else's disk space. 阿司匹林比其他人的磁盘空间更贵。

::this file will test if the octave portable is downloaded and unpacked
@ECHO OFF

SET my_m_file=your_mfile.m
SET name_of_this_script=run_me.bat

::if the file exists, skip to the actual running.
IF EXIST "octave.bat" goto OctaveIsExtracted
IF EXIST "octave-4.2.1-w32.zip" goto OctaveIsDownloaded
ECHO The runtime (Octave portable 4.2.1) will now be downloaded.
ECHO This may take a long time, as it is about 280MB.
ECHO .
ECHO If this download restarts multiple times, you can manually download the octave-4.2.1-w32.zip from the GNU website. Make sure to unpack the contents.
::if this errors, you can uncomment the line with archive.org (which doesn't report total size during download)
curl http://ftp.gnu.org/gnu/octave/windows/octave-4.2.1-w32.zip > octave-4.2.1-w32.zip
::curl http://web.archive.org/web/20170827205614/https://ftp.gnu.org/gnu/octave/windows/octave-4.2.1-w32.zip > octave-4.2.1-w32.zip
:OctaveIsDownloaded
::check to see if the file size is the correct size to assume a successful download
::if the file size is incorrect, delete the file, restart this script to attempt a new download
::file size should be 293570269 bytes
call :filesize octave-4.2.1-w32.zip
IF /I "%size%" GEQ "293560000" goto OctaveIsDownloadedSuccessfully
del octave-4.2.1-w32.zip
::start new instance and exit and release this one
start %name_of_this_script%
exit
:OctaveIsDownloadedSuccessfully
IF EXIST "octave.bat" goto OctaveIsExtracted
::unzip and move those contents to the current folder
ECHO Unzipping octave portable, this may take a moment.
cscript //B j_unzip.vbs octave-4.2.1-w32.zip
SET src_folder=octave-4.2.1
SET tar_folder=%cd%
for /f %%a IN ('dir "%src_folder%" /b') do move %src_folder%\%%a %tar_folder%
pause
:OctaveIsExtracted
octave.bat %my_m_file%
goto :eof

:filesize
  set size=%~z1
  exit /b 0

And j_unzip.vbs 和j_unzip.vbs

' j_unzip.vbs
'
' UnZip a file script
'
' By Justin Godden 2010
'
' It's a mess, I know!!!
'

' Dim ArgObj, var1, var2
Set ArgObj = WScript.Arguments

If (Wscript.Arguments.Count > 0) Then
 var1 = ArgObj(0)
Else
 var1 = ""
End if

If var1 = "" then
 strFileZIP = "example.zip"
Else
 strFileZIP = var1
End if

'The location of the zip file.
REM Set WshShell = CreateObject("Wscript.Shell")
REM CurDir = WshShell.ExpandEnvironmentStrings("%%cd%%")
Dim sCurPath
sCurPath = CreateObject("Scripting.FileSystemObject").GetAbsolutePathName(".")
strZipFile = sCurPath & "\" & strFileZIP
'The folder the contents should be extracted to.
outFolder = sCurPath
'original line: outFolder = sCurPath & "\"

 WScript.Echo ( "Extracting file " & strFileZIP)

Set objShell = CreateObject( "Shell.Application" )
Set objSource = objShell.NameSpace(strZipFile).Items()
Set objTarget = objShell.NameSpace(outFolder)
intOptions = 256
objTarget.CopyHere objSource, intOptions

 WScript.Echo ( "Extracted." )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM