Perl配置信息模块-Config
2024-01-23 11:17:01 阿炯

Config模块包含在Perl构建时Configure程序可用的所有信息(其中有超过900个选项及其值,不过部分的信息准确性有点问题,需要使用者甄选核对)。

config.sh文件中的Shell变量(由Configure编写)存储在只读变量%config中,并按其名称进行索引,并以"undef"形式存储在config.sh中的值将作为未定义的值返回。exists函数可用于检查命名变量是否存在。

myconfig()
Returns a textual summary of the major perl configuration values. See also -V in Command Switches in perlrun.
返回主要perl配置值的文本摘要。另请参阅perlrun中命令开关中的-V。

config_sh()
Returns the entire perl configuration information in the form of the original config.sh shell variable assignment script.
以原始config.sh shell变量分配脚本的形式返回整个perl配置信息。

config_re($regex)
Like config_sh() but returns, as a list, only the config entries who's names match the $regex.
与config_sh()类似,但作为一个列表,只返回名称与$regex匹配的配置条目。

config_vars(@names)
Prints to STDOUT the values of the named configuration variable. Each is printed on a separate line in the form:
将命名配置变量的值打印到STDOUT。每个都打印在单独行上,格式如下:
name='value';

Names which are unknown are output as name='UNKNOWN'; . See also -V:name in Command Switches in perlrun.
未知的名称输出为name="unknown"。另请参阅perlrun中命令开关中的-V:name。

bincompat_options()
Returns a list of C pre-processor options used when compiling this perl binary, which affect its binary compatibility with extensions. bincompat_options() and non_bincompat_options() are shown together in the output of perl -V as Compile-time options.
返回编译此perl二进制文件时使用的C预处理器选项的列表,这些选项会影响其与扩展的二进制兼容性。bincompat_options()和non_bomplat_options()在perl -V的输出中一起显示为编译时(Compile-time)选项。

non_bincompat_options()
Returns a list of C pre-processor options used when compiling this perl binary, which do not affect binary compatibility with extensions.
返回编译此perl二进制文件时使用的C预处理器选项的列表,这些选项不会影响二进制文件与扩展的兼容性。

compile_date()
Returns the compile date (as a string), equivalent to what is shown by perl -V
返回编译日期(以字符串形式),相当于perl-V显示的日期

local_patches()
Returns a list of the names of locally applied patches, equivalent to what is shown by perl -V
返回本地应用的补丁程序名称列表,相当于perl -V所显示的'Locally applied patches'。

header_files()
Returns a list of the header files that should be used as dependencies for XS code, for this version of Perl on this platform.
返回应该用作XS代码依赖项的头文件列表,其用于此平台上此版本的Perl。


一些参考示例:

################
use v5.32;
use Config qw(myconfig config_sh config_vars config_re bincompat_options compile_date local_patches header_files);

config_vars qw/osname osvers archname ivsize/;

#say myconfig();
say '=' x 32;

say config_sh();
say '=' x 32;

#say config_vars();
say '=' x 32;

my @bco = bincompat_options();
#say "@bco";
say '=' x 32;

#say compile_date();
say '=' x 32;

my @lps = local_patches();
#say for @lps;
say '=' x 32;

my @hdfs = header_files();
#say for @hdfs;
say '=' x 32;

有太多的输出,大多操作系统的编译、运行环境相关:
cc='x86_64-linux-gnu-gcc'
archname='x86_64-linux-gnu-thread-multi'
cpp='x86_64-linux-gnu-cpp'
ld='x86_64-linux-gnu-gcc'
hostosname=''        #主机名居然没有取到?
osname='linux'
osvers='4.19.0'        #这个与当前运行的linux内核版本不符,难道是预编译版本的主机内核?
version='5.32.1'

################

use v5.32;
use Config;

say 'threadsupted.' if ($Config{usethreads});
say '=' x 32;
say 'cc:'.$Config{cc};

################

use v5.28;
use Config;
my ($osd,$osv)=($Config{osname},(split(/-/,$Config{osvers}))[0]);
say "$osd,$osv";


检查Perl所在的主机环境信息

取得其所在主机的端序
perl -MConfig -E 'say "$Config{byteorder}";'
12345678

perl -V:byteorder
byteorder='12345678';

明显是小端,Byteorders "1234" and "12345678" are little-endian; "4321" and "87654321" are big-endian.

在perlmonks.org上看到的一个示例
Convert hex string from little endian to decimal

See the "Perl pack() and unpack() Tutorial" to get a basic understanding of how pack and unpack work.
$ perl -le 'my $h = "5840b200"; print unpack "I", pack "H*", $h'
11681880

显然作者后面意识到了问题,修正了一下:
See hex.
Update: Sorry, didn't see the bit about little-endianity. See also reverse.

perl -e 'print sprintf("%#d",0x5840b200)'
1480634880

