内容

名称

perlos2 - OS/2、DOS、Win0.3*、Win0.95 和 WinNT 下的 Perl。

概要

可以以下格式阅读本文档

man perlos2
view perl perlos2
explorer perlos2.html
info perlos2

列出一些(并非所有格式都同时可用),或按“原样”阅读:作为 README.os2pod/perlos2.pod

要在 OS/2 外部阅读文档的 .INF 版本(非常推荐),需要 IBM 的阅读器(可能在 IBM ftp 站点提供 (?)(有 URL 吗?))或与 PC DOS 7.0 和 IBM 的 Visual Age C++ 3.5 一起提供。

“Just add OS/2 Warp”软件包中包含 Win* 查看器的副本

ftp://ftp.software.ibm.com/ps/products/os2/tools/jaow/jaow.zip

?:\JUST_ADD\view.exe 中。这也使你可以访问 EMX 的 .INF 文档(文本格式在 EMX 发行版的 /emx/doc 中提供)。还有一个名为 xview 的不同查看器。

请注意,如果你安装了 lynx.exenetscape.exe,则可以按照 .INF 格式的本文档中的 WWW 链接。如果你正确安装了 EMX 文档,则可以按照库链接(你需要通过设置 EMXBOOK 环境变量使 view emxbook 正常工作,如 EMX 文档中所述)。

说明

目标

目标是使 OS/2 成为使用/构建/开发 Perl 和 Perl 应用程序 的最佳受支持平台之一,以及使 Perl 成为在 OS/2 下使用的最佳语言。次要目标是尝试在 DOS 和 Win* 下也实现此目标(但不要难)。

当前状态非常接近此目标。已知限制

请通过告知我其他项目来保持此列表的最新状态。

其他操作系统

由于 perl 的 OS/2 端口使用了非凡的 EMX 环境,因此它可以在任何可以运行 EMX 的环境中运行(并构建扩展,并且 - 可能 - 自行构建)。当前列表为 DOS、DOS-inside-OS/2、Win0.3*、Win0.95 和 WinNT。在众多 perl 版本中,只有一个版本有效,请参阅 "perl_.exe"

请注意,并非所有 Perl 功能都可以在这些环境中使用。这取决于扩展器(很可能是 RSX)决定实现的功能。

请参阅 "先决条件"

先决条件

EMX

需要 EMX 运行时(可以用 RSX 代替)。请注意,可以通过将emx.exe/rsx.exe绑定到它来使perl_.exe在没有任何外部支持的情况下在 DOS 下运行,请参阅 emxbind(1)。请注意,在 DOS 下,为了获得最佳效果,应该使用 RSX 运行时,它有更多可用的功能(如forkpopen等)。事实上,如果没有 VCPI,则需要 RSX。请注意,RSX 需要 DPMI。已知许多 DPMI 实现非常容易出错,请小心!

仅支持最新的运行时,目前为0.9d fix 03。Perl 可以在 EMX 的早期版本下运行,但未经测试。

可以从以下位置获取 EMX 的不同部分

ftp://crydee.sai.msu.ru/pub/comp/os/os2/leo/gnu/emx+gcc/
http://hobbes.nmsu.edu/h-browse.php?dir=/pub/os2/dev/emx/v0.9d/

运行时组件应具有名称emxrt.zip

注意。使用emx.exe/rsx.exe时,只需将它们放在路径中即可。无需明确指定它们(尽管这

emx perl_.exe -de 0

也可以正常工作)。

RSX

要在 DPMI 平台上运行 Perl,需要 RSX 运行时。在 DOS-inside-OS/2、Win0.3*、Win0.95 和 WinNT 下需要此项(请参阅"其他操作系统")。RSX 无法仅与 VCPI 一起使用,而 EMX 可以,它需要 DMPI。

拥有 RSX 和最新的sh.exe,可以在 DOS 下获得一个功能齐全的类似*nix的环境,例如,fork``和管道open可以正常工作。事实上,MakeMaker 可以正常工作(用于静态构建),因此可以在 DOS 下拥有 Perl 开发环境。

可以从以下位置获取 RSX

http://cd.textfiles.com/hobbesos29804/disk1/EMX09C/
ftp://crydee.sai.msu.ru/pub/comp/os/os2/leo/gnu/emx+gcc/contrib/

通过电子邮件[email protected]联系作者。

带有 DOS 挂钩的最新sh.exe可在以下位置获得

http://www.ilyaz.org/software/os2/

作为sh_dos.zip或以shpdksh等开头的类似名称。

HPFS

Perl 不关心文件系统,但 perl 库包含许多具有长名称的文件,因此要完整安装它,需要支持长文件名的文件系统。

请注意,如果您不打算构建 perl 本身,则有可能欺骗 EMX 截断文件名。不支持此操作,请阅读 EMX 文档以了解如何执行此操作。

pdksh

要使用复杂的命令行(例如,管道和/或参数引用)启动外部程序,Perl 使用外部 shell。对于 EMX 端口,此类 shell 应命名为sh.exe,并位于编译期间固定的位置(通常为F:/bin)或可配置的位置(请参阅"PERL_SH_DIR")。

为了获得最佳结果,请使用 EMX pdksh。标准二进制文件(5.2.14 或更高版本)也可以在 DOS(使用"RSX")下运行,请参阅

http://www.ilyaz.org/software/os2/

在 OS/2(以及 DOS 和...)下启动 Perl 程序

通过以下方式使用参数 arg1 arg2 arg3 启动 Perl 程序 foo.pl,与在任何其他平台上相同:

perl foo.pl arg1 arg2 arg3

如果您想为 perl 本身(而不是程序)指定 perl 选项 -my_opts,请使用

perl -my_opts foo.pl arg1 arg2 arg3

或者,如果您使用类似 CMD 或 4os2 的 OS/2 样式 shell,请将以下内容放在 perl 脚本的开头

extproc perl -S -my_opts

将程序重命名为 foo.cmd,并通过键入以下内容启动它

foo arg1 arg2 arg3

请注意,由于 OS/2 的愚蠢限制,在使用 extproc 时 perl 脚本的完整路径不可用,因此您被迫使用 -S perl 开关,并且您的脚本应位于 PATH 中。作为积极的一面,如果您知道脚本的完整路径,您仍然可以使用以下内容启动它

perl ../../blah/foo.cmd arg1 arg2 arg3

(请注意,参数 -my_opts 由脚本中的 extproc 行处理,请参见第一行的 "extproc")。

要了解上述魔术的作用,请阅读有关 -S 开关的 perl 文档 - 请参阅 perlrun,以及有关 extproc 的 cmdref

view perl perlrun
man perlrun
view cmdref extproc
help extproc

或您喜欢的任何方法。

还有无穷无尽的可能性来使用 4os2 的可执行扩展、WPS 的关联等等... 但是,如果您使用 *nixish shell(例如二进制发行版中提供的sh.exe),则需要遵循 "perlrun 中的命令开关" 中指定的语法。

请注意,-S 开关还支持具有附加扩展名 .cmd.btm.bat.pl 的脚本。

在 Perl 下启动 OS/2(和 DOS)程序

这是 system()(请参阅 "perlfunc 中的 system")、``(请参阅 "perlop 中的 I/O 运算符")和open pipe(请参阅 "perlfunc 中的 open")的用途。(除非您知道自己在做什么,否则请避免使用 exec()(请参阅 "perlfunc 中的 exec")。

但是请注意,要使用其中一些运算符,您需要安装一个 sh 语法 shell(请参阅 "Pdksh""常见问题"),并且 perl 应该能够找到它(请参阅 "PERL_SH_DIR")。

使用 shell 的情况是

  1. 带有一个参数的 system()(请参阅 "perlfunc 中的 system"),带有重定向或 shell 元字符的 exec()(请参阅 "perlfunc 中的 exec");

  2. 带有包含重定向或 shell 元字符的命令的管道打开(请参阅 "perlfunc 中的 open");

  3. 带有包含重定向或 shell 元字符的命令的反引号 ``(请参阅 "perlop 中的 I/O 运算符");

  4. 如果由 system()/exec()/pipe-open()/`` 调用的可执行文件是一个带有指定 shell 的“魔术”#! 行或 extproc 行的脚本;

  5. 如果 system()/exec()/pipe-open()/`` 调用的可执行文件是无“魔术”行的脚本,且 $ENV{EXECSHELL} 设置为 shell;

  6. 如果 system()/exec()/pipe-open()/`` 调用的可执行文件未找到(此备注是否已过时?);

  7. 对于 glob(见 perlfunc 中的“glob”perlop 中的“I/O 运算符”)(已过时?Perl 现今使用内置 glob)。

为了加快常见情况的速度,在上述算法中,命令名称中的反斜杠不被视为 shell 元字符。

Perl 直接启动以 cookie extproc#! 开头的脚本,无需 shell 干预。Perl 使用与 pdksh 相同的算法查找可执行文件:如果 #! 行上的路径不起作用且包含 /,则可执行文件的目录部分将被忽略,并在 .PATH 中搜索可执行文件。为了查找这些脚本的参数,Perl 使用与 pdksh 不同的算法:最多识别 3 个参数,并去除尾部空白。

如果脚本不包含此类 cookie,则为避免调用 sh.exe,Perl 使用与 pdksh 相同的算法:如果设置了 $ENV{EXECSHELL},则将脚本作为此命令的第一个参数提供,如果没有设置,则使用 $ENV{COMSPEC} /c(或如果未设置 $ENV{COMSPEC},则使用硬编码猜测)。

在直接启动脚本时,Perl 使用与通过 -S 命令行选项给出的脚本搜索完全相同的算法:它将在当前目录中查找,然后使用以下附加扩展名顺序在 $ENV{PATH} 的组件上查找:无扩展名、.cmd.btm.bat.pl

请注意,只有当 OS/2 无法启动指定应用程序时,Perl 才会开始查找脚本,因此如果 PATH 中的 任何位置 都存在可执行文件 blah.exe,则 system 'blah' 不会查找脚本。换句话说,PATH 本质上被搜索了两次:一次由操作系统搜索可执行文件,然后由 Perl 搜索脚本。

还要注意,OS/2 上的可执行文件可以具有任意扩展名,但如果名称中没有句点,则会自动附加 .exe。解决方法很简单:由于 blah.blah 表示同一文件(至少在 FAT 和 HPFS 文件系统上),因此要启动驻留在文件 n:/bin/blah(无扩展名)中的可执行文件,请向 system() 提供参数 n:/bin/blah.(附加句点)。

Perl 会从 VIO(= 文本模式)Perl 进程中启动 PM 程序,在单独的 PM 会话中;反之则不然:当您从 PM Perl 进程启动非 PM 程序时,Perl 不会在单独的会话中运行它。如果需要单独的会话,请确保使用 shell,如 system 'cmd /c myprog',或使用 OS2::Process 模块中记录的 system() 的可选参数启动它。这被认为是一个特性。

常见问题

"它不起作用"

Perl 二进制发行版附带一个 testperl.cmd 脚本,它尝试检测配置错误的安装的常见问题。它很有可能发现您设法搞砸的安装步骤。;-)

