Description
Module:
ExtUtils::ParseXS
Description
The assertion made in the title is true only when the typemap provided by the user is NOT found by default, but relies on being found via the TYPEMAPS
setting in WriteMakefile()
.
If the typemap provided by the user is found by default, then it overrides ExtUtils/typemap
, as expected.
For the purposes of experimentation, the safe and reliable method of ensuring that the typemap is NOT found by default, is to name it anything other than "typemap".
It can then be placed anywhere you like, and the only way to have it recognized as a typemap is to use the TYPEMAPS
option I just mentioned above.
If that user provided typemap (let's call it "my_typemap") is being provided to override a setting specified in ExtUtils/typemap, then you'll be sorely disappointed and left scratching your head as to why that does not happen.
You'll examine the compilation output and see that, as expected, there's a -typemap
switch specifying the ExtUtils/typemap
, followed a by a second -typemap
switch specifying "my_typemap" - which suggests that "my_typemap" will override any conflicting setting in ExtUtils/typemap
, as specified in the documentation..
What you don't see is that ExtUtils::ParseXS::Utilities::process_typemaps() then secretly appends the list of all defaults to the list of typemap files (which includes "my_typemap") that were already found.
As that appendage includes ExtUtils/typemap
, the rules of precedence determine that the settings specified in ExtUtils/typemap
then override the settings specified in "my_typemap".
My suggested patch to restore DWIMmery is fairly simple:
--- Utilities.pm_orig 2021-12-21 16:02:22 +1100
+++ Utilities.pm 2021-12-22 14:58:53 +1100
@@ -272,7 +272,9 @@
die "Can't find $typemap in $pwd\n" unless -r $typemap;
}
- push @tm, standard_typemap_locations( \@INC );
+ my @s = standard_typemap_locations( \@INC );
+ shift @s if $s[0] eq $tm[0];
+ push @tm, @s;
require ExtUtils::Typemaps;
my $typemap = ExtUtils::Typemaps->new;
AFAICS, in practice, the condition $s[0] eq $tm[0]
is always true, with both $s[0]
and $tm[0]
identifying ExtUtils/typemap
.
But test 1 of t/600-t-compat.t manages to construct a case where it's NOT true, and that test then fails if we unconditionally shift @s
Steps to Reproduce
As a demo, consider the following typemap (named "typemap") which seeks to alter the typing of unsigned char *
from T_PV
(as specified by ExtUtils/typemap
) to T_PTR
:
unsigned char * T_PTR
and, in the same directory as that typemap file, place the following Inline::C script:
use strict;
use warnings;
use Inline C => Config =>
# TYPEMAPS => ['./my_typemap'],
BUILD_NOISY => 1, # verbose build
FORCE_BUILD => 1, # re-build whenever the script is run
CLEAN_AFTER_BUILD => 0, # don't clean up the build directory
;
use Inline C =><<'EOC';
void foo(unsigned char *name) {
if(name) printf("Ignoring my typemap\n");
else printf("Honouring my typemap\n");
}
EOC
foo(undef);
Then cd to the directory that contains that script, run it, and after it has gone through the build process, it will output "Honouring my typemap".
In this instance, the typemap has (obviously) been found by default, so everything worked as intended.
Then rename "typemap" to "my_typemap" and comment in the TYPEMAPS line in the Inline::C script.
Run it again, and the final output changes to "Ignoring my typemap".
Apply the patch to Utilities.pm, run the script again, and see the output return to "Honouring my typemap".
AFAICT, this is not some quirk of the way that Inline::C generates the Makefile.PL and Makefile. Those files look fine to me, and totally in keeping with the Makefile.PL and Makefile that would be found in an XS module build.
Perl configuration
AFAIK, any perl build later than perl-5.8.8 (possibly earlier) will be subject to this.