The module Bit::Vector has a built-in method for reversing bit-order ...
And the module is internally written in C ...

但如何使用看具体学习了。

如何得知当前主机为大端还是小端
First I sensed whether I am bigendian or littleendian. Either read the file and look at the endian flag (bytes 0-1 in a TIFF file for instance), or sense my own system's endianness by

$x = pack("S", 256);
$bigendian = ord(substr($x, 0, 1));    # 1 for bigendian 0 for littleendian
#如果系统为非标准(既不是大端序也不是小端序)字节排序(例如PDP-11),则下面的代码可能会失败。
$big_endian = pack("L", 1) eq pack("N", 1);

Once I have a value for $bigendian, I use variables for packing and unpacking:
$short = $bigendian ? "n" : "v";
$long = $bigendian ? "N" : "V";
($a,$b) = unpack($long . "2", substr($temp,0,8));
($c,$d) = unpack($short . "2", substr($temp,8,4));

nN stands for "network" which is a standard that calls for bigendian.

vV stands for "Vax", an old DEC system which is littleendian.

print "ok\n" if 0x12653489 == unpack 'L', pack 'N', 0x89346512;


Little endian to Big endian(in Perl)

这是一些网络程序员在编码时遇到的问题之一。在调试可执行文件时可能已经注意到,当在十六进制编辑器中看到时,文件中的一些数据是向后排列的。首先看到的是1,然后是几个零。但可以肯定的是,为常数编码的值实际上是'1',而不是01 00 00 00。这就是小端字节顺序,十进制值305419896的十六进制是0x12345678。如果机器是大端序,会看到这个值存储在一个二进制文件中,看起来和它一样。但如果计算机是小端序,存储在文件中的值看起来像78 56 34 12。最不重要的字节将在前面,最重要的字节在后面。

此外受制于速度。如果处理器只有3个实寄存器(X、Y和Accumulator),那么如果它们是小端序,则更容易计算这些值。
Y = 0;
A = 1;
foreach byte do {
    X = readbyte;    # we read next byte
    if X > 0 do {    # Check if the computation is needed at all.
        Y = Y + (X * A);    # we use Y to collect the results of all bytes multiplied by A
    }
    SHL A << 8;    # A grows from 1 to 256 to 65536 to 16777216 (2^0, 2^8, 2^16, 2^24)
}

这当然是现在所知的64位处理器的理想情况。可以使用64位字和寄存器的一种。如果使用的是大端字节顺序,则不能使用乘法,而是使用整数除法,后者速度较慢。如果是Linux用户,但不确定设备使用的端序,请执行以下操作:
# perl -MConfig -e 'print "$Config{byteorder}\n";'

如果想颠倒这个字节顺序并使用简单的数学方法显示,请使用以下Perl脚本:
#!/usr/bin/perl -w
my ($a1,$a2,$a3,$a4,$r);
if (!$ARGV[0]) {die "There are no args";}
$r = $ARGV[0];

$a1 = $r % 256;
$a2 = ($r - $a1) % 65536;
$a3 = ($r - $a1 - $a2) % 16777216;
$a4 = ($r - $a1 - $a2 - $a3);

$a2 = $a2 / 256;
$a3 = $a3 / 65536;
$a4 = $a4 / 16777216;

printf ("\n$r is equal to 0x%02x 0x%02x 0x%02x 0x%02x\n", $a4, $a3, $a2, $a1);
printf ("$r is reverted to 0x%02x 0x%02x 0x%02x 0x%02x\n\n", $a1, $a2, $a3, $a4);


这只是一个粗略的例子。有一种更容易的方法来制作和解释它。获取输入值,通过从输入值中获取整数除法的“模”可以获得最低有效字节,将该模存储在数组中。在此之后,从该输入值减去模并将该值除以256。这是新的输入值。重复,直到值为零。您有一个[最高有效、较低有效…最低有效]字节的数组。

该脚本只能处理长整数,但可以很容易地处理64位字。把它写得很短,因为它更容易阅读。使用Little endian,将始终看到向后的字节顺序:

# ./RevertByteOrder.pl 305419896
305419896 is equal to    0x12 0x34 0x56 0x78
305419896 is reverted to 0x78 0x56 0x34 0x12

# ./RevertByteOrder.pl 22136
22136 is equal to    0x00 0x00 0x56 0x78
22136 is reverted to 0x78 0x56 0x00 0x00

# ./RevertByteOrder.pl 4660
4660 is equal to    0x00 0x00 0x12 0x34
4660 is reverted to 0x34 0x12 0x00 0x00

如果需要查看设备使用的每个整数和长整数的字节数,请执行以下操作:
perl -V:{short,int,long{,long}}

short='UNKNOWN';
int='UNKNOWN';
long='UNKNOWN';
longlong='UNKNOWN';

参考:
Config

25.2. Endianness and Number Width