我无法运行外部程序

我无法将 perl 嵌入到我的程序中,或无法从我的程序中使用 perl.dll

您的程序是否使用 -Zmt -Zcrtdll 编译的 EMX?

好吧,现在 Perl DLL 也应该可以从不同编译的程序中使用了... 如果您可以从 REXX 脚本运行 Perl 代码(请参阅 OS2::REXX),那么当前支持不同编译的主程序的黑客代码忽略了交互的其他方面。

如果其他方法都失败了,您需要为 perl 构建一个独立的 DLL。联系我,我曾经做过。套接字将不起作用,还有很多其他东西。

您是否使用了 ExtUtils::Embed

前段时间我收到报告说它不起作用。现在它在 Perl 测试套件中得到了检查,所以 grep 构建树的 ./t 子目录(以及 ./lib 子目录中的 *.t 文件)以找到如何“正确”地完成它。

`` 和 pipe-open 在 DOS 下不起作用。

这可能只是 "我无法运行外部程序" 的一个变体,或者是一个更深层次的问题。基本上:您需要 RSX(请参阅 "先决条件")才能使这些命令工作,您可能需要一个理解命令参数的 sh.exe 端口。其中一个端口在 "先决条件" 中的 RSX 下列出。不要忘记设置变量 "PERL_SH_DIR"

DPMI 是 RSX 所必需的。

无法启动 find.exe "pattern" file

“标准 C API 以启动应用程序”的整个理念是程序参数的 foo"foo" 形式完全可以互换。find 打破了这一范例;

find "pattern" file
find pattern file

不相等;find 无法使用上述 API 直接启动。需要一种方法来用其他引用结构包围双引号,必然需要一个额外的非 Unix 外壳。

使用以下方法之一

system 'cmd', '/c', 'find "pattern" file';
`cmd /c 'find "pattern" file'`

这将通过 sh.exe 通过 perl.exe 通过 cmd.exe 启动 find.exe,但如果您想使用不符合规范的程序,这是必须付出的代价。

安装

自动二进制安装

安装 perl 二进制分发版的最便捷方式是通过 perl 安装程序 install.exe。只需按照说明进行操作,99% 的安装问题就会消失。

但是,请注意,您需要在路径中安装 unzip.exe,并运行 EMX 环境。后者意味着如果您刚刚安装了 EMX,并对 Config.sys 进行了所有必要的更改,则可能需要重新启动。通过运行检查 EMX 运行时

emxrev

二进制安装程序还会在您的桌面上创建一个文件夹,其中包含一些有用的对象。如果您需要更改二进制安装程序工作的一些方面,请随时编辑文件 Perl.pkg。例如,如果您需要多次运行安装程序并且不想在 GUI 中进行许多交互式更改,这可能很有用。

自动二进制安装未解决的问题

PERL_BADLANG

如果您在 perl 安装之后更改了代码页,并且 EMX 不支持新值,则可能需要。请参阅 "PERL_BADLANG"

PERL_BADFREE

请参阅 "PERL_BADFREE"

Config.pm

此文件位于您安装 perl 库位置的某个深层位置,通过以下方式找到它

perl -MConfig -le "print $INC{'Config.pm'}"

虽然此文件中的大多数重要值都会由二进制安装程序更新,但其中一些值可能需要手动编辑。我不知道此类数据,如果您找到此类数据,请随时通知我。此外,对已安装版本的更改可能需要编辑此文件。

注意。由于拼写错误,5.00305 的二进制安装程序会在 Config.sys 中安装变量 PERL_SHPATH。请删除此变量,并改为添加 "PERL_SH_DIR"

手动二进制安装

从版本 5.00305 开始,OS/2 perl 二进制发行版被拆分为 11 个组件。不幸的是,为了启用可配置的二进制安装,zip 文件中的文件路径不是绝对路径,而是相对于某个目录的相对路径。

请注意,仍然需要使用已存储的路径进行提取(unzip 的默认设置,为 pkunzip 指定 -d)。但是,您需要知道将文件提取到哪里。您还需要手动更改 Config.sys 中的条目,以反映您放置文件的位置。请注意,如果您有一些原始的解压缩程序(如 pkunzip),您可能会在解压缩过程中收到大量警告/错误。升级到 (w)unzip

以下是复制我机器上配置的示例。现在,您可以在 VIEW.EXE 中按 Ctrl-Insert,然后从生成的(在您启动 VIEW.EXE 的目录中创建的)文件中剪切并粘贴。

对于每个组件,我们都会提及与每个安装目录相关的环境变量。要么选择与变量值匹配的目录,要么创建/追加变量以考虑目录。

Perl VIO 和 PM 可执行文件(动态链接)
unzip perl_exc.zip *.exe *.ico -d f:/emx.add/bin
unzip perl_exc.zip *.dll -d f:/emx.add/dll

(在 PATH 上具有包含 *.exe 的目录,在 LIBPATH 上具有 *.dll);

Perl_ VIO 可执行文件(静态链接)
unzip perl_aou.zip -d f:/emx.add/bin

(在 PATH 上具有目录);

Perl 实用程序的可执行文件
unzip perl_utl.zip -d f:/emx.add/bin

(在 PATH 上具有目录);

主 Perl 库
unzip perl_mlb.zip -d f:/perllib/lib

如果此目录与编译到 perl.exe 中的前缀完全相同,则无需更改任何内容。但是,如果您使用不同的路径,则 perl 才能找到库,您需要在 Config.sysset PERLLIB_PREFIX,请参见 "PERLLIB_PREFIX"

其他 Perl 模块
unzip perl_ste.zip -d f:/perllib/lib/site_perl/5.38.2/

同样适用于上述说明。此外,如果此目录不是 @INC 中的目录之一(且 @INC 受 PERLLIB_PREFIX 影响),您需要将此目录和子目录 ./os2 放入 PERLLIBPERL5LIB 变量中。除非您已设置 PERL5LIB,否则不要使用它。请参阅 perl 中的“ENVIRONMENT”

[检查此提取目录是否仍适用于新的目录结构布局!]

编译 Perl 模块的工具
unzip perl_blb.zip -d f:/perllib/lib

perl_ste.zip 相同的说明。

Perl 和实用程序的手册页
unzip perl_man.zip -d f:/perllib/man

此目录最好放在 MANPATH 中。您需要有一个可用的 man 才能访问这些文件。

Perl 模块的手册页
unzip perl_mam.zip -d f:/perllib/man

此目录最好放在 MANPATH 中。您需要有一个可用的 man 才能访问这些文件。

Perl 文档的源代码
unzip perl_pod.zip -d f:/perllib/lib

这由 perldoc 程序使用(请参阅 perldoc),并且可用于生成可供 WWW 浏览器使用的 HTML 文档,以及大量其他格式的文档:infoLaTeXAcrobatFrameMaker 等。[使用 pod2latex 等程序]

.INF 格式的 Perl 手册
unzip perl_inf.zip -d d:/os2/book

此目录最好放在 BOOKSHELF 中。

Pdksh
unzip perl_sh.zip -d f:/bin

perl 使用此项来运行明确需要 shell 的外部命令,例如使用 重定向shell 元字符 的命令。它还用于代替显式的 /bin/sh

如果您将 sh.exe 从上述位置移动,请设置 PERL_SH_DIR(请参阅 "PERL_SH_DIR")。

注意。可能可以使用其他一些兼容 sh 的 shell(未经测试)。

在您安装所需的组件并相应地更新 Config.sys 之后,您需要手动编辑 Config.pm。此文件位于您安装 perl 库的位置的某个深层目录中,可以通过以下方式找到它

perl -MConfig -le "print $INC{'Config.pm'}"

您需要更正所有看起来像文件路径的条目(它们当前以 f:/ 开头)。

警告

自动和手动 perl 安装会在 perl 可执行文件中留下预编译的路径。虽然这些路径可覆盖(请参阅 "PERLLIB_PREFIX""PERL_SH_DIR"),但有些人可能更喜欢对可执行文件/DLL 中的路径进行二进制编辑。

访问文档

根据您构建/安装 Perl 的方式,您可能拥有以下格式的(否则相同)Perl 文档

OS/2 .INF 文件

很可能是最方便的形式。在 OS/2 下将其视为

view perl
view perl perlfunc
view perl less
view perl ExtUtils::MakeMaker

(目前最后两个可能会命中错误位置,但很快可能会得到改善)。在 Win* 下,请参阅 "SYNOPSIS"

如果您想自己构建文档,并且拥有 OS/2 工具包,请运行

pod2ipf > perl.ipf

/perllib/lib/pod 目录中,然后

ipfc /inf perl.ipf

(在两个步骤中都会遇到很多错误。)现在将其移到您的 BOOKSHELF 路径上。

纯文本

如果您有源代码形式的 Perl 文档、已安装的 Perl 实用程序和已安装的 GNU groff,则可以使用

perldoc perlfunc
perldoc less
perldoc ExtUtils::MakeMaker

以文本形式访问 Perl 文档(请注意,使用 Perl 手册页可能会获得更好的结果)。

或者,尝试在 .pod 文件上运行 pod2text。

手册页

如果您在系统上安装了 man,并且安装了 Perl 手册页,请使用类似以下内容

man perlfunc
man 3 less
man ExtUtils.MakeMaker

