summaryrefslogtreecommitdiff
path: root/cpan/ExtUtils-MakeMaker/t/04-xs-rpath-darwin.t
diff options
context:
space:
mode:
Diffstat (limited to 'cpan/ExtUtils-MakeMaker/t/04-xs-rpath-darwin.t')
-rw-r--r--cpan/ExtUtils-MakeMaker/t/04-xs-rpath-darwin.t269
1 files changed, 269 insertions, 0 deletions
diff --git a/cpan/ExtUtils-MakeMaker/t/04-xs-rpath-darwin.t b/cpan/ExtUtils-MakeMaker/t/04-xs-rpath-darwin.t
new file mode 100644
index 0000000000..1848883875
--- /dev/null
+++ b/cpan/ExtUtils-MakeMaker/t/04-xs-rpath-darwin.t
@@ -0,0 +1,269 @@
+#!/usr/bin/perl -w
+
+# This test file tests a special case for the generation of XS modules on OS darwin.
+# More specifically, it tests if we are able to compile an XS module which refers
+# to another shared library in a non-standard location such that we can
+# load the XS module from a perl script without having to set the
+# DYLD_LIBRARY_PATH environment variable. See PR #403 and issue #402.
+#
+package Main;
+use strict;
+use warnings;
+use Config;
+BEGIN {
+ chdir 't' or die "chdir(t): $!\n";
+ unshift @INC, 'lib/';
+ use Test::More;
+ if( $^O ne "darwin" ) {
+ plan skip_all => 'Not darwin platform';
+ }
+ else {
+ plan skip_all => 'Dynaloading not enabled'
+ if !$Config{usedl} or $Config{usedl} ne 'define';
+ plan tests => 1;
+ }
+}
+use Cwd;
+use ExtUtils::MakeMaker;
+use File::Temp qw[tempdir];
+use File::Path; # exports: mkpath and rmtree
+use File::Spec;
+
+{
+ $| = 1;
+ # We need this when re-running "perl Makefile.PL"
+ my $ext_utils_lib_dir = File::Spec->rel2abs('../lib');
+ # This tmpdir will be removed when the program exits
+ my $tmpdir = tempdir( DIR => '.', CLEANUP => 1 );
+ my $cwd = getcwd;
+ # File::Temp will not clean up the temp directory if the current directory
+ # is a sub directory of the temp dir. This can happen in the case of an
+ # error (a call to die). which disrupts the normal program flow that would
+ # have restored the cwd before exit. To solve this issue
+ # we add the below END block (which will be called before the File::Temp
+ # cleanup END block call since END blocks are called in LIFO order)
+ END { chdir $cwd }
+ _chdir($tmpdir);
+ my $self = Main->new(
+ mylib_dir => "mylib",
+ mylib_c_fn => "mylib.c",
+ mylib_h_fn => "mylib.h",
+ mylib_lib_name => "mylib",
+ module_name => "My::Module",
+ test_script_name => 'p.pl',
+ ext_utils_lib_dir => $ext_utils_lib_dir,
+ );
+ $self->compile_library();
+ $self->write_makefile_pl();
+ $self->write_module_file();
+ $self->write_xs_file();
+ $self->run_make();
+ $self->write_test_script();
+ $self->run_test_script();
+ _chdir($cwd);
+}
+
+sub _chdir { chdir $_[0] or die "Cannot change directory to $_[0] : $!" }
+
+sub _mkpath { mkpath($_[0]) or die "Could not create directory $_[0] : $!" };
+
+sub run_test_script {
+ my ($self) = @_;
+
+ my @cmd = ($^X, '-Mblib', $self->{test_script_name});
+ my $out = _capture_stdout(\@cmd);
+ like( $out, qr{\Qcalling foo()\E\s+\QHello from foo()\E});
+}
+
+sub write_xs_file {
+ my ($self) = @_;
+
+ my $str = <<'END';
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#include "mylib.h"
+
+MODULE = <<module_name_colon>> PACKAGE = <<module_name_colon>>
+PROTOTYPES: DISABLE
+
+void
+mylib_func()
+ CODE:
+ printf("calling foo()\n");
+ foo();
+END
+ $str =~ s/\Q<<module_name_colon>>\E/$self->{module_name}/g;
+ my @module_name = split /::/, $self->{module_name};
+ my $xs_name = pop @module_name;
+ $xs_name .= '.xs';
+ _write_file( $xs_name, $str );
+}
+
+sub write_test_script {
+ my ($self) = @_;
+
+ my $str = <<'END';
+use strict;
+use warnings;
+use ExtUtils::testlib;
+use <<module_name_colon>>;
+
+<<module_name_colon>>::mylib_func();
+END
+ $str =~ s/\Q<<module_name_colon>>\E/$self->{module_name}/g;
+ _write_file( $self->{test_script_name}, $str );
+}
+
+sub run_make {
+ my ($self) = @_;
+
+ my @cmd = ($^X, '-I'. $self->{ext_utils_lib_dir}, 'Makefile.PL');
+ _run_system_cmd(\@cmd);
+ _run_system_cmd(['make']);
+}
+
+sub write_module_file {
+ my ( $self ) = @_;
+
+ my @dirs = split /::/, $self->{module_name};
+ my $basename = pop @dirs;
+ my $dir = File::Spec->catfile('lib', @dirs);
+ _mkpath( $dir );
+ my $fn = File::Spec->catfile($dir, $basename . '.pm');
+ my $str = <<'END';
+package <<module_name_colon>>;
+require Exporter;
+require DynaLoader;
+$VERSION = 1.01;
+@ISA = qw(Exporter DynaLoader);
+@EXPORT = qw();
+bootstrap <<module_name_colon>> $VERSION;
+1;
+
+=head1 NAME
+
+<<module_name_colon>> - Short description of <<module_name_colon>>
+END
+ $str =~ s/\Q<<module_name_colon>>\E/$self->{module_name}/g;
+ _write_file( $fn, $str );
+}
+
+sub write_makefile_pl {
+ my ( $self ) = @_;
+
+ my $str = <<'END';
+use strict;
+use warnings;
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+ NAME => '<<module_name_colon>>',
+ VERSION_FROM => 'lib/<<module_name_slash>>.pm',
+ ABSTRACT_FROM => 'lib/<<module_name_slash>>.pm',
+ PERL => "$^X -w",
+ LIBS => ['-L./<<lib_dir>> -l<<lib_name>>'],
+ INC => '-I. -I./<<lib_dir>>',
+);
+END
+ my $mod_name1 = $self->{module_name};
+ my $mod_name2 = $self->{module_name};
+ $mod_name2 =~ s{::}{/}g;
+ $str =~ s/\Q<<module_name_colon>>\E/$mod_name1/g;
+ $str =~ s/\Q<<module_name_slash>>\E/$mod_name2/g;
+ $str =~ s/\Q<<lib_dir>>\E/$self->{mylib_dir}/g;
+ $str =~ s/\Q<<lib_name>>\E/$self->{mylib_lib_name}/g;
+ _write_file('Makefile.PL', $str);
+}
+
+sub compile_library {
+ my ($self) = @_;
+
+ _mkpath( $self->{mylib_dir} );
+ my $cwd = getcwd;
+ _chdir( $self->{mylib_dir} );
+ $self->write_mylib_h();
+ $self->write_mylib_c();
+ $self->compile_mylib();
+ _chdir( $cwd );
+}
+
+sub compile_mylib {
+ my ($self) = @_;
+
+ my $cc = $Config{cc};
+ my $libext = $Config{so};
+
+ my $libname = 'lib' . $self->{mylib_lib_name} . '.' . $libext;
+ my @cmd = ($cc, '-I.', '-dynamiclib', '-install_name',
+ '@rpath/' . $libname,
+ 'mylib.c', '-o', $libname);
+ _run_system_cmd(\@cmd);
+}
+
+sub _capture_stdout {
+ my ($cmd) = @_;
+
+ my $out = `@$cmd`;
+ _check_sys_cmd_error( $cmd, $? ) if $? != 0;
+ return $out;
+}
+
+sub _stringify_cmd { '"' . (join " ", @{$_[0]}) . '"' }
+
+sub _check_sys_cmd_error {
+ my ( $cmd, $error ) = @_;
+ my $cmd_str = _stringify_cmd($cmd);
+ if ( $error == -1 ) {
+ # A return value of -1 from system() indicates a failure to start the program
+ die "Could not run $cmd_str: $!";
+ }
+ elsif ($error & 127) {
+ die sprintf "Command $cmd_str : killed by signal %d, %s coredump\n",
+ ($error & 127), ($error & 128) ? 'with' : 'without';
+ }
+ elsif ($error != 0) {
+ die sprintf "$cmd_str exited with error code %d\n", $error >> 8;
+ }
+}
+
+sub _run_system_cmd {
+ my ($cmd) = @_;
+
+ my $res = system @$cmd;
+ _check_sys_cmd_error( $cmd, $res ) if $res != 0;
+
+}
+
+sub write_mylib_c {
+ my ($self) = @_;
+ my $str = <<'END';
+#include <stdio.h>
+#include <stdlib.h>
+#include "mylib.h"
+
+void foo() {
+ printf( "Hello from foo()\n");
+}
+END
+ _write_file($self->{mylib_c_fn}, $str);
+}
+
+sub write_mylib_h {
+ my ($self) = @_;
+ my $str = 'void foo();';
+ _write_file($self->{mylib_h_fn}, $str);
+}
+
+sub _write_file {
+ my ($file, $text) = @_;
+ my $utf8 = ("$]" < 5.008 or !$Config{useperlio}) ? "" : ":utf8";
+ open(FILE, ">$utf8", $file) || die "Can't create $file: $!";
+ print FILE $text;
+ close FILE;
+}
+
+sub new {
+ my ($class, %args) = @_;
+ return bless \%args, $class;
+}