Search code examples
perlipc

Calling configure and make from Perl script


I need help please. I'm writing a Perl script to configure, compile and install MPICH. The initial two tasks require calling configure and make commands. I'm struggling to pass the options to configure command. Please find my minimal example below:

#!/usr/local/bin/perl

use v5.38;
use autodie;
use strict;
use warnings;
use IPC::System::Simple qw(capturex);

# Writes text into given file
sub writef($fname, $txt) {
    open  my $fh, ">:encoding(UTF-8)", $fname;
    print $fh $txt;
    close $fh;
}

my $gnubin ='/opt/local/bin';
my $prefix ='/opt/mpich-4.1.2';
my $np     = 8;
my $txt;

print "Setting environment variables...\n";

$ENV{'FC'}  = $gnubin . '/gfortran';
$ENV{'F77'} = $ENV{'FC'};
$ENV{'CC'}  = $gnubin . '/gcc';
$ENV{'CXX'} = $gnubin . '/g++';

$ENV{'FFLAGS'} = '-m64 -fallow-argument-mismatch';
$ENV{'CFLAGS'} = '-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -m64';

mkdir 'build';
chdir 'build';

print "Configuring MPICH...\n";
my $conf_options = "--prefix=$prefix --enable-shared=no --enable-fast=O3,ndebug --disable-error-checking --enable-fortran=all --enable-cxx --disable-opencl --enable-romio --without-timing --without-mpit-pvars";
$txt = capturex('../configure', $conf_options);
&writef('c.txt', $txt);

print "Compiling MPICH...\n";
$txt = capturex('make', '-j', $np);
&writef('m.txt', $txt);

Configuration is done correctly, but compilation fails with the following error messages:

gcc: error: unrecognized command-line option '--without-timing'
gcc: error: unrecognized command-line option '--without-mpit-pvars/etc"'
gcc: error: unrecognized command-line option '--without-mpit-pvars/lib/libfabric"'

It seems I have a problem in the capturex call. I suspect there are no spaces in between the $conf_options when they are passed to capturex command. I tried declaring configure options as an array my @conf_options and passing the strings in the qq() operator. But that fails with a similar set of errors. Any help would be greatly appreciated.


Solution

  • Instead of passing arguments, you are passing part of a shell command to a sub that doesn't invoke a shell.

    Replace

    my $conf_options = "--prefix=$prefix --enable-shared=no ...";
    my $txt = capturex( "../configure", $conf_options );
    

    with

    my @conf_options = ( "--prefix=$prefix", "--enable-shared=no", "..." );
    my $txt = capturex( "../configure", @conf_options );
    

    or

    use String::ShellQuote qw( shell_quote );
    
    my $prefix_lit = shell_quote( $prefix );
    
    my $conf_options = "--prefix=$prefix_lit --enable-shared=no ...";
    my $txt = capture( "../configure $conf_options" );
    

    The former doesn't use a shell, while the latter does.