以访问 Perl 不同组件的文档。从

man perl

请注意,点 (.) 用作文档包的包分隔符,并且像往常一样,有时您需要提供部分 - 上面的 3 - 以避免被 less(1) 手册页 隐藏。

确保手册页目录上方的目录位于我们的 MANPATH 中,如下所示

set MANPATH=c:/man;f:/perllib/man

对于 f:/perllib/man/man1/ 等中的 Perl 手册页。

HTML

如果您有一些可用的 WWW 浏览器、以源代码形式安装了 Perl 文档和 Perl 实用程序,则可以构建 HTML 文档。切换到包含 .pod 文件的目录,然后执行以下操作

cd f:/perllib/lib/pod
pod2html

在此之后,您可以将浏览器定向到此目录中的 perl.html 文件,然后继续阅读文档,如下所示

explore file:///f:/perllib/lib/pod/perl.html

或者,您可能能够从 CPAN 预构建这些文档。

GNU info 文件

Emacs 用户会非常喜欢它,尤其是加载了 CPerl 模式时。您需要从 CPAN 获取最新的 pod2texi,或者,也可以获取预构建的信息页面。

PDF 文件

用于 Acrobat 可在 CPAN 上获得(可能是针对稍旧版本的 Perl)。

LaTeX 文档

可以使用 pod2latex 构建。

构建

我们在此讨论如何在 OS/2 下构建 Perl。

简短说明

假设您是一位经验丰富的搬运工,因此确信系统中已存在所有必要的工具,并且您知道如何获取 Perl 源代码发行版。将其解包,切换到提取目录,然后

gnupatch -p0 < os2\diff.configure
sh Configure -des -D prefix=f:/perllib
make
make test
make install
make aout_test
make aout_install

这会将可执行文件放入 f:/perllib/bin。手动将它们移动到 PATH,手动将构建的 perl*.dll 移动到 LIBPATH(此处对于 Perl DLL * 是一个不太有意义的十六进制校验和),然后运行

make installcmd INSTALLCMDDIR=d:/ir/on/path

假设 man 文件已放置在适当的位置,这将完成最小 Perl 系统的安装。(二进制发行版还包含许多附加模块和 INF 格式的文档。)

以下是这些步骤的详细指南。

先决条件

您需要拥有最新的 EMX 开发环境、完整的 GNU 工具套件(gawk 重命名为 awk,并且 GNU find.exe 早于路径中的 OS/2 find.exesort.exe 也一样,要检查使用

find --version
sort --version

)。您需要将最新版本的 pdksh 安装为 sh.exe

检查您是否已安装 BSD 库和头文件,以及(可选)Berkeley DB 头文件和库以及 crypt。

获取文件可能的路径

ftp://ftp.uni-heidelberg.de/pub/os2/unix/
http://hobbes.nmsu.edu/h-browse.php?dir=/pub/os2
http://cd.textfiles.com/hobbesos29804/disk1/DEV32/
http://cd.textfiles.com/hobbesos29804/disk1/EMX09C/

据报道,以下存档包含足够用于构建 perl 的实用程序:gnufutil.zipgnusutil.zipgnututil.zipgnused.zipgnupatch.zipgnuawk.zipgnumake.zipgnugrep.zipbsddev.zipksh527rt.zip(或更高版本)。请注意,所有这些实用程序都可从 LEO 获得

ftp://crydee.sai.msu.ru/pub/comp/os/os2/leo/gnu/

还要注意,EMX 发行版中的 db.libdb.a 不适用于多线程编译(即使是单线程版本的 Perl 也使用多线程 C RTL,以兼容 XFree86-OS/2)。从以下位置获取更正版本

http://www.ilyaz.org/software/os2/db_mt.zip

如果您已经安装了完全相同的 Perl 版本,请确保没有 perl 副本或 perl 正在运行。构建的后续步骤可能会失败,因为可能会找到已加载到内存中的较旧版本的 perl.dll。运行 make test 将变得毫无意义,因为测试正在检查 perl 的先前构建(os2/os2_base.t 测试会检测并报告此情况)。不要忘记在环境中取消设置 PERL_EMXLOAD_SEC

还要确保当前驱动器上存在 /tmp 目录,并且 . 目录位于您的 LIBPATH 中。可以通过以下方法尝试纠正后一种情况

set BEGINLIBPATH .\.

如果您使用类似 CMD.EXE 或最新版本的 4os2.exe。(将 BEGINLIBPATH 设置为仅 . 会被 OS/2 内核忽略。)

确保您的 gcc 适用于 -Zomf 链接:在 /emx/lib 目录中运行 omflibs 脚本。

检查您是否已安装 link386。它随 OS/2 一起提供,但由于自定义可能未安装。如果键入

link386

显示您没有它,请执行选择性安装,然后在可选系统实用程序/更多中选择链接对象模块。如果您进入 link386 提示,请按 Ctrl-C 退出。

获取 perl 源代码

您需要获取最新的 perl 源代码(包括开发人员版本)。它有可能位于

http://www.cpan.org/src/
http://www.cpan.org/src/unsupported

如果没有,您可能需要在索引中查找它以在当前维护者的目录中找到它。

开发人员版本的快速循环可能会不时中断 OS/2 构建,查看

http://www.cpan.org/ports/os2/

可能会指示维护者公开发布的最新版本。请注意,该版本可能包括一些附加补丁,以应用于当前的 perl 源代码。

像这样提取它

tar vzxf perl5.00409.tar.gz

您可能会在提取配置时看到有关错误的消息。这是因为与同名文件配置存在冲突。

更改为提取目录。

应用补丁

您需要像这样应用./os2/diff.* 中的补丁

gnupatch -p0 < os2\diff.configure

您可能还需要应用 perl 二进制发行版中提供的补丁。查看 perl5-porters 邮件列表以获取最新的与 OS/2 相关的补丁也是有意义的(请参阅 http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/)。此类补丁通常包含字符串 /os2/patch,因此查找这些字符串是有意义的。

手动编辑

您可以查看文件 ./hints/os2.sh 并更正您在那里发现的任何错误。我不认为它在任何地方都是必需的。

制作

sh Configure -des -D prefix=f:/perllib

prefix 表示:安装生成的 perl 库的位置。提供正确的 prefix,您可能无需指定 PERLLIB_PREFIX,请参阅 "PERLLIB_PREFIX"

忽略有关缺少 ln 和有关 tr 的 -c 选项的消息。如果您看到它并且可以追溯到后者虚假警告的来源,后者很可能已经修复,请通知我。

现在

make

在某个时刻,构建可能会终止,报告版本不匹配无法运行perl。这意味着您的 LIBPATH 中没有 .,因此 perl.exe 无法找到所需的 perl67B2.dll(将这些十六进制数字视为行噪声)。修复此问题后,构建应顺利完成。

测试

现在运行

make test

所有测试都应成功(其中一些被跳过)。如果您安装了相同版本的 Perl,则至关重要的是在您的 LIBPATH(或 BEGINLIBPATH)中尽早使用 .,否则您的测试很可能会测试错误版本的 Perl。

一些测试可能会生成类似于

大量 bad free

与 Berkeley DB 相关的数据库测试中。这应该已经修复了。如果它仍然存在,您可以禁用此警告,请参阅 "PERL_BADFREE"

进程被 SIGTERM/SIGINT 终止

这是 OS/2 应用程序发出的标准消息。*nix 应用程序在静默中终止。它被认为是一个特性。可以通过适当的 sighandler 轻松禁用它。

然而,测试引擎在意外时刻将这些消息泄露到屏幕上。在测试期间应该出现两条此类消息。

要获得更精细的测试报告,请调用

perl t/harness

io/pipe.t 失败的报告可能如下所示

Failed Test  Status Wstat Total Fail  Failed  List of failed
------------------------------------------------------------
io/pipe.t                    12    1   8.33%  9
7 tests skipped, plus 56 subtests skipped.
Failed 1/195 test scripts, 99.49% okay. 1/6542 subtests failed,
   99.98% okay.

最重要的跳过测试的原因是

op/fs.t
18

检查 stat()atimemtime - 不幸的是,HPFS 仅提供 2 秒的时间粒度(为了与 FAT 兼容?)。

25

检查刚打开用于写入的文件句柄上的truncate() - 我不知道为什么应该或不应该工作。

op/stat.t

检查stat()。测试

4

检查 stat()atimemtime - 不幸的是,HPFS 仅提供 2 秒的时间粒度(为了与 FAT 兼容?)。

安装已构建的 perl

如果您尚未将perl*.dll移动到 LIBPATH,请立即执行此操作。

运行

make install

它会将生成的文件放入所需的位置。手动将perl.exeperl__.exeperl___.exe放入 PATH 上的位置,将perl.dll放入 LIBPATH 上的位置。

运行

make installcmd INSTALLCMDDIR=d:/ir/on/path

将 perl 实用程序转换为.cmd文件并将其放在 PATH 上。您需要手动将.EXE实用程序放在路径上。它们安装在$prefix/bin中,此处$prefix是您提供给Configure的内容,请参见"制作"

如果您使用man,请将已安装的*/man/目录移动到您的MANPATH,或修改MANPATH以匹配该位置。(可以通过向./Configure提供正确的manpath选项或在配置和制作步骤之间编辑./config.sh来避免这种情况。)

a.out风格的构建

