Skip to content

EU::ParseXS: ExtUtils/typemap overrides typemap provided by user #19294

Open
@sisyphus

Description

@sisyphus

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions