Hi there, Here's a patch for Build.PL that should avoid most of the pkg_config troubles on platforms that don't have it. I still don't quite know what to do on Windows when installing from outside of the Parrot tree.
-- c
=== MANIFEST ================================================================== --- MANIFEST (revision 20293) +++ MANIFEST (local) @@ -209,6 +209,7 @@ config/gen/makefiles/dynpmc.in [] config/gen/makefiles/dynpmc_pl.in [] config/gen/makefiles/editor.in [] +config/gen/makefiles/ext.in [] config/gen/makefiles/languages.in [] config/gen/makefiles/parrot.pc.in [] config/gen/makefiles/past.in [] @@ -648,6 +649,15 @@ examples/tge/branch/lib/Branch.pir [main]doc examples/tge/branch/lib/Leaf.pir [main]doc examples/tge/branch/transform.pir [main]doc +ext/Parrot-Embed/t/embed.t [devel] +ext/Parrot-Embed/t/greet.pir [devel] +ext/Parrot-Embed/lib/Parrot/Embed.xs [devel] +ext/Parrot-Embed/lib/Parrot/Embed.pm [devel] +ext/Parrot-Embed/Changes [devel] +ext/Parrot-Embed/MANIFEST [devel] +ext/Parrot-Embed/typemap [devel] +ext/Parrot-Embed/Build.PL [devel] +ext/Parrot-Embed/README [devel] include/parrot/atomic.h [main]include include/parrot/atomic/fallback.h [main]include include/parrot/atomic/gcc_pcc.h [main]include === config/gen/makefiles/root.in ================================================================== --- config/gen/makefiles/root.in (revision 20293) +++ config/gen/makefiles/root.in (local) @@ -186,6 +186,7 @@ compilers/tge/Makefile \ compilers/bcg/Makefile \ editor/Makefile \ + ext/Makefile \ languages/Makefile \ languages/amber/Makefile \ languages/APL/Makefile \ === config/gen/makefiles/ext.in ================================================================== --- config/gen/makefiles/ext.in (revision 20293) +++ config/gen/makefiles/ext.in (local) @@ -0,0 +1,64 @@ +# $Id: /parrotcode/offline/config/gen/makefiles/languages.in 19764 2006-08-03T18:17:04.907999Z chromatic $ + +# setup of commands [EMAIL PROTECTED]@ +PERL = @perl@ +MAKE = @make_c@ +RM_F = @rm_f@ + +# add new languages here +# remove obsolete languages here +EXT = \ + Parrot-Embed + +# the default target +all: $(EXT) + +# hard-code these for now +test: Parrot-Embed + - cd Parrot-Embed && $(PERL) Build test + +clean: Parrot-Embed + - cd Parrot-Embed && $(PERL) Build clean + +# This is a listing of all targets, that are meant to be called by users +help: + @echo "" + @echo "Following targets are available for the user:" + @echo "" + @echo " all: Make a lot of language implementations." + @echo " This is the default." + @echo " test: Unified test suite for a lot of languages." + @echo "" + @echo " clean: Clean up a lot of languages." + @echo "" + @echo " help: Print this help message." + @echo "" + @echo " smoke: Run the test suite and send smoke.html to " + @echo " http://smoke.parrotcode.org/" + @echo "" + @echo " smoke-clean: clean up smoke.html" + @echo "" + @echo "" + @echo "Following languages are available:" + @echo " $(LANGUAGES)" + @echo "A particular language <lang> can be built, tested and cleand up" + @echo " make <lang>" + @echo " make <lang>.test" + @echo " make <lang>.clean" + @echo "For the status of individual languages see LANGUAGES.STATUS.pod" + @echo "" + +clean: \ + Parrot-Embed.clean + +# +# Extension specific targets +# + +# The *.dummy targets are a replacement for the target .PHONY in 'GNU make' + +Parrot-Embed : Parrot-Embed.dummy + +Parrot-Embed.dummy: + - cd ext/Parrot-Embed && $(PERL) Build.PL && $(PERL) Build === config/gen/makefiles.pm ================================================================== --- config/gen/makefiles.pm (revision 20293) +++ config/gen/makefiles.pm (local) @@ -117,6 +117,11 @@ replace_slashes => 1 ); genfile( + 'config/gen/makefiles/ext.in' => 'ext/Makefile', + commentType => '#', + replace_slashes => 1 + ); + genfile( 'config/gen/makefiles/parrot.pc.in' => 'parrot.pc' ); === ext/Parrot-Embed/Build.PL ================================================================== --- ext/Parrot-Embed/Build.PL (revision 20293) +++ ext/Parrot-Embed/Build.PL (local) @@ -0,0 +1,128 @@ +use strict; +use warnings; + +use Cwd; +use File::Spec; +use Module::Build; + +my $in_parrot_tree = in_parrot_tree(); +my ($cflags, $lflags) = get_compiler_flags( $in_parrot_tree ); +my $parrot = get_parrot_path( $in_parrot_tree ); + +my $class = Module::Build->subclass( + code => <<"END_HERE", + use Cwd; + + sub ACTION_build + { + my \$self = shift; + my \$old_dir = cwd(); + chdir 't'; + + print "\$old_dir\n"; + system(qw( $parrot -o greet.pbc greet.pir ) ) == 0 + or die "Cannot compile PBC for test: \$?"; + + chdir \$old_dir; + \$self->SUPER::ACTION_build( [EMAIL PROTECTED] ); + } +END_HERE +); + +my $builder = $class->new( + module_name => 'Parrot::Embed', + license => 'perl', + dist_author => 'chromatic <[EMAIL PROTECTED]>', + dist_version_from => 'lib/Parrot/Embed.pm', + build_requires => { + 'Test::More' => 0, + }, + add_to_cleanup => [ 'Parrot-Embed-*' ], + extra_compiler_flags => $cflags, + extra_linker_flags => $lflags, +); + +$builder->create_build_script(); + +sub in_parrot_tree +{ + my $cwd = cwd(); + return $cwd =~ /\bparrot\b.ext/; +} + +sub get_compiler_flags +{ + my $in_parrot_tree = shift; + return get_flags_from_parrot_src() if $in_parrot_tree; + return get_flags_from_pkg_config() if $ENV{PKG_CONFIG_PATH}; +} + +sub get_flags_from_pkg_config +{ + require ExtUtils::PkgConfig; + my %pkg_info = ExtUtils::PkgConfig->find( 'parrot' ); + return @pkg_info{qw( cflags libs )}; +} + +sub get_flags_from_parrot_src +{ + my $updir = File::Spec->updir(); + my $file = File::Spec->catfile( $updir, $updir, 'parrot.pc' ); + open( my $fh, '<', $file ) or die "Cannot read $file: $!\n"; + + my %vars; + while (<$fh>) + { + chomp; + last unless /\S/; + my ($var, $value) = split(/=/, $_); + $vars{$var} = $value; + } + + while (<$fh>) + { + chomp; + last unless /\S/; + my ($var, $value) = split(/: /, $_); + $value =~ s/{(\w+)}/$vars{$1}/g; + $vars{$var} = $value; + } + + return @vars{qw( Cflags Libs )}; +} + +sub get_parrot_path +{ + my $in_parrot_tree = shift; + return get_parrot_path_internal() if $in_parrot_tree; + return get_parrot_path_external(); +} + +sub get_parrot_path_internal +{ + my $updir = File::Spec->updir(); + my $path = File::Spec->catfile(($updir) x 3, get_parrot_executable_name()); + + die "parrot apparently not built!\n" unless -e $path; + return $path; +} + +sub get_parrot_path_external +{ + my $parrot = get_parrot_executable_name(); + + for my $path ( split( /:/, $ENV{PATH} ) ) + { + my $file = File::Spec->catfile( $path, $parrot ); + next unless -e $file; + return $file; + } + + die "parrot apparently not installed in \$PATH\n"; +} + +sub get_parrot_executable_name +{ + return 'parrot' unless $^O =~ /Win32/; + return 'parrot.exe'; +} === ext/Parrot-Embed/Changes ================================================================== --- ext/Parrot-Embed/Changes (revision 20293) +++ ext/Parrot-Embed/Changes (local) @@ -0,0 +1,5 @@ +Revision history for Parrot-Embed + +0.01 Date/time + First version, released on an unsuspecting world. + === ext/Parrot-Embed/MANIFEST ================================================================== --- ext/Parrot-Embed/MANIFEST (revision 20293) +++ ext/Parrot-Embed/MANIFEST (local) @@ -0,0 +1,10 @@ +Build.PL +Changes +MANIFEST +META.yml # Will be created by "make dist" +README +lib/Parrot/Embed.pm +lib/Parrot/Embed.xs +t/embed.t +t/greet.pir +typemap === ext/Parrot-Embed/README ================================================================== --- ext/Parrot-Embed/README (revision 20293) +++ ext/Parrot-Embed/README (local) @@ -0,0 +1,22 @@ +Parrot::Embed +------------- + +This is the first version of an embedding interface to use Parrot from Perl 5. + +Be afraid. + +INSTALLATION + +To install this module, run the following commands: + + perl Build.PL + perl ./Build + perl ./Build test + perl ./Build install + +COPYRIGHT AND LICENCE + +Copyright (C) 2006 The Perl Foundation/chromatic + +This program is free software; you can redistribute it and/or modify it +under the same terms as Parrot itself. === ext/Parrot-Embed/lib/Parrot/Embed.pm ================================================================== --- ext/Parrot-Embed/lib/Parrot/Embed.pm (revision 20293) +++ ext/Parrot-Embed/lib/Parrot/Embed.pm (local) @@ -0,0 +1,44 @@ +package Parrot::Embed; + +use strict; +use warnings; + +our $VERSION = '0.01'; + +use base 'DynaLoader'; + +Parrot::Embed->bootstrap( $VERSION ); + +1; + +__END__ + +=head1 NAME + +Parrot::Embed - use Parrot from Perl 5 + +=head1 VERSION + +Version 0.01 + +=head1 SYNOPSIS + +This module embeds libparrot in Perl 5 programs. You can load Parrot bytecode, +compile your own code, and call Parrot subroutines and send and receive values +to them. + +=head1 AUTHOR + +chromatic, C<< <chromatic at wgz.org> >> + +=head1 BUGS + +Please report any bugs or feature requests to the Parrot Porters mailing list. +Someday there may be a CPAN version of this code. Who knows? + +=head1 COPYRIGHT & LICENSE + +Copyright (c) 2006 The Perl Foundation / chromatic, all rights reserved. + +This program is free software; you can redistribute it and/or modify it +under the same terms as Parrot itself. === ext/Parrot-Embed/lib/Parrot/Embed.xs ================================================================== --- ext/Parrot-Embed/lib/Parrot/Embed.xs (revision 20293) +++ ext/Parrot-Embed/lib/Parrot/Embed.xs (local) @@ -0,0 +1,133 @@ +#define PERL_NO_GET_CONTEXT +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include "parrot/parrot.h" +#include "parrot/embed.h" +#include "parrot/extend.h" + +MODULE = Parrot::Embed PACKAGE = Parrot::Embed + +Parrot_Interp +create_interpreter( ... ) +INIT: + Parrot_Interp parent; + Parrot_Interp interp; + Parrot_PackFile pf; +CODE: + if (items == 0) + { + parent = 0; + } + else if ( items == 1 ) + { + parent = INT2PTR( Parrot_Interp, SvIV( ST(0) ) ); + } + else + { + Perl_croak( aTHX_ + "Usage: Parrot::Embed::create_interpreter( [ parent ] )" ); + } + interp = Parrot_new( parent ); + pf = PackFile_new( interp, 0 ); + Parrot_loadbc( interp, pf ); + RETVAL = interp; +OUTPUT: + RETVAL + +Parrot_STRING +create_string( interp, string ) + Parrot_Interp interp + SV * string +INIT: + int length; +CODE: + length = SvLEN( string ); + RETVAL = const_string( interp, SvPVX( string ) ); +OUTPUT: + RETVAL + +Parrot_PackFile +read_bytecode( interp, filename ) + Parrot_Interp interp + char * filename +CODE: + RETVAL = Parrot_readbc( interp, filename ); +OUTPUT: + RETVAL + +void +load_bytecode( interp, packfile ) + Parrot_Interp interp + Parrot_PackFile packfile +CODE: + Parrot_loadbc( interp, packfile ); + +Parrot_PMC +find_global( interp, ... ) + Parrot_Interp interp +INIT: + SV * namespace; + Parrot_STRING p_namespace; + Parrot_STRING p_global; +CODE: + if ( items < 2 || items > 3 ) + { + Perl_croak( aTHX_ + "Usage: Parrot::Embed::find_global( interp, name, [ namespace ] )"); + } + + p_global = const_string( interp, SvPVX( ST(1) ) ); + + if ( items == 3 ) + namespace = ST(2); + else + namespace = &PL_sv_undef; + + if (namespace != &PL_sv_undef ) + { + p_namespace = const_string( interp, SvPVX( namespace ) ); + RETVAL = Parrot_find_global_s( interp, p_namespace, p_global ); + } + else + { + RETVAL = Parrot_find_global_cur( interp, p_global ); + } +OUTPUT: + RETVAL + +Parrot_PMC +call_sub( interp, sub, signature, argument ) + Parrot_Interp interp + Parrot_PMC sub + const char * signature + const char * argument +INIT: + Parrot_STRING arg_string; +CODE: + arg_string = const_string( interp, argument ); + RETVAL = Parrot_call_sub( interp, sub, signature, arg_string ); +OUTPUT: + RETVAL + +char * +get_string_from_pmc( interp, pmc ) + Parrot_Interp interp + Parrot_PMC pmc +CODE: + RETVAL = Parrot_PMC_get_cstring( interp, pmc ); +OUTPUT: + RETVAL + +Parrot_PMC +compile_string( interp, code ) + Parrot_Interp interp + char * code +INIT: + STRING *code_type; + STRING *error; +CODE: + code_type = const_string( interp, "PIR" ); + RETVAL = Parrot_compile_string( interp, code_type, code, &error ); +OUTPUT: + RETVAL === ext/Parrot-Embed/t/embed.t ================================================================== --- ext/Parrot-Embed/t/embed.t (revision 20293) +++ ext/Parrot-Embed/t/embed.t (local) @@ -0,0 +1,105 @@ +#!perl + +use strict; +use warnings; + +use Test::More tests => 27; +use File::Spec; + +my $hello_pbc = File::Spec->catfile( 't', 'greet.pbc' ); + +my $module = 'Parrot::Embed'; +use_ok( $module ) or exit; + +diag( "Testing Parrot::Embed $Parrot::Embed::VERSION, Perl $], $^X" ); + +can_ok( $module, 'create_interpreter' ); +my $interp = Parrot::Embed::create_interpreter( 0 ); +ok( $interp, 'create_interpreter() should return a valid interpreter' ); + +my $i2 = Parrot::Embed::create_interpreter( $interp ); +isnt( $interp, $i2, '... but not always the same one' ); + +eval { Parrot::Embed::create_interpreter( 0, 1, 2 ) }; +like( $@, qr/Usage: .+create_interpreter/, + '... and should croak when given invalid arguments' ); + +can_ok( $module, 'read_bytecode' ); +my $bc = Parrot::Embed::read_bytecode( $interp, $hello_pbc ); +ok( $bc, 'read_bytecode() should work on valid file' ); + +TODO: +{ + local $TODO = 'Cannot catch Parrot exceptions yet'; + + # XXX - can you not see that I am serious? + close STDERR; + + eval { Parrot::Embed::read_bytecode( $interp, $0 ) }; + like( $@, qr/Can't unpack packfile/, '... but not on non-PBC file' ); + + eval { Parrot::Embed::read_bytecode( $interp, 'not_a_file' ) }; + like( $@, qr/Can't unpack packfile/, '... or a non-existent file' ); +} + +can_ok( $module, 'load_bytecode' ); +eval { Parrot::Embed::load_bytecode( $interp, $bc ) }; +is( $@, '', 'load_bytecode() should work on read bytecode' ); + +TODO: +{ + local $TODO = 'Cannot catch Parrot exceptions yet'; + + eval { Parrot::Embed::load_bytecode( $interp, undef ) }; + like( $@, qr/Invalid packfile/, '... but not on non-packfile' ); + +} + +can_ok( $module, 'find_global' ); +my $global_greet = Parrot::Embed::find_global( $interp, 'greet' ); +ok( $global_greet, + 'find_global() should return non-namespaced global, if found' ); + +ok( ! Parrot::Embed::find_global( $interp, 'goat' ), + '... or nothing, if there is no non-namespaced global of that name' ); + +my $else_greet = Parrot::Embed::find_global( $interp, 'greet', 'Elsewhere' ); +ok( $else_greet, '... or a namespaced global, if it exists in the namespace' ); +isnt( $global_greet, $else_greet, '... and definitely the namespaced version' ); + +ok( ! Parrot::Embed::find_global( $interp, 'goat', 'Elsewhere' ), + '... but again, not if there is no global of that name there' ); + +can_ok( $module, 'call_sub' ); +my $pmc = Parrot::Embed::call_sub( $interp, $global_greet, 'PS', 'Bob' ); +ok( $pmc, 'call_sub() should return a PMC, given that signature' ); + +can_ok( $module, 'get_string_from_pmc' ); +is( Parrot::Embed::get_string_from_pmc( $interp, $pmc ), 'Hello, Bob!', + '... containing a string returned as a PMC' ); + +$pmc = Parrot::Embed::call_sub( $interp, $else_greet, 'P', '' ); +is( Parrot::Embed::get_string_from_pmc( $interp, $pmc ), 'Hiya!', + '... calling the passed-in subroutine' ); + +can_ok( $module, 'compile_string' ); +my $eval = Parrot::Embed::compile_string( $interp, <<END_PIR ); +.sub foo + .param pmc in_string + + .local string string_s + string_s = in_string + string_s .= ' FOO ' + + .return( string_s ) +.end +END_PIR +ok( $eval, 'compile_string() should compile PIR code and return a PMC' ); + +ok( ! Parrot::Embed::compile_string( $i2, 'blah' ), + '... but only for valid PIR' ); + +my $foo = Parrot::Embed::find_global( $interp, 'foo' ); +$pmc = Parrot::Embed::call_sub( $interp, $foo, 'PS', 'BAR' ); +is( Parrot::Embed::get_string_from_pmc( $interp, $pmc ), 'BAR FOO ', + '... and compiled sub should work just like any other Sub pmc' ); Property changes on: ext/Parrot-Embed/t/embed.t ___________________________________________________________________ Name: svn:mime-type +text/plain === ext/Parrot-Embed/t/greet.pir ================================================================== --- ext/Parrot-Embed/t/greet.pir (revision 20293) +++ ext/Parrot-Embed/t/greet.pir (local) @@ -0,0 +1,20 @@ +.sub greet + .param pmc name + + .local string name_str + name_str = name + + .local pmc greeting + greeting = new .String + greeting = 'Hello, ' + greeting .= name_str + greeting .= '!' + + .return( greeting ) +.end + +.namespace [ 'Elsewhere' ] + +.sub greet + .return( 'Hiya!' ) +.end === ext/Parrot-Embed/typemap ================================================================== --- ext/Parrot-Embed/typemap (revision 20293) +++ ext/Parrot-Embed/typemap (local) @@ -0,0 +1,5 @@ +TYPEMAP +Parrot_Interp T_PTR +Parrot_PackFile T_PTR +Parrot_STRING T_PTR +Parrot_PMC T_PTR