按上述方法进行,但通过以下方式制作perl_.exe(请参见"perl_.exe"

make perl_

通过以下方式测试和安装

make aout_test
make aout_install

手动将perl_.exe放入 PATH 上的位置。

注意。perl_的构建过程不知道所有依赖项,因此您应确保所有内容都是最新的,例如,通过执行

make perl_dll

首先。

构建二进制分发包

[本节仅提供简要概述...]

构建过程应根据您安装的 perl 版本是已在系统上存在并使用,还是尚未使用的版本而有所不同。以下说明假定该版本是新的,因此安装其 DLL 和.pm文件不会破坏系统的操作,即使某些中间步骤尚未完全起作用也是如此。

其他情况需要稍微复杂一些的过程。以下我假设 Perl 的当前版本是5.8.2,因此可执行文件也相应地命名。

  1. 完全构建并测试 Perl 分发包。确保没有测试因testaout_test目标而失败;修复 Perl 和 Perl 测试套件通过这些测试检测到的错误。确保all_test make 目标尽可能干净地运行。检查os2/perlrexx.cmd是否正常运行。

  2. 完全安装 Perl,包括 installcmd 目标。将生成的 DLL 复制到 LIBPATH;将编号的 Perl 可执行文件(如 perl5.8.2.exe)复制到 PATH;将 perl_.exe 作为 perl_5.8.2.exe 复制到 PATH。考虑是否需要向后兼容的 DLL。在大多数情况下,您现在不需要安装它们;但有时这可能会简化以下步骤。

  3. 确保 CPAN.pm 可以从 CPAN 下载文件。如果没有,您可能需要手动安装 Net::FTP

  4. 安装包 Bundle::OS2_default

    perl5.8.2 -MCPAN -e "install Bundle::OS2_default" < nul |& tee 00cpan_i_1

    这可能在 1GHz 处理器上花费几个小时(首次运行时)。这应该不是一个顺利的过程。一些模块可能未指定所需的依赖项,因此可能需要重复此过程几次,直到结果稳定为止。

    perl5.8.2 -MCPAN -e "install Bundle::OS2_default" < nul |& tee 00cpan_i_2
    perl5.8.2 -MCPAN -e "install Bundle::OS2_default" < nul |& tee 00cpan_i_3

    即使它们稳定后,一些测试也可能失败。

    修复尽可能多的已发现的错误。记录所有未修复的错误以及所有原因不明的故障。检查生成的日志 00cpan_i_1 以查找可疑跳过的测试和其他可疑事件。

    请记住,某些模块的安装也可能失败:例如,要更新的 DLL 可能已由 CPAN.pm 加载。检查install 日志(在上面的示例中为 00cpan_i_1 等)以查找错误,并手动安装内容,如下所示

    cd $CPANHOME/.cpan/build/Digest-MD5-2.31
    make install

    某些发行版可能会导致一些测试失败,但您可能仍然希望安装它们(如上所述,或通过 CPAN.pm shell 模式的 force install 命令)。

    由于此过程可能需要很长时间才能完成,因此通过禁用 CPAN 索引本地副本的定期更新来“冻结”您的 CPAN 配置是有意义的:将 index_expire 设置为某个大值(我使用 365),然后保存设置

    CPAN> o conf index_expire 365
    CPAN> o conf commit

    完成后,重置回默认值 1

  5. 对结果满意后,重新运行 installcmd 目标。现在,您可以将 perl5.8.2.exe 复制到 perl.exe,并安装其他 OMF 构建的可执行文件:perl__.exe 等。它们已准备好使用。

  6. 更改到构建树的 ./pod 目录,下载 Perl 徽标 CamelGrayBig.BMP,并运行

    ( perl2ipf > perl.ipf ) |& tee 00ipf
    ipfc /INF perl.ipf |& tee 00inf

    这将生成 Perl 文档在线手册 perl.INF。将其安装在 BOOKSHELF 路径中。

  7. 现在是构建静态链接的可执行文件 perl_.exe 的时候了,其中包括通过 Bundle::OS2_default 新安装的模块。通过 CPAN.pm 进行测试将非常缓慢,因为它为每个 XS 扩展静态链接一个新可执行文件。

    这里有一个可能的解决方法:在 $CPANHOME/.cpan/build/ 中创建一个顶级 Makefile.PL,其内容如下(与 "使用静态加载扩展的自定义集合制作可执行文件" 进行比较)

    use ExtUtils::MakeMaker;
    WriteMakefile NAME => 'dummy';

    以这种方式执行

    perl_5.8.2.exe Makefile.PL <nul |& tee 00aout_c1
    make -k all test <nul |& 00aout_t1

    同样,此过程不应该绝对顺利。子目录中的某些 Makefile.PL 可能存在缺陷,并且无法作为“子”脚本运行。模块的相互依赖性可能会影响你;但是,由于非 XS 模块已经安装,因此大多数模块的先决条件很有可能存在。

    如果你发现一些小故障,请将有问题的模块目录移动到其他位置;如果这些模块是非 XS 模块,你可以忽略它们 - 它们已经安装;剩下的 XS 模块你需要手动逐个安装。

    每次进行此类删除后,你需要重新运行 Makefile.PL/make 进程;通常此过程很快就会收敛。(但请务必将所有必需的外部 C 库从 .lib 格式转换为 .a 格式:运行其中一个

    emxaout foo.lib
    emximp -o foo.a foo.lib

    哪个合适。)此外,请确保外部库的 DLL 可用于在没有 -Zmtd 选项的情况下编译的可执行文件。

    当你确信只有几个子目录会导致失败时,你可能希望向 make 添加 -j4 选项以加快跳过已完成构建的子目录的速度。

    当你对测试结果感到满意时,请安装扩展的构建 C 库

    make install |& tee 00aout_i

    现在,你可以将最后阶段生成的 ./perl.exe 文件重命名为 perl_5.8.2.exe;将其放在 PATH 中;如果某些 XS 模块之间存在相互依赖性,你可能需要使用此新可执行文件和一些排除的模块重复 test/install 循环 - 直到过程收敛。

    现在,你可以在 Perl 构建器可以找到的地方为这些 Perl 模块提供了所有必需的 .a 库。使用 Perl 构建器:更改为空目录,再次创建一个“虚拟”Makefile.PL,然后运行

    perl_5.8.2.exe Makefile.PL |& tee 00c
    make perl		     |& tee 00p

    这应该创建一个可执行文件 ./perl.exe,其中内置了所有静态加载的扩展。比较生成的 perlmain.c 文件以确保在迭代过程中加载的扩展数量只会增加。在 PATH 上将 ./perl.exe 重命名为 perl_5.8.2.exe

    当它收敛时,你得到了 perl_5.8.2.exe 的功能变体;将其复制到 perl_.exe。你已经完成了本地 Perl 安装的生成。

  8. 确保已安装的模块实际上已安装在新 Perl 的位置,并且没有从 Perl 旧版本继承的 @INC 条目中继承:将 PERLLIB_582_PREFIX 设置为将 Perl 的新版本重定向到新位置,并将已安装的文件复制到此新位置。重新进行测试以确保不需要从 Perl 旧版本继承的模块版本。

    实际上,步骤 6 中 pod2ipf(1) 的日志输出提供了有关从何处加载哪些模块的非常详细的信息;因此,你可以将其用作附加验证工具。

    检查一些临时文件是否已进入 perl 安装树。运行类似以下内容

    pfind . -f "!(/\.(pm|pl|ix|al|h|a|lib|txt|pod|imp|bs|dll|ld|bs|inc|xbm|yml|cgi|uu|e2x|skip|packlist|eg|cfg|html|pub|enc|all|ini|po|pot)$/i or /^\w+$/") | less

    在安装树(顶级和sitelib)中。

    使用lxlite压缩所有 DLL。可以使用/c:max压缩微小的.exe(错误仅在页面的最后 6 个字节中存在修补程序时出现(?);由于微小的可执行文件远小于一页,因此不会出现错误)。不要压缩perl_.exe - 它在 DOS 下不起作用。

  9. 现在,您可以生成二进制分发包。这是通过运行 CPAN 分发包OS2::SoftInstaller的测试来完成的。首先调整文件test.pl以适应当前版本的 Perl 布局。不要忘记相应地打包必要的外部 DLL。包括您无法修复的错误和测试套件故障的说明。包括 Perl 构建目录中 Perl 可执行文件的 small-stack 版本。

    包括perl5.def,以便人们可以在保留二进制兼容性的情况下重新链接 perl DLL,或者可以创建兼容性 DLL。包括您所做的修复的 diff 文件(diff -pu old new),以便人们可以重建您的版本。包括perl5.map,以便人们可以使用远程调试。

  10. 与其他人分享您的工作成果。放松。享受您的劳动成果。

  11. 为上一步带来的感谢、错误报告、仇恨邮件和垃圾邮件做好准备。任何善举都应该受到惩罚!

构建自定义.EXE文件

Perl 可执行文件可以在任何时候轻松重建。此外,人们可以使用嵌入接口(请参阅 perlembed)来制作非常定制的可执行文件。

使用静态加载扩展的自定义集合制作可执行文件

减少静态加载扩展列表时,这样做会稍微容易一些。我们在此仅讨论这种情况。

  1. 切换到一个空目录,并创建一个占位符 <Makefile.PL>

    use ExtUtils::MakeMaker;
    WriteMakefile NAME => 'dummy';
  2. 使用您想要重建的 Perl(perl.exeperl_.exe)的风格运行它。

    perl_ Makefile.PL
  3. 要求它创建新的 Perl 可执行文件

    make perl

    (您可能需要在某些版本的 Perl 上手动将PERLTYPE=-DPERL_CORE添加到此命令行;症状是命令行通配符无法通过 OS/2 shell 使用新编译的可执行文件工作;使用以下命令检查

    .\perl.exe -wle "print for @ARGV" *

    ).

  4. 上一步创建了perlmain.c,其中包含结尾附近的一系列 newXS() 调用。删除不必要的调用,并重新运行

    make perl

    将生成一个自定义的可执行文件。

使用自定义搜索路径制作可执行文件

默认的 Perl 可执行文件足够灵活,可以支持大多数用法。但是,人们可能希望它更灵活一些;例如,人们可能希望相对于 EXE 文件的位置找到 Perl DLL;或者人们可能希望在设置 Perl 库搜索补丁时忽略环境等。

如果您对嵌入界面感到满意(参见 perlembed),那么很容易通过重复 "使用自定义静态加载扩展集合制作可执行文件" 中概述的步骤,并对 perlmain.c 的 main() 进行更全面的编辑来完成这些事情。那些不太想了解 Perl 的人可以只重命名 main(),并在适当的时候调用重命名函数的自定义 main() 中进行必要的修改。

