如何创建一个不需要安装Octave的简单Octave分发包

21

Octave的文档在这方面既令人畏惧又稀少。

我不知道该在哪里记录我找到的解决方案,所以我在这里发布。如果这是不合适的,我深表歉意,但我想帮助下一个遇到同样问题的人。

以下解决方案适用于简单的Windows可分发程序。

应用场景:
使用Octave 3.2.4开发了一个解决方案,并需要将其分发给具有少量计算机技能的最终用户。安装和解释Octave是不可能的,解决方案必须是“一键式”或“极度简单的”。

已知问题:
由于file_in_path.m文件错误,imread在3.2.4中失败。您需要将文件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=[]; 

8
回答自己的问题是可以的,但最好编辑您的问题,删除“解决方案”部分,并将其作为单独的答案在下面发布。这样,如果其他人提供了他们自己的答案,他们可以在更公平的基础上竞争,最佳答案会浮现到排序顶部。 - Jim Lewis
现在这样做可以吗?我不知道这里的礼仪 - 我总是觉得这个网站非常有用...我想帮助下一个人。 - Noah
是的,你应该这样做。 - Radu
2
由于这个问题已经快两年了,而且还没有得到答案,我将它移动到社区维基答案中,以便它不再出现在未回答的部分。 - ronalchn
1
https://saturnapi.com 允许您与他人共享和运行代码。可能适合您的需求。 - FullStack
7个回答

11
解决方案:使用mkoctfile创建可分发的exe文件,并将此exe与核心Octave文件以及其他必要的.oct和.m文件一起打包。
步骤1:创建一个独立的可执行文件。
您可以在这里查看可行的代码: http://www.gnu.org/software/octave/doc/interpreter/Standalone-Programs.html 特别是文件“embedded.cc”。
我已经简化了该文件如下:
#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;
}

使用以下命令构建此文件

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

虽然可能会出现警告,但只要没有错误,你就应该没问题。嵌入式文件embedded.exe将被构建,并可运行。唯一的问题是它将缺少所有使Octave变得很棒的好东西。你需要提供这些。

步骤2:创建分发文件夹

您需要创建许多Octave文件的副本。我建议为此专门使用一个目录。至少,您需要在\bin中复制所有或大部分DLL。此外,将可分发的可执行文件放置在此目录中。

步骤3:其他文件的捉迷藏

现在,您需要找出运行.m脚本所需的其他文件。您可以通过将\oct\i686-pc-mingw32*.oct和\share\octave\3.2.4\m\*\*.m复制到分发目录中来简化此步骤,尽管这可能过度,并且实际上并不能防止捉迷藏步骤。

现在,您必须进行捉迷藏或传统的“我的包含在哪里?”游戏。

  1. 打开命令提示符并导航到您的分发文件夹。
  2. 删除任何有用的PATH字符串。 您的客户不会有它们。
  3. 尝试运行程序embedded.exe。 您将收到以下类似的错误:

    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

  4. A在Octave安装中搜索“max”。 它将是一个.oct或.m文件。 在这种情况下,它是一个.oct文件,max.oct。 将其复制到您的分发目录中。

    B您搜索一些明显的东西,比如“min”,但没有结果。 这是因为可加载函数“min”位于.oct文件“max.oct”中。 复制max.oct,并将其重命名为min.oct。 现在它会工作了。 您如何知道函数在哪里? 我不确定。 大多数函数都在明显的位置,例如min的“max.oct”,以及ifft2.oct的“fft2.oct”。 祝你好运。

  5. 重复此过程,直到您的可执行文件运行为止。


4
请注意,如果您这样做,因为Octave本身是GPLv3+,而您正在将代码与它链接起来,所以您的代码需要使用GPL兼容许可证进行发布。根据Octave FAQ (http://wiki.octave.org/FAQ#If_I_write_code_using_Octave_do_I_have_to_release_it_under_the_GPL.3F)的说明,“使用Octave的本地插件接口(也称为.oct文件)编写的代码必然会链接到Octave内部,并被视为Octave的派生作品,因此必须按照与GPL兼容的条款发布。” - carandraug

5
只是要补充一点,如果您想运行一个脚本而不是一个 m 函数,则需要修改 embedded.cc 文件中的这一行:
octave_value_list out = feval ("your_custom_m_file", in);

should be:

octave_value_list out = feval ("your_custom_m_script");

同样,使用“which”命令查找缺失函数所在的位置。例如查找min函数:
octave:22> which min

min是从文件C:\Octave\Octave3.6.2_gcc4.6.2\lib\octave\3.6.2\oct\i686-pc-mingw32\max.oct中的一个函数。


2

当我将自定义的m文件链接到Octave独立程序时,发现以下问题:

  1. 需要添加#include <octave/toplev.h>
  2. return 0;(如上所述)替换为clean_up_and_exit(0);

如果不执行这些步骤,我的程序会在退出时反复崩溃。


1
运行mkoctfile --link-stand-alone embedded.cc -o embedded命令,而不是从批处理文件中运行。 从Octave解决方案中保存,而不是从批处理文件中保存。刚刚为您节省了半天时间(-;)。

1
在步骤4B的解决方案中: 您需要搜索一些明显的内容,例如“min”,但是没有结果。这是因为可加载函数“min”位于.oct文件“max.oct”中。请复制max.oct并将其重命名为min.oct,然后它就可以使用了。 如果从@folder function.m调用某些函数,则此方法可能无效,同时避免不必要的重复文件,请在m文件外部添加以下代码。
autoload ("min", "max.oct");

同样,它可以通过以下方式移除:
autoload ("min", "max.oct", "remove");

请确保此处提供了 max.oct 的路径。

上述理解基于通信包中的文件 PKG_ADD 和 PKG_DEL,该包位于 \Octave-4.0.1\lib\octave\packages\communications-1.2.1\i686-w64-mingw32-api-v50+\


0

我有同样的需求(一键式,非常简单),所以我制作了一个安装程序,其中只包含curl.exe、下面的批处理文件、一个伪装成.bat的exe文件(仅调用下面的批处理文件)和下面的.vbs脚本(不是我编写的)。当然还有我的m文件。

这将下载Octave 4.2.1作为便携式程序(32位,否则如果系统是32位,我们将不得不再次下载),使用vbs脚本解压缩,将内容移动到与批处理文件相同的文件夹中,并以GUI模式运行它。每次调用相同的脚本时,它只会检查octave.bat是否仍然存在。

当然,这会导致巨大的磁盘空间浪费,下载280MB的zip文件,解压后超过1GB(我更糟糕的是不删除zip文件),而且你会卡在一个不容易隐藏的cmd窗口中。

但是这确实提供了我能找到的最简单的解决方案。它也不太可能在未来(无论是您自己的更新还是Octave的更新)中出现问题。有一天,mkoktfile实际上将变得易于使用并且将自行解决依赖关系,但在那一天之前,这仍然是我能找到的最少头痛的解决方案。阿司匹林比别人的磁盘空间更贵。

::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

还有 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." )

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接