#! /usr/bin/perl
# Log the environment in which this script is running.
# Each entry in @ARGV is a program of interest, which is invoked with the
# --version option.
# Copyright (C) 2021 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
use v5.14; # implicit use strict, use feature ':5.14'
use warnings FATAL => 'all';
use utf8;
use open qw(:utf8);
use Cwd qw(getcwd);
use FindBin ();
use POSIX ();
use lib $FindBin::Bin;
use BuildCommon qw(
ensure_C_locale
ensure_empty_stdin
error
get_status
get_status_and_output
run
sh_quote
which
);
# C library detection for Linux. Algorithm from NPM package 'detect-libc',
# ; currently only supports GNU and
# musl libc. If cross-compiling, the result is for the build environment,
# not the host or target. Does not use a C compiler.
sub report_linux_libc {
# Try getconf.
my ($gcstat, @gcout) = get_status_and_output('getconf', 'GNU_LIBC_VERSION');
if ($gcstat == 0) {
my $gcver = $gcout[0];
chomp $gcver;
print "C library: $gcver\n\n";
return;
} elsif ($gcstat == -1) {
print "getconf: command not found\n";
}
# Try ldd --version.
my ($ldstat, @ldout) = get_status_and_output('ldd', '--version');
if ($ldstat == 0 || $ldstat == 1) {
my $ld1 = $ldout[0];
my $ld2 = $ldout[1];
if ($ld1 =~ /\bmusl\b/ia) {
$ld2 =~ s/^version\s+(\S+).*$/$1/i;
print "C library: musl $ld2\n\n";
return;
}
if ($ld2 =~ /^copyright.*free software foundation/i) {
$ld1 =~ s/^\S+\s+\([^\)]+\)\s+//;
$ld1 =~ s/\s+\z//;
print "C library: glibc $ld1\n\n";
return;
}
print "WARNING: ldd --version output not recognized:\n";
for my $line (@ldout) {
print '> ', $line;
}
print "\n";
} elsif ($ldstat == -1) {
print "ldd: command not found\n";
} else {
print "WARNING: ldd --version exit $ldstat\n";
for my $line (@ldout) {
print '> ', $line;
}
print "\n";
}
# detect-libc goes on to poke around in /lib, which I don't think is
# solid enough to base an actual detection on, but we may as well list
# contents that may be relevant.
print "C library: unknown\n\n";
run("ls", "-l", glob('/lib*/{libc[.-],ld[-.]*.so}*'));
print "\n";
}
sub report_machine {
print "## Machine information:\n\n";
my ($sysname, undef, $release, $version, $machine) = POSIX::uname();
print '$(uname -m) = ', sh_quote($machine || 'unknown'), "\n";
print '$(uname -r) = ', sh_quote($release || 'unknown'), "\n";
print '$(uname -s) = ', sh_quote($sysname || 'unknown'), "\n";
print '$(uname -v) = ', sh_quote($version || 'unknown'), "\n";
print "\n";
if ($sysname eq 'Linux') {
report_linux_libc();
my $npstat = get_status('nproc');
if ($npstat != 0) {
print "nproc: exit $npstat\n";
}
} elsif ($sysname eq 'FreeBSD') {
run('sysctl', 'kern.sched.topology_spec');
} else {
print "WARNING: don't know how to probe #CPUs on this OS\n";
}
print "\n";
my $cwd = getcwd();
my $qcwd = sh_quote($cwd);
print '$(pwd) = ', $qcwd, "\n";
print "WARNING: working directory requires quotation\n"
if $cwd ne $qcwd;
print "\n";
## FIXME: Not all df implementations support -h or -T.
run(qw(df -h -T), $cwd);
print "\n";
}
sub report_ENV {
my $envp = $_[0];
print "## Environment variables:\n\n";
for my $key (sort keys %$envp) {
print ' ', sh_quote($key), '=', sh_quote($envp->{$key}), "\n";
}
print "\n";
}
sub report_programs {
print "## Programs used during build:\n\n";
for my $prog (@_) {
my ($absprog) = which($prog);
if ($absprog) {
print sh_quote($prog), ' is ', sh_quote($absprog), "\n";
# Try various options that might get a program to print its
# version number, in order of likelihood.
# mawk only recognizes -Wversion
# -qversion is in AC_PROG_CC's list of things to try
for my $vopt (qw(--version -V -v -Wversion -qversion)) {
my $status = get_status($absprog, $vopt);
last if $status == 0;
if ($status == -1) {
# 'no such file or directory' doesn't make sense here
print "$absprog $vopt: exit 126\n";
} else {
print "$absprog $vopt: exit $status\n";
}
}
} else {
print "WARNING: $prog not found in \$PATH\n";
}
print "\n";
}
}
sub main {
my %orig_env = %ENV;
ensure_C_locale();
ensure_empty_stdin();
print "# CI environment report\n";
report_machine();
report_ENV(\%orig_env);
report_programs(@_) if scalar(@_);
};
eval {
main(@ARGV);
exit(0);
};
error("$@");