但是,还有第三种方法:perl DLL 导出了 main() 函数和几个回调函数以自定义搜索路径。以下是“Perl 加载器”的完整示例,它

  1. 在目录 $exedir/../dll 中查找 Perl DLL;

  2. 将上述目录添加到 BEGINLIBPATH 的前面;

  3. 如果通过 BEGINLIBPATH 找到的 Perl DLL 与在步骤 1 中加载的 DLL 不同,则会失败;例如,另一个进程可能已从 LIBPATHBEGINLIBPATH 的不同值加载了它。在这些情况下,需要修改系统设置,以便该另一个进程要么不运行,要么使用 LIBPATHSTRICT=T(2000 年 9 月之后的内核中可用)从 BEGINLIBPATH 加载 DLL。

  4. $exedir/../dll/lib/ 加载 Perl 库。

  5. $exedir/../dll/sh/ksh.exe 使用 Bourne shell。

为了获得最佳结果,请使用与 Perl DLL 相同的选项编译下面的 C 文件。但是,即使可执行文件不是 EMX 应用程序,例如,如果使用

gcc -Wall -DDOSISH -DOS2=1 -O2 -s -Zomf -Zsys perl-starter.c \
  -DPERL_DLL_BASENAME=\"perl312F\" -Zstack 8192 -Zlinker /PM:VIO

以下是示例 C 文件

#define INCL_DOS
#define INCL_NOPM
/* These are needed for compile if os2.h includes os2tk.h, not
 * os2emx.h */
#define INCL_DOSPROCESS
#include <os2.h>

#include "EXTERN.h"
#define PERL_IN_MINIPERLMAIN_C
#include "perl.h"

static char *me;
HMODULE handle;

static void
die_with(char *msg1, char *msg2, char *msg3, char *msg4)
{
   ULONG c;
   char *s = " error: ";

   DosWrite(2, me, strlen(me), &c);
   DosWrite(2, s, strlen(s), &c);
   DosWrite(2, msg1, strlen(msg1), &c);
   DosWrite(2, msg2, strlen(msg2), &c);
   DosWrite(2, msg3, strlen(msg3), &c);
   DosWrite(2, msg4, strlen(msg4), &c);
   DosWrite(2, "\r\n", 2, &c);
   exit(255);
}

typedef ULONG (*fill_extLibpath_t)(int type,
                                   char *pre,
                                   char *post,
                                   int replace,
                                   char *msg);
typedef int (*main_t)(int type, char *argv[], char *env[]);
typedef int (*handler_t)(void* data, int which);

#ifndef PERL_DLL_BASENAME
#  define PERL_DLL_BASENAME "perl"
#endif

