I\'m a beginner in Perl. I have a Windows batch script which contains multiple NMake commands. An existing issue with this batch script is that even if the NMake command fai
You have:
use IPC::System::Simple qw(system);
my $exit_status = system ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1");
Given that you don't seem to care about the actual output, you can try
my $exit_status = systemx(nmake =>
qw(/f _nt.mak pack_cd),
"SUB_PLAT=$PLAT",
"DR=$plat",
);
To make sure you bypass cmd.exe
and see if you get something useful.
For reference, the exit codes from nmake are listed here.
Running the following program:
use strict; use warnings;
use IPC::System::Simple qw(systemx);
use Try::Tiny;
my $status = 0;
try { systemx nmake => qw(/f bogus) }
catch { ($status) = ( /exit value ([0-9])/ ) };
print "Failed to execute nmake. Exit status = $status\n";
produces:
NMAKE : fatal error U1052: file 'bogus' not found Stop. Failed to execute nmake. Exit status = 2
The following version:
use strict; use warnings;
my $status = system nmake => qw(/f bogus);
if ($status) {
if ($? == -1) {
print "failed to execute: $!\n";
}
elsif ($? & 127) {
printf "child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
}
else {
printf "child exited with value %d\n", $? >> 8;
}
}
produces:
NMAKE : fatal error U1052: file 'bogus' not found Stop. child exited with value 2
In fact, even when I use
my $status = system "nmake /f bogus";
I get the same correct and expected output.
Ditto when I use
my $status = system "nmake /f bogus 2>&1";
These observations lead me to the following questions:
Which version of nmake are you using?
Is the /I
option in effect? Even though you don't set it from the command line, note the following:
/I
Ignores exit codes from all commands. To set or clear/I
for part of a makefile, use!CMDSWITCHES
. To ignore exit codes for part of a makefile, use a dash (–
) command modifier or.IGNORE
. Overrides/K
if both are specified.
So, I put together the following files:
C:\temp> cat test.mak test.target: bogus.pl; perl bogus.pl
C:\temp> cat bogus.pl exit 1;
And, ran:
use strict; use warnings;
my $status = system "nmake /f test.mak 2>&1";
if ($status) {
if ($? == -1) {
print "failed to execute: $!\n";
}
elsif ($? & 127) {
printf "child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
}
else {
printf "child exited with value %d\n", $? >> 8;
}
}
which gave me the output:
perl bogus.pl NMAKE : fatal error U1077: 'c:\opt\perl\bin\perl.EXE' : return code '0x1' Stop. child exited with value 2
where the last line shows that the exit status of nmake was correctly propagated.
You have some other problem.
In fact, the OP later pointed out in comments that:
The actual command that i am trying to run is:
system ("nmake /f _nt.mak pack_cd SUB_PLAT=$PLAT DR=$plat 2>&1 | C:\\tee2 $TEMP_DIR\\modules-nt_${platlogfile}");
Given tee
s involvement in the pipeline, it is not surprising that nmake
s exit code gets lost. tee
is successfully able to process output from nmake
, so it returns success, and that's the exit code your script sees.
Therefore, the solution is to capture the output of nmake
yourself, either using qx
(coupled with the appropriate level of error checking), or using capture
from IPC::System::Simple
. Then, you can decide to whether you want to print that output, save to a file, put it in an email etc …