Subject: | [PATCH] Work around Android's linker ignoring RTLD_GLOBAL |
Couple of important prefaces! Android support is brand new in core perl, so I'm still working out edge cases and just plain breakage in the port. Also, the patch below is only half of the solution for this -- the other part is this fix for MakeMaker:
https://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker/commit/9d540908bbc962715da337b308cab06983d51fd5
Which I haven't merged into MakeMaker proper yet, because I figure it ought to get a thumbs up from here as well.
The attached patch does two things; the first is relatively simple, it adds support for platforms with DynaLoader::mod2fname() defined.
mod2fname isn't exactly well documented, but basically, some platforms have some unusual requirements for their library names, so instead of, say, Utils.so for List::Utils, you might end up with PL_List__Utils.so; what mod2fname does is get you that library name.
There's currently two systems with mod2fname defined, VMS and Android. OS/2 uses it as well, but the OS/2 port isn't functional at the moment. Additionally, Windows may start using it in the near future.
(as an addendum: I have a suspicion that the module doesn't work quite right on VMS as-is, but I don't have a VMS box to confirm that)
The second thing that the patch does is actually solve a problem with Android's linker. I'll copypaste a bit of the patch to explain this bit:
+ # Android's linker ignores the RTLD_GLOBAL flag
+ # and loads everything as if under RTLD_LOCAL.
+ # What this means in practice is that modules need
+ # to explicitly link to their dependencies,
+ # because otherwise they won't be able to locate any
+ # functions they define.
+ # We use the -l:foo.so flag to indicate that the
+ # actual library name to look for is foo.so, not
+ # libfoo.so
As an example of what would happen, if i want my module to depend on mro, instead of passing LIBS something like
"-L/mnt/asec/home/built/lib/perl5/5.19.9/armv7l-linux-android-thread-multi/auto/mro -lPL_mro"
it ends up passing this:
"-L/mnt/asec/home/built/lib/perl5/5.19.9/armv7l-linux-android-thread-multi/auto/mro -l:PL_mro.so"
Which is then used during linking to get the correct dependency.
I've also made this part of the patch only kicks in for Android, since to my knowledge the module is working fine elsewhere. I'm also not sure if -l: is gcc/clang only, but currently it's only possible to compile perl for/on android with gcc and potentially clang, so it's not really a worry.
Subject: | 0001-Work-around-Android-s-linker-ignoring-RTLD_GLOBAL.patch |
From af51eed8807de61c5ecf1485b3a02053af63ab92 Mon Sep 17 00:00:00 2001
From: Brian Fraser <fraserbn@gmail.com>
Date: Mon, 3 Feb 2014 09:33:18 +0100
Subject: [PATCH] Work around Android's linker ignoring RTLD_GLOBAL
On Android, modules must explicitly link to their dependencies.
---
lib/ExtUtils/Depends.pm | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/lib/ExtUtils/Depends.pm b/lib/ExtUtils/Depends.pm
index 05ef316..5c4ca8c 100644
--- a/lib/ExtUtils/Depends.pm
+++ b/lib/ExtUtils/Depends.pm
@@ -7,12 +7,16 @@ package ExtUtils::Depends;
use strict;
use warnings;
use Carp;
+use Config;
use File::Find;
use File::Spec;
use Data::Dumper;
our $VERSION = '0.306';
+# For platforms with DynaLoader::mod2fname(), like VMS or Android
+require DynaLoader;
+
sub import {
my $class = shift;
return unless @_;
@@ -315,6 +319,7 @@ sub find_extra_libs {
my %mappers = (
MSWin32 => sub { $_[0] . '\.(?:lib|a)' },
cygwin => sub { $_[0] . '\.dll'},
+ android => sub { $_[0] . '\.' . $Config{dlext} },
);
my $mapper = $mappers{$^O};
return () unless defined $mapper;
@@ -322,6 +327,10 @@ sub find_extra_libs {
my @found_libs = ();
foreach my $name (keys %{ $self->{deps} }) {
(my $stem = $name) =~ s/^.*:://;
+ if ( defined &DynaLoader::mod2fname ) {
+ my @parts = split /::/, $name;
+ $stem = DynaLoader::mod2fname([@parts]);
+ }
my $lib = $mapper->($stem);
my $pattern = qr/$lib$/;
@@ -336,6 +345,18 @@ sub find_extra_libs {
if ($matching_file && -f $matching_file) {
push @found_libs, ('-L' . $matching_dir, '-l' . $stem);
+ # Android's linker ignores the RTLD_GLOBAL flag
+ # and loads everything as if under RTLD_LOCAL.
+ # What this means in practice is that modules need
+ # to explicitly link to their dependencies,
+ # because otherwise they won't be able to locate any
+ # functions they define.
+ # We use the -l:foo.so flag to indicate that the
+ # actual library name to look for is foo.so, not
+ # libfoo.so
+ if ( $^O eq 'android' ) {
+ $found_libs[-1] = "-l:$stem.$Config{dlext}";
+ }
next;
}
}
--
1.7.12.4 (Apple Git-37)