static HMODULE
load_perl_dll(char *basename)
{
    char buf[300], fail[260];
    STRLEN l, dirl;
    fill_extLibpath_t f;
    ULONG rc_fullname;
    HMODULE handle, handle1;

    if (_execname(buf, sizeof(buf) - 13) != 0)
        die_with("Can't find full path: ", strerror(errno), "", "");
    /* XXXX Fill 'me' with new value */
    l = strlen(buf);
    while (l && buf[l-1] != '/' && buf[l-1] != '\\')
        l--;
    dirl = l - 1;
    strcpy(buf + l, basename);
    l += strlen(basename);
    strcpy(buf + l, ".dll");
    if ( (rc_fullname = DosLoadModule(fail, sizeof fail, buf, &handle))
                                                                   != 0
         && DosLoadModule(fail, sizeof fail, basename, &handle) != 0 )
        die_with("Can't load DLL ", buf, "", "");
    if (rc_fullname)
        return handle;    /* was loaded with short name; all is fine */
    if (DosQueryProcAddr(handle, 0, "fill_extLibpath", (PFN*)&f))
        die_with(buf,
                 ": DLL exports no symbol ",
                 "fill_extLibpath",
                 "");
    buf[dirl] = 0;
    if (f(0 /*BEGINLIBPATH*/, buf /* prepend */, NULL /* append */,
          0 /* keep old value */, me))
        die_with(me, ": prepending BEGINLIBPATH", "", "");
    if (DosLoadModule(fail, sizeof fail, basename, &handle1) != 0)
        die_with(me,
                 ": finding perl DLL again via BEGINLIBPATH",
                 "",
                 "");
    buf[dirl] = '\\';
    if (handle1 != handle) {
        if (DosQueryModuleName(handle1, sizeof(fail), fail))
            strcpy(fail, "???");
        die_with(buf,
                 ":\n\tperl DLL via BEGINLIBPATH is different: \n\t",
                 fail,
                 "\n\tYou may need to manipulate global BEGINLIBPATH"
                    " and LIBPATHSTRICT"
                    "\n\tso that the other copy is loaded via"
                    BEGINLIBPATH.");
    }
    return handle;
}

int
main(int argc, char **argv, char **env)
{
    main_t f;
    handler_t h;

    me = argv[0];
    /**/
    handle = load_perl_dll(PERL_DLL_BASENAME);

    if (DosQueryProcAddr(handle,
                         0,
                         "Perl_OS2_handler_install",
                         (PFN*)&h))
        die_with(PERL_DLL_BASENAME,
                 ": DLL exports no symbol ",
                 "Perl_OS2_handler_install",
                 "");
    if ( !h((void *)"~installprefix", Perlos2_handler_perllib_from)
         || !h((void *)"~dll", Perlos2_handler_perllib_to)
         || !h((void *)"~dll/sh/ksh.exe", Perlos2_handler_perl_sh) )
        die_with(PERL_DLL_BASENAME,
                 ": Can't install @INC manglers",
                 "",
                 "");
    if (DosQueryProcAddr(handle, 0, "dll_perlmain", (PFN*)&f))
        die_with(PERL_DLL_BASENAME,
                 ": DLL exports no symbol ",
                 "dll_perlmain",
                 "");
    return f(argc, argv, env);
}

构建常见问题解答

在 pdksh 中,一些 / 变成了 \

您的 pdksh 非常旧。请参见 "先决条件"

'errno' - 未解析的外部

您没有 MT 安全的 db.lib。请参见 "先决条件"

tr 或 sed 问题

在非常旧版本的 tr 和 sed 中报告。

一些问题(忘记哪一个 ;-)

您的 LIBPATH 上有较旧版本的 perl.dll,它破坏了扩展的构建。

库 ... 未找到

您没有运行 omflibs。请参见 "先决条件"

make 中的段错误

您使用的是旧版本的 GNU make。请参阅"先决条件"

op/sprintf 测试失败

这可能是由于 emx sprintf 中的错误导致的,该错误已在 0.9d 修复程序 03 中修复。

OS/2 端口的特定 (错误) 特性

setprioritygetpriority

请注意,这些函数与 *nix 兼容,不与 94 - 95 年的旧端口兼容。优先级是绝对的,范围从 32 到 -95,较低表示更快。0 是默认优先级。

警告。在 Warp3 fixpak22 之前,对不存在的进程调用 getpriority 可能会锁定系统。从 Warp3 开始,Perl 将使用一种解决方法:如果进程不存在,它将中止 getpriority()。在较旧的 2.* 版本中这是不可能的,并且无论如何都会出现竞争条件。

system()

system() 的多参数形式允许使用一个额外的数字参数。此参数的含义在 OS2::Process 中进行了描述。

在查找要运行的程序时,Perl 首先要求操作系统在 PATH 上查找可执行文件(如果未提供扩展名,OS/2 会添加扩展名 .exe)。如果未找到,它会按以下顺序查找具有可能扩展名的脚本:无扩展名、.cmd.btm.bat.pl。如果找到,Perl 会检查文件开头是否有魔术字符串 "#!""extproc "。如果找到,Perl 会将第一行的其余部分用作运行此脚本的命令行的开头。对第一行执行的唯一修改是提取参数(当前最多 3 个),并且如果无法使用完整路径找到“解释器”名称的路径部分,则忽略该部分。

例如,system 'foo', 'bar', 'baz' 可能会导致 Perl 找到 C:/emx/bin/foo.cmd,其第一行为

extproc /bin/bash    -x   -c

如果未找到 /bin/bash.exe,则 Perl 会在 PATH 上查找可执行文件 bash.exe。如果在 C:/emx.add/bin/bash.exe 中找到,则上述 system() 将转换为

system qw(C:/emx.add/bin/bash.exe -x -c C:/emx/bin/foo.cmd bar baz)

执行了一项额外的转换:Perl 使用硬连线或自定义 shell(请参阅"PERL_SH_DIR"),而不是 /bin/sh

以上对“解释器”的搜索是递归的:如果找不到bash可执行文件,但找到了bash.btm,Perl 将调查其第一行等。对递归深度唯一硬连线的限制是隐式的:在传递给 system() 的实际参数之前插入的其他参数的数量限制为 4。特别是,如果在“魔术”第一行中未指定其他参数,则深度限制为 4。

如果 Perl 发现找到的可执行文件是 PM 类型,而当前会话不是,它将在必要类型的单独会话中启动新进程。通过 OS2::Process 调用来禁用此魔术。

警告。由于所述逻辑,您需要在需要时明确指定.com扩展名。此外,如果请求可执行文件perl5.6.1,Perl 将不会查找perl5.6.1.exe。[这可能会在未来发生变化。]

第一行上的extproc

如果 Perl 脚本的第一个字符是"extproc ",则此行将被视为#!行,因此将处理此行上的所有开关(如果通过 cmd.exe 启动脚本,则处理两次)。请参阅perlrun 中的“DESCRIPTION”

其他模块

OS2::ProcessOS2::DLLOS2::REXXOS2::PrfDBOS2::ExtAttr。这些模块提供对 system 的其他数字参数的访问,以及对正在运行的进程、具有 REXX 签名的函数的 DLL 和 REXX 运行时、.INI 格式中的 OS/2 数据库以及扩展属性的信息的访问。

Andreas Kaiser 的两个其他扩展,OS2::UPMOS2::FTP,已包含在 ILYAZ 目录中,该目录在 CPAN 上镜像。其他与 OS/2 相关的扩展也可用。

预构建的方法

File::Copy::syscopy

File::Copy::copy 使用,请参阅File::Copy

DynaLoader::mod2fname

DynaLoader 用于 DLL 名称混淆。

Cwd::current_drive()

不言自明。

Cwd::sys_chdir(name)

保留驱动器。

Cwd::change_drive(name)

更改“当前”驱动器。

Cwd::sys_is_absolute(name)

表示具有驱动器号和 is_rooted。

Cwd::sys_is_rooted(name)

表示具有前导[/\\](可能在驱动器号之后:)。

Cwd::sys_is_relative(name)

表示随当前目录而变化。

Cwd::sys_cwd(name)

EMX 中 cwd 的接口。由 Cwd::cwd 使用。

Cwd::sys_abspath(name, dir)

真正令人讨厌的函数实现。返回文件的绝对名称,如果 CWD 为 dir,则该名称为 nameDir 默认为当前目录。

Cwd::extLibpath([type])

获取扩展库搜索路径的当前值。如果 type 存在且为正,则使用 END_LIBPATH,如果为负,则使用 LIBPATHSTRICT,否则使用 BEGIN_LIBPATH

Cwd::extLibpath_set( path [, type ] )

设置扩展库搜索路径的当前值。如果 type 存在且为正,则使用 <END_LIBPATH>,如果为负,则使用 LIBPATHSTRICT,否则使用 BEGIN_LIBPATH

OS2::Error(do_harderror,do_exception)

如果尚未调用,则返回 undef,否则,如果在上次调用中启用了 do_harderror,则设置位 1,如果在上次调用中启用了 do_exception,则设置位 2。

此函数启用/禁用与硬件错误(磁盘未就绪等)和软件异常关联的错误弹出窗口。

我不知道在首次调用此函数之前如何找出弹出窗口的状态。

OS2::Errors2Drive(drive)

如果尚未调用,则返回 undef,否则,如果未请求将错误写入硬盘,则返回 false,如果请求了,则返回驱动器号。

此函数可以将与硬件错误(磁盘未就绪等)和软件异常关联的错误弹出窗口重定向到指定驱动器的根目录中的 POPUPLOG.OS2 文件。覆盖各个程序指定的 OS2::Error()。给定的参数 undef 将禁用重定向。

具有全局效果,在应用程序退出后仍然存在。

我不知道在首次调用此函数之前如何找出弹出窗口重定向到磁盘的状态。

OS2::SysInfo()

返回包含系统信息的哈希。哈希的键为

MAX_PATH_LENGTH, MAX_TEXT_SESSIONS, MAX_PM_SESSIONS,
MAX_VDM_SESSIONS, BOOT_DRIVE, DYN_PRI_VARIATION,
MAX_WAIT, MIN_SLICE, MAX_SLICE, PAGE_SIZE,
VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION,
MS_COUNT, TIME_LOW, TIME_HIGH, TOTPHYSMEM, TOTRESMEM,
TOTAVAILMEM, MAXPRMEM, MAXSHMEM, TIMER_INTERVAL,
MAX_COMP_LENGTH, FOREGROUND_FS_SESSION,
FOREGROUND_PROCESS
OS2::BootDrive()

返回一个不带冒号的字母。

OS2::MorphPM(serve), OS2::UnMorphPM(serve)

将当前应用程序转换为 PM 应用程序,然后转换回来。参数 true 表示将提供一个真正的消息循环。OS2::MorphPM() 将 PM 消息队列句柄作为整数返回。

有关其他详细信息,请参见"集中管理资源"

OS2::Serve_Messages(force)

伪按需检索未完成的 PM 消息。如果force为 false,则在已知存在真实消息循环时不会分派消息。返回检索到的消息数。

如果获得 WM_QUIT 消息,则会显示“QUITing...”并退出。

OS2::Process_Messages(force [, cnt])

在创建/销毁窗口之前检索 PM 消息。如果force为 false,则在已知存在真实消息循环时不会分派消息。

返回窗口数量的变化。如果给出了cnt,则它将增加检索到的消息数。

如果获得 WM_QUIT 消息,则会显示“QUITing...”并退出。

OS2::_control87(new,mask)

与 EMX 的_control87(3)相同。将整数作为参数,将先前的协处理器控制字作为整数返回。在控制字中,只有new中存在于mask中的位才会发生更改。

OS2::get_control87()

将协处理器控制字作为整数获取。

OS2::set_control87_em(new=MCW_EM,mask=MCW_EM)

OS2::_control87() 的变体,其默认值适用于处理异常掩码:如果没有mask,则仅使用new的异常掩码部分。如果没有new,则禁用所有浮点异常。

有关详细信息,请参见"缺陷"

OS2::DLLname([how [, \&xsub]])

提供有关 Perl DLL 或包含绑定到 &xsub 的 C 函数的 DLL 的信息。how 的含义:默认值 (2):全名;0:句柄;1:模块名。

(请注意,其中一些内容可能最终会被移至不同的库)。

预构建变量

$OS2::emx_rev

数字值与 EMX 的 _emx_rev 相同,字符串值与 _emx_vprt 相同(类似于 0.9c)。

$OS2::emx_env

与 EMX 的 _emx_env 相同,类似于 0x8001 的数字。

$OS2::os_ver

数字 OS_MAJOR + 0.001 * OS_MINOR

$OS2::is_aout

如果 Perl 库以 AOUT 格式编译,则为 true。

$OS2::can_fork

如果当前可执行文件是 AOUT EMX 可执行文件,则为 true,因此 Perl 可以 fork。不要使用此项,请使用 $Config::Config{dfork} 的可移植检查。

$OS2::nsyserror

此变量(默认值为 1)控制是否强制 $^E 的内容以类似于 SYS0003 的 ID 开头。如果设置为 0,则 $^E 的字符串值是 OS/2 消息文件中可用的内容。(此文件中的某些消息前面添加了类似于 SYS0003 的 ID,而另一些则没有。)

错误功能

修改

Perl 以以下方式修改了一些标准 C 库调用

popen

如果需要 shell,my_popen 将使用 sh.exe,参见 "PERL_SH_DIR"

tmpnam

使用 TMPTEMP 环境变量通过 tempnam 创建。

tmpfile

如果当前目录不可写,则使用修改后的 tmpnam 创建文件,因此可能存在竞争条件。

ctermid

一个虚拟实现。

stat

os2_stat 特殊情况 /dev/tty/dev/con

mkdir, rmdir

如果路径包含尾部 /,这些 EMX 函数将不起作用。Perl 包含一个解决方法。

flock

由于 flock(3) 存在于 EMX 中,但不起作用,因此由 perl 模拟。要禁用模拟,请设置环境变量 USE_PERL_FLOCK=0

识别 DLL

使用当前 Perl 版本构建的所有 DLL 都具有 ID 字符串,用于识别扩展名、其版本以及此 DLL 所需的 Perl 版本。运行 bldlevel DLL-name 以查找此信息。

资源的集中管理

由于要调用某些 OS/2 API,需要正确初始化 Win 子系统,因此特定于 OS/2 的扩展可能需要获取 HABHMQ。如果一个扩展自行执行此操作,另一个扩展可能无法初始化。

Perl 提供了对这些资源的集中管理

HAB

要获取 HAB,扩展应在 C 中调用 hab = perl_hab_GET()。执行此调用后,可以将 hab 作为 Perl_hab 访问。使用 HAB 后无需释放它。

如果由于某些原因无法包含 perl.h,请使用

extern int Perl_hab_GET(void);

代替。

HMQ

有两种情况

  • 扩展仅需要 HMQ,因为否则某些 API 将无法正常工作。在下面使用 serve = 0

  • 扩展需要 HMQ,因为它希望参与 PM 事件循环。在下面使用 serve = 1

要获取 HMQ,扩展应在 C 中调用 hmq = perl_hmq_GET(serve)。执行此调用后,可以将 hmq 作为 Perl_hmq 访问。

要向 Perl 发出不再需要 HMQ 的信号,请调用 perl_hmq_UNSET(serve)。如果需要/不需要 HMQ,Perl 进程将自动将自身变形/解除变形为 PM 进程。如果消息队列已服务/未服务,Perl 将在关闭期间自动启用/禁用 WM_QUIT 消息。

注意。如果在关闭期间有一个未禁用 WM_QUIT 且未处理收到的 WM_QUIT 消息的消息队列,则关闭将自动取消。除非您要按顺序处理消息,否则不要调用 perl_hmq_GET(1)

处理 OS/2 API 报告的错误

OS/2 API 报告错误状况有两个主要约定(称它们为 Dos*Win* 很实用 - 尽管函数签名的这一部分并不总是由 API 的名称决定)。大多数 Dos* API 将错误代码报告为调用的结果(因此 0 表示成功,并且有许多类型的错误)。大多数 Win* API 通过结果为 TRUE/FALSE 报告成功/失败;要找到失败的原因,应调用 WinGetLastError() API。

一些 Win* 入口点还会用错误指示符重载“有意义”的返回值;具有 0 返回值表示错误。然而,一些其他 Win* 入口点会更多地重载内容,并且 0 返回值可能表示成功调用返回有效值 0,以及错误状况;在返回值为 0 的情况下,应调用 WinGetLastError() API 以区分成功调用和失败调用。

根据约定,所有对 OS/2 API 的调用都应通过重置 $^E 指示其失败。所有可由 Perl 访问的调用 OS/2 API 的函数可以分为两类:一些在遇到 API 错误时会 die(),另一些通过错误返回值报告错误(当然,这不涉及期望OS/2 API 调用失败的可由 Perl 访问的函数,这些函数已编码了一些解决方法)。

显然,在 OS/2 API 最后一种签名类型的情况下,如果通过 die() 指示故障,对用户来说会更方便:无需检查 $^E 即可知道出现了问题。但是,如果由于某种原因这种解决方案不可取,则相关代码应在调用此 OS/2 API 之前将 $^E 重置为 0,以便此 Perl 可访问函数的调用者有机会将成功但返回 0 的值与故障区分开来。(可以返回 undef 作为报告错误的替代方法。)

简化此类错误传播的宏是

CheckOSError(expr)

在发生错误时返回 true,设置 $^E。期望 expr() 是对 Dos* 风格 API 的调用。

CheckWinError(expr)

在发生错误时返回 true,设置 $^E。期望 expr() 是对 Win* 风格 API 的调用。

SaveWinError(expr)

返回 expr,如果 expr 为 false,则从 WinGetLastError() 设置 $^E。

SaveCroakWinError(expr,die,name1,name2)

返回 expr,如果 expr 为 false,则从 WinGetLastError() 设置 $^E,如果 die 和 $^E 为 true,则执行 die()。die() 的消息是连接的字符串 name1name2,用 ": " 从 $^E 的内容中分隔。

WinError_2_Perl_rc

Perl_rc 设置为 WinGetLastError() 的返回值。

FillWinError

Perl_rc 设置为 WinGetLastError() 的返回值,并将 $^E 设置为相应的值。

FillOSError(rc)

Perl_rc 设置为 rc,并将 $^E 设置为相应的值。

加载 DLL 和 DLL 中的序数

某些 DLL 仅出现在某些版本的 OS/2 中,或出现在 OS/2 的某些配置中。某些导出的入口点仅出现在某些版本的 OS/2 附带的 DLL 中。如果这些 DLL 和入口点直接链接到 Perl 可执行文件/DLL 或 Perl 扩展,则此二进制文件将仅适用于指定版本/设置。即使不需要这些入口点,可执行文件(或 DLL)的加载也会失败。

例如,许多较新的有用 API 在 OS/2 v2 中不存在;许多与 PM 相关的 API 需要在软盘引导设置中不可用的 DLL。

若要仅在执行调用时使这些调用失败,应通过动态链接 API 调用这些 API。Perl 中有一个子系统可简化此类调用。提供了大量可用于此类链接的入口点(请参阅os2ish.h 中的entries_ordinals - 以及PMWIN_entries)。可以通过以下 API 访问这些序数

CallORD(), DeclFuncByORD(), DeclVoidFuncByORD(),
DeclOSFuncByORD(), DeclWinFuncByORD(), AssignFuncPByORD(),
DeclWinFuncByORD_CACHE(), DeclWinFuncByORD_CACHE_survive(),
DeclWinFuncByORD_CACHE_resetError_survive(),
DeclWinFunc_CACHE(), DeclWinFunc_CACHE_resetError(),
DeclWinFunc_CACHE_survive(), DeclWinFunc_CACHE_resetError_survive()

有关使用这些函数的详细信息,请参阅提供的与 OS/2 相关的模块中的头文件和 C 代码。

其中一些函数还将动态加载语义与上述错误传播语义结合在一起。

Perl 风格

由于 OS/2 的特殊性,无法将所有鸡蛋放在同一个篮子里(尽管 EMX 环境努力克服这些限制,因此情况可能会得到改善)。该发行版提供了 4 个 Perl 可执行文件

perl.exe

主要工作引擎。这是一个嵌合体可执行文件:它被编译为a.out样式的可执行文件,但与omf样式的动态库perl.dll和动态 CRT DLL 链接。此可执行文件是 VIO 应用程序。

它可以加载 perl 动态扩展,并且可以分叉(fork())。

注意。请记住,需要 fork() 才能向自己打开管道。

perl_.exe

这是一个静态链接的a.out样式可执行文件。它无法加载动态 Perl 扩展。二进制发行版中提供的可执行文件预先构建了许多扩展,因此只有在使用自定义构建的扩展时,上述限制才重要。此可执行文件是 VIO 应用程序。

这是唯一不需要 OS/2 的可执行文件。被锁定在M$世界中的朋友会欣赏这样一个事实:此可执行文件可以在 DOS、Win0.3*、Win0.95 和 WinNT 中使用适当的扩展程序运行。请参阅"其他操作系统"

perl__.exe

这是与 perl___.exe 相同的可执行文件,但它是 PM 应用程序。

注意。通常(除非在启动期间明确重定向),PM 应用程序的 STDIN、STDERR 和 STDOUT 会重定向到 nul。但是,如果你从模拟控制台窗口的 PM 程序(如 Emacs 或 EPM 的 Shell 模式)启动 perl__.exe,则有可能“看到”它们。因此,有可能使用 Perl 调试器(请参阅 perldebug)来调试你的 PM 应用程序(但要注意消息循环锁定 - 如果你有要处理的消息队列,则此方法不起作用,除非你将处理挂接到调试器的 getc() 函数)。

查看 PM 程序输出的另一种方法是按如下方式运行它

pm_prog args 2>&1 | cat -

使用与 cmd.exe 不同的 shell,以便它不会在 VIO 会话和 pm_porg 会话之间创建链接。(此类链接会关闭 VIO 窗口。)例如,这适用于 sh.exe - 或 Perl!

open P, 'pm_prog args 2>&1 |' or die;
print while <P>;

如果你想在没有 VIO 窗口的情况下启动程序,但未 detach(运行 help detach 了解更多信息),则需要 perl__.exe 版本。对于使用 PM 的扩展非常有用,如 Perl/TkOpenGL

还要注意,PM 和 VIO 可执行文件之间的差异仅在于默认行为。可以通过使用命令 startCMD.EXE 或类似 shell)的参数 /fs/pm/win 开关在任何类型的会话中启动任何可执行文件。或者,可以使用 system Perl 函数的第一个数字参数(请参阅 OS2::Process)。

