Both qx and system set $! when unable to launch the child.
Both qx and system set $? to the child's error code.
An error did not necessarily occur when qx return false, only when it returns undef.
$! is not necessarily set when qx return false, only when it returns undef.
Here is how one actually gets meaningful errors from them:
my $output = qx(date);
die("Unable to launch external process: $!\n")
if not defined $output;
die("The external process did not run successfully (error code $?)\n")
if $?;
my $rv = system(date);
die("Unable to launch external process: $!\n")
if $rv == -1;
die("The external process did not run successfully (error code $?)\n")
if $?;