perl___.exe

这是一个与 perl.dll 和 CRT DLL 动态链接的 omf 样式可执行文件。我不知道此可执行文件相对于 perl.exe 有什么优势,但它根本无法 fork()。嗯,一个优点是构建过程不像 perl.exe 那样复杂。

它是一个 VIO 应用程序。

为什么是奇怪的名称?

由于 Perl 处理 #!-line(请参阅 perlrun 中的“DESCRIPTION”perlrun 中的“Command Switches”perldiag 中的“No Perl script found in input”),因此它应该知道何时程序是 Perl。有一些命名约定允许 Perl 区分正确的行和错误的行。上述名称几乎是此约定允许的唯一不包含数字(具有完全不同语义)的名称。

为什么动态链接?

好吧,将多个可执行文件动态链接到同一个庞大库中具有其优势,但这并不能证明使其编译的额外工作是合理的。原因在于 OS/2 使用的“硬”动态链接对开发者来说很复杂,但对用户来说非常快速且方便。

OS/2 的动态链接模型有两个显著特点:首先,所有对外部函数的引用都在编译时解析;其次,在 DLL 加载到内存后,不会对它们进行运行时修复。第一个特点比其他模型具有巨大的优势:它避免了应用程序使用的多个 DLL 导出具有相同名称的条目时发生的冲突。在这样的情况下,“其他”动态链接模型只是使用一些随机标准在这两个入口点之间进行选择 - 结果是可预见的灾难。但是,正是第二个特点需要构建 perl.dll。

DLL 的地址表仅在加载时修补一次。对于使用相同 DLL 的所有程序,保证 DLL 中入口点的地址相同。这消除了运行时修复 - 一旦 DLL 加载,其代码就是只读的。

虽然这允许一些(显著的?)性能优势,但这给开发人员带来了更大的困难,因为上述方案使得 DLL 无法“链接”到 .EXE 文件中的符号。事实上,这需要 DLL 为使用此 DLL 的(不同)可执行文件具有不同的重定位表。

但是,动态加载的 Perl 扩展被迫使用 perl 可执行文件中的某些符号,例如,了解如何查找函数的参数:参数位于 perl 内部求值堆栈上。解决办法是将解释器的主要代码放入 DLL 中,并制作 .EXE 文件,该文件仅将此 DLL 加载到内存中并提供命令参数。扩展 DLL 无法链接到 .EXE 中的符号,但它可以链接到 .DLL 中的符号,这没有问题。

这极大地增加了应用程序的加载时间(以及编译的复杂性)。由于解释器位于 DLL 中,因此 C RTL 基本上也被迫驻留在 DLL 中(否则扩展将无法使用 CRT)。如果您使用不同版本的 perl,例如同时运行 perl.exe 和 perl__.exe,则会有一些优势:它们共享 perl.dll 的内存。

注意。还有一个额外的影响使得 DLL 更加浪费:DLL 加载在共享内存区域中,这是一个稀缺资源,因为“标准”OS/2 虚拟内存的 512M 障碍。.EXE 文件的代码也由使用特定 .EXE 的所有进程共享,但它们“在进程的私有地址空间中共享”;这是可能的,因为 .EXE 文件的不同部分加载到的地址是在编译时确定的,因此所有进程都在相同的地址加载这些部分,并且不需要修复 .EXE 内部链接。

由于 DLL 可以在运行时加载,因此要为 DLL 拥有相同的机制,需要在系统中任何已加载 DLL 的地址范围在所有进程中可用,这些进程尚未加载特定 DLL。这就是 DLL 映射到共享内存区域的原因。

为什么进行嵌合构建?

当前的 EMX 环境不允许使用 Unixish a.out 格式编译的 DLL 导出数据符号(或至少某些类型的数据)。这强制对 perl.dll 进行 omf 风格的编译。

当前的 EMX 环境不允许以 omf 格式编译的 .EXE 文件进行 fork()。fork() 对于正好三个 Perl 操作是必需的

虽然这些操作不是生死攸关的问题,但它们对于许多有用的脚本是必需的。这强制对 perl.exe 进行 a.out 风格的编译。

环境

这里我们列出环境变量,它们可能是 OS/2 和 DOS 和 Win* 特有的,或者在 OS/2 中比在其他操作系统中更重要。

PERLLIB_PREFIX

EMX 端口特有的。应该具有以下形式

path1;path2

path1 path2

如果某些预建路径的开头与 path1 匹配,则用 path2 替换它。

如果 perl 库从默认位置移动,则应该使用它,而不是 PERL(5)LIB,因为这不会在 @INC 中留下错误的条目。例如,如果编译的 perl 版本在 f:/perllib/lib 中查找 @INC,并且您想在 h:/opt/gnu 中安装库,请执行

set PERLLIB_PREFIX=f:/perllib/lib;h:/opt/gnu

这将导致 Perl 使用预建的 @INC

f:/perllib/lib/5.00553/os2
f:/perllib/lib/5.00553
f:/perllib/lib/site_perl/5.00553/os2
f:/perllib/lib/site_perl/5.00553
.

使用以下 @INC

h:/opt/gnu/5.00553/os2
h:/opt/gnu/5.00553
h:/opt/gnu/site_perl/5.00553/os2
h:/opt/gnu/site_perl/5.00553
.

PERL_BADLANG

如果为 0,perl 将忽略 setlocale() 失败。对于一些奇怪的 区域设置可能有用。

PERL_BADFREE

如果为 0,perl 将不会在出现不合理的 free() 时发出警告。对于较旧的 perl,这可能与 DB_File 模块结合使用,该模块在动态链接和 OMF 构建时存在错误。

不应与较新的 Perl 一起设置,因为这可能会隐藏一些实际问题。

PERL_SH_DIR

EMX 端口特定。提供 sh.exe 位置的目录部分。

USE_PERL_FLOCK

EMX 端口特定。由于 EMX 中存在 flock(3),但不可用,因此由 perl 模拟。要禁用模拟,请设置环境变量 USE_PERL_FLOCK=0

TMPTEMP

EMX 端口特定。用作临时文件的存储位置。

演变

此处列出了可能让你感到惊讶的主要更改。

文本模式文件句柄

从 5.8 版本开始,Perl 对文本模式文件使用内置转换层。这用一些代码替换了经过充分测试的 EMX 层,这些代码最好描述为“快速黑客”。

除了可能的错误和无法通过 TERMIO 转换的开/关开关来遵循转换策略的更改之外,这还引入了一个严重的不兼容更改:在文本模式文件句柄上进行 sysread() 之前会通过转换层,现在不会了。

优先级

setprioritygetpriority 与 Andreas Kaiser 早期的端口不兼容。请参见 "setpriority, getpriority"

DLL 名称混淆:5.6.2 之前

随着 5.003_01 版本的发布,在编译不同版本的 Perl 时应重建可动态加载的库。特别是,DLL(包括 perl.dll)现在使用包含校验和的名称创建,从而允许解决 OS/2 DLL 缓存方案。

可以编写一个简单的解决方法,该方法将

DLL 名称混淆:5.6.2 及更高版本

实际上,扩展 DLL 的混淆是由于对 OS/2 动态加载模型的误解造成的。OS/2(有效地)维护两个不同的已加载 DLL 表

全局 DLL

LIBPATH 中按基本名称加载的那些;包括在链接时关联的那些;

特定 DLL

按全名加载。

在解析对全局 DLL 的请求时,已加载的特定 DLL 表(有效地)被忽略;此外,特定 DLL 始终 从规定的路径加载。

有一个/曾有一个小问题,使此方案变得脆弱:如何处理从

BEGINLIBPATHENDLIBPATH

(取决于进程)

.LIBPATH

有效地 取决于进程(尽管 LIBPATH 对所有进程都是相同的)。

除非将 LIBPATHSTRICT 设置为 T(并且内核在 2000/09/01 之后),否则此类 DLL 被视为全局。在加载全局 DLL 时,首先在已加载的全局 DLL 表中查找它。因此,一个可执行文件从 BEGINLIBPATHENDLIBPATH.LIBPATH 加载 DLL 的事实可能会影响在另一个 可执行文件请求具有相同名称的 DLL 时加载哪个 DLL。这是 Perl DLL 的 DLL 名称进行特定版本混淆的原因。

由于 Perl 扩展 DLL 总是使用完整路径加载,因此无需以特定于版本的方式修改其名称:其目录已反映了相应的 Perl 版本,并且 @INC 考虑了与旧版本的二进制兼容性。从 5.6.2 开始,名称修改方案被固定为与 Perl 5.005_53 相同(与流行的二进制发行版中相同)。因此,如果 @INC 允许查找旧扩展 DLL 的目录,新的 Perl 将能够解析旧扩展 DLL 的名称

但是,这仍然不能保证可以加载这些 DLL。原因是Perl DLL 的名称修改。由于扩展 DLL 与 Perl DLL 链接,因此旧版本的扩展 DLL 将加载旧版本的 Perl DLL,并且很可能会出现段错误(因为此 DLL 中的数据未正确初始化)。

有一个部分解决方法(可以使用较新的 OS/2 内核完成):创建一个转发器 DLL,其名称与旧版本 Perl 的 DLL 相同,该转发器将入口点转发到较新 Perl 的 DLL。使此 DLL 在(例如)新 Perl 可执行文件的 BEGINLIBPATH 上可访问。当新可执行文件访问旧 Perl 的扩展 DLL 时,它们将按名称请求旧 Perl 的 DLL,而是获取转发器,因此实际上将链接到当前运行的(新)Perl DLL。

这可能会以两种方式中断

借助对 LIBPATHSTRICT 的支持,可以规避此问题 - 除非从 LIBPATH 中的. 启动其中一个 DLL(我不知道 LIBPATHSTRICT 是否会影响这种情况)。

备注。除非较新的内核允许在 BEGINLIBPATH 中使用.(较旧的内核不允许),否则无法彻底清除此混乱。(事实证明,截至 2002 年初,不允许使用.,但允许使用.\. - 并且它具有相同的效果。)

备注LIBPATHSTRICTBEGINLIBPATHENDLIBPATH 不是环境变量,尽管cmd.exeSET ... 行上模拟它们。从 Perl 中,可以通过 Cwd::extLibpathCwd::extLibpath_set 访问它们。

DLL 转发器生成

假设旧 DLL 名为perlE0AC.dll(如 5.005_53 的 DLL),新版本为 5.6.1。使用以下内容创建一个文件perl5shim.def-leader

LIBRARY 'perlE0AC' INITINSTANCE TERMINSTANCE
DESCRIPTION '@#[email protected]:5.006001#@ Perl module for 5.00553 -> Perl 5.6.1 forwarder'
CODE LOADONCALL
DATA LOADONCALL NONSHARED MULTIPLE
EXPORTS

根据需要修改版本/名称。运行

perl -wnle "next if 0../EXPORTS/; print qq(  \"$1\")
                                         if /\"(\w+)\"/" perl5.def >lst

在 Perl 构建目录中(为了使 DLL 更小,如果存在,请用旧版本 Perl 的定义文件替换 perl5.def)。

cat perl5shim.def-leader lst >perl5shim.def
gcc -Zomf -Zdll -o perlE0AC.dll perl5shim.def -s -llibperl

(忽略多个警告 L4085)。

多线程

从 5.003_01 版本开始,perl 链接到多线程 C RTL DLL。如果 perl 本身没有编译为多线程启用,那么 perl 的 malloc() 也不会启用。但是,扩展可以自行承担风险使用多个线程。

这是为了编译开箱即用的 XFree86-OS/2 的 Perl/Tk,并链接到其他有用库的 DLL,这些库通常使用 -Zmt -Zcrtdll 编译。

调用外部程序

由于流行的需求,perl 外部程序调用已针对 Andreas Kaiser 的端口进行了更改。如果 perl 需要通过 shell调用外部程序,则将调用f:/bin/sh.exe,或任何覆盖,请参阅 "PERL_SH_DIR"

因此,这意味着您还需要获取一个sh.exe 的副本(我使用 pdksh 中的一个)。上面的路径F:/bin 在构建期间会在构建器机器上自动设置为正确的值,但可以在运行时覆盖,

原因:perl5-porters 的共识是 perl 应该为每个平台使用一个不可覆盖的 shell。OS/2 的明显选择是cmd.exesh.exe。使用cmd.exe 作为 shell,perl 无法自行构建,因此我选择了sh.exe。这确保了与来自 *nix 的脚本几乎 100% 的兼容性。作为附加好处,如果您使用 pdksh 的 DOS 启用端口(请参阅 "先决条件"),这在 DOS 下也能正常工作。

缺点:目前 pdksh 的sh.exe 通过 fork()/exec() 调用外部程序,并且 OS/2 上没有可用的 exec()。exec() 由 EMX 通过异步调用模拟,而调用者等待子进程完成(以假装pid 没有改变)。这意味着通过 fork()/exec() 激活了sh.exe 的 1 个额外副本,这可能会导致从系统中获取一些资源(即使我们不计算 fork() 所需的额外工作)。

请注意,当我们不需要时不会生成sh.exe,因此现在这是一个较小的问题(找到了元字符)。

可以通过以下方式始终显式启动cmd.exe

system 'cmd', '/c', 'mycmd', 'arg1', 'arg2', ...

如果您需要使用cmd.exe,并且不想手动编辑数千个脚本,p5-p 上提出的长期解决方案是使用指令

use OS2::Cmd;

它将覆盖 system()、exec()、``open(,'...|')。使用当前的 perl,你只能覆盖 system()、readpipe() - `` 的显式版本,以及可能是 exec()。该代码将用 CORE::system('cmd.exe', '/c', shift) 替换 system() 的单参数调用。

如果你有一些适用于 OS2::Cmd 的工作代码,请将其发送给我,我将把它包含到发行版中。我并不需要这样的模块,因此无法对其进行测试。

有关调用外部程序的当前情况的详细信息,请参阅 "在 Perl 下启动 OS/2(和 DOS)程序"。让我们提一下几个特性

内存分配

Perl 在 OS/2 下使用自己的 malloc() - 解释器通常受 malloc 限制以提高速度,但 perl 不受限制,因为它的 malloc 非常快。经过 Perl 内存使用情况调整的基准测试表明,Perl 的 malloc 比 EMX 的快 5 倍。我没有关于内存占用空间的令人信服的数据,但一个(相当随机的)基准测试表明,Perl 的内存占用空间要好 5%。

perl 的 malloc() 和严格的 DLL 名称解析的组合为库函数创建了一个特殊问题,这些库函数希望它们的返回值由系统的 free() 释放。为了方便需要调用此类函数的扩展,系统内存分配函数仍然可用,并添加了前缀 emx_。(目前只有 DLL perl 具有此功能,它应该很快传播到 perl_.exe。)

线程

可以通过向 Configure 提供 -D usethreads 选项来构建启用了线程支持的 perl。目前,OS/2 对线程的支持非常初步。

最显着的问题

COND_WAIT

可能存在竞争条件(但由于 OS/2 事件信号量的边缘触发特性,可能不存在)。(需要重新实现(以链接等待线程的方式,将链表存储在每个线程结构中?)?)

os2.c

在 OS/2 特定的函数中使用了一些静态变量。(需要移动到每个线程结构,还是需要序列化?)

请注意,这些问题不应阻碍实验,因为它们影响小程序的可能性很低。

BUG

此描述不常更新(自 5.6.1 起?),请参阅 ./os2/Changes 了解更多信息。

作者

Ilya Zakharevich,[email protected]

另请参阅

perl(1)。