Last weekend tetragon and I had considerable discussion on #parrot about this problem. My diagnosis was that we should not be handling command-line options at all in 'hints' files; they should be handled in inter::progs.
The patch attached removes options handling from config/init/hints/darwin.pm, adds a prompt for the flag about which Coke was concerned in config/inter/progs.pm, and adds a file of tests for config/init/hints/darwin.pm. This was developed in the 'darwin_fix_hints' branch. If you use 'patch' to apply it to trunk, you'll probably get a bit of rejected material in MANIFEST, but that doesn't affect the soundness of the rest of the patch. I will apply this to trunk in a few days if there is no objection. Thank you very much. kid51
Index: MANIFEST =================================================================== --- MANIFEST (.../trunk) (revision 29926) +++ MANIFEST (.../branches/darwin_fix_hints) (revision 29963) @@ -1,7 +1,7 @@ # ex: set ro: # $Id$ # -# generated by tools/dev/mk_manifest_and_skip.pl Fri Aug 1 22:58:18 2008 UT +# generated by tools/dev/mk_manifest_and_skip.pl Sat Aug 2 01:30:14 2008 UT # # See tools/dev/install_files.pl for documentation on the # format of this file. @@ -3651,6 +3651,7 @@ t/steps/init_defaults-01.t [] t/steps/init_headers-01.t [] t/steps/init_hints-01.t [] +t/steps/init_hints-02.t [] t/steps/init_install-01.t [] t/steps/init_manifest-01.t [] t/steps/init_miniparrot-01.t [] Index: t/steps/init_hints-02.t =================================================================== --- t/steps/init_hints-02.t (.../trunk) (revision 0) +++ t/steps/init_hints-02.t (.../branches/darwin_fix_hints) (revision 29963) @@ -0,0 +1,278 @@ +#! perl +# Copyright (C) 2007, The Perl Foundation. +# $Id$ +# init_hints-02.t + +use strict; +use warnings; +use Data::Dumper;$Data::Dumper::Indent=1; +use Test::More; +plan( skip_all => 'Macports is Darwin only' ) unless $^O =~ /darwin/; +plan( tests => 32 ); +use Carp; +use Cwd; +use File::Path (); +use File::Spec::Functions qw/catfile/; +use File::Temp qw(tempdir); +use lib qw( lib t/configure/testlib ); +use_ok('config::init::defaults'); +use_ok('config::init::hints'); +use_ok('config::init::hints::darwin'); +use Parrot::Configure; +use Parrot::Configure::Options qw( process_options ); +use Parrot::Configure::Test qw( + test_step_thru_runstep + test_step_constructor_and_description +); +use IO::CaptureOutput qw | capture |; + +my $args = process_options( { + argv => [], + mode => q{configure}, +} ); + +my $conf = Parrot::Configure->new; +test_step_thru_runstep( $conf, q{init::defaults}, $args ); +my $pkg = q{init::hints}; +$conf->add_steps($pkg); +my $serialized = $conf->pcfreeze(); +$conf->options->set( %{$args} ); +my $step = test_step_constructor_and_description($conf); + +########### _precheck() ########## + +my ($flag, $stored, $verbose); +$flag = 'ccflags'; +{ + $stored = 'baz'; + $verbose = 1; + my ($stdout, $stderr); + capture ( + sub { init::hints::darwin::_precheck( + $flag, $stored, $verbose); }, + \$stdout, + \$stderr, + ); + like($stdout, qr/Checking $flag/s, + "Got expected verbose output for _precheck()"); + like($stdout, qr/Pre-check:\s+$stored/s, + "Got expected verbose output for _precheck()"); +} + +{ + $stored = q{}; + $verbose = 1; + my ($stdout, $stderr); + capture ( + sub { init::hints::darwin::_precheck( + $flag, $stored, $verbose); }, + \$stdout, + \$stderr, + ); + like($stdout, qr/Checking $flag/s, + "Got expected verbose output for _precheck()"); + like($stdout, qr/Pre-check:\s+\(nil\)/s, + "Got expected verbose output for _precheck()"); +} + +{ + $stored = 'baz'; + $verbose = 0; + my ($stdout, $stderr); + capture ( + sub { init::hints::darwin::_precheck( + $flag, $stored, $verbose); }, + \$stdout, + \$stderr, + ); + ok(! $stdout, "As expected, got no verbose output"); +} + +########### _strip_arch_flags_engine() ########## + +my ($arches, $flagsref); +$arches = $init::hints::darwin::defaults{architecture}; +$stored = q{foo -arch i386 -arch ppc bar -arch i386 baz}; +$flagsref = { + map { $_ => '' } + @{ $init::hints::darwin::defaults{problem_flags} } +}; +$flagsref = init::hints::darwin::_strip_arch_flags_engine( + $arches, $stored, $flagsref, 'ccflags' +); +$flagsref = init::hints::darwin::_strip_arch_flags_engine( + $arches, $stored, $flagsref, 'ldflags' +); +my $expected = qr/foo\sbar\sbaz/; +like($flagsref->{ccflags}, $expected, + "-arch flags stripped appropriately from ccflags" ); +like($flagsref->{ldflags}, $expected, + "-arch flags stripped appropriately from ldflags" ); + +########### _postcheck() ########## + +my $setting; +$flag = 'ccflags'; +{ + $setting = 'foo bar baz'; + $verbose = 1; + my ($stdout, $stderr); + capture ( + sub { init::hints::darwin::_postcheck($flagsref, $flag, $verbose); }, + \$stdout, + \$stderr, + ); + like( $stdout, + qr/Post-check:\s+$setting/s, + "Got expected verbose output for _postcheck()" + ); +} + +{ + $setting = 'foo bar baz'; + $verbose = 0; + my ($stdout, $stderr); + capture ( + sub { init::hints::darwin::_postcheck($flagsref, $flag, $verbose); }, + \$stdout, + \$stderr, + ); + ok( ! $stdout, "As expected, got no verbose output"); +} + +$flagsref->{ccflags} = q{}; +$flag = 'ccflags'; +{ + $verbose = 1; + my ($stdout, $stderr); + capture ( + sub { init::hints::darwin::_postcheck($flagsref, $flag, $verbose); }, + \$stdout, + \$stderr, + ); + like( $stdout, + qr/Post-check:\s+\(nil\)/s, + "Got expected verbose output for _postcheck()" + ); +} + +########### _strip_arch_flags() ########## + +my $ccflags_orig = $conf->data->get( 'ccflags' ); +my $ldflags_orig = $conf->data->get( 'ldflags' ); + +$conf->data->set( ccflags => + q{foo -arch i386 -arch ppc bar -arch i386 baz} ); +$conf->data->set( ldflags => + q{foo -arch i386 -arch ppc bar -arch i386 baz -arch ppc samba} ); +$verbose = 0; +$flagsref = init::hints::darwin::_strip_arch_flags($conf, $verbose); +like( $flagsref->{ccflags}, qr/foo\sbar\sbaz/, + "-arch flags stripped appropriately for ccflags" ); +like( $flagsref->{ldflags}, qr/foo\sbar\sbaz\ssamba/, + "-arch flags stripped appropriately for ldflags" ); + +$verbose = 1; +{ + my ($stdout, $stderr); + capture( sub { $flagsref = + init::hints::darwin::_strip_arch_flags($conf, $verbose); }, + \$stdout, + \$stderr, + ); + like( $flagsref->{ccflags}, qr/foo\sbar\sbaz/, + "-arch flags stripped appropriately for ccflags" ); + like( $flagsref->{ldflags}, qr/foo\sbar\sbaz\ssamba/, + "-arch flags stripped appropriately for ldflags" ); + like( $stdout, + qr/Stripping -arch flags due to Apple multi-architecture build problems/, + "Got expected verbose output from _strip_arch_flags()" ); +} + +$conf->data->set( ccflags => q{} ); +$conf->data->set( ldflags => + q{foo -arch i386 -arch ppc bar -arch i386 baz -arch ppc samba} ); +$verbose = 0; +$flagsref = init::hints::darwin::_strip_arch_flags($conf, $verbose); +like( $flagsref->{ccflags}, qr/^$/, + "Got appropriate value when ccflags was empty" ); +like( $flagsref->{ldflags}, qr/foo\sbar\sbaz\ssamba/, + "-arch flags stripped appropriately for ldflags" ); + +# re-set for next test +$conf->data->set( ccflags => $ccflags_orig ); +$conf->data->set( ldflags => $ldflags_orig ); + +########### _strip_ldl_as_needed() ########## + +my $libs_orig = $conf->data->get( 'libs' ); +my $uname_orig = $init::hints::darwin::defaults{uname}; +my $libs; + +$init::hints::darwin::defaults{uname} = '8.1.0'; +$libs = q{-ldlfoobar}; +$libs = init::hints::darwin::_strip_ldl_as_needed($libs); +is($libs, q{foobar}, "'-ldl' stripped as expected"); + +$init::hints::darwin::defaults{uname} = '6.1.0'; +$libs = q{-ldlfoobar}; +$libs = init::hints::darwin::_strip_ldl_as_needed($libs); +is($libs, q{-ldlfoobar}, "'-ldl' not stripped, as expected"); + +# re-set for next test +$conf->data->set( ccflags => $ccflags_orig ); +$init::hints::darwin::defaults{uname} = $uname_orig; + +########### _set_deployment_environment()########## +{ + local %ENV = %ENV; + delete $ENV{'MACOSX_DEPLOYMENT_TARGET'}; + my $sw_vers_orig = $init::hints::darwin::defaults{sw_vers}; + $init::hints::darwin::defaults{sw_vers} = qq{99.88.77\n}; + init::hints::darwin::_set_deployment_environment(); + is( $ENV{'MACOSX_DEPLOYMENT_TARGET'}, q{99.88}, + "Got expected environmental setting"); + + # re-set for next test + $init::hints::darwin::defaults{sw_vers} = $sw_vers_orig; + + local $ENV{'MACOSX_DEPLOYMENT_TARGET'} = q{66.55}; + init::hints::darwin::_set_deployment_environment(); + is( $ENV{'MACOSX_DEPLOYMENT_TARGET'}, q{66.55}, + "Got expected environmental setting"); +} + +pass("Completed all tests in $0"); + +################### DOCUMENTATION ################### + +=head1 NAME + +init_hints-02.t - test init::hints::darwin + +=head1 SYNOPSIS + + % prove t/steps/init_hints-02.t + +=head1 DESCRIPTION + +The files in this directory test functionality used by F<Configure.pl>. + +The tests in this file test init::hints::darwin. + +=head1 AUTHOR + +James E Keenan + +=head1 SEE ALSO + +config::init::hints, F<Configure.pl>. + +=cut + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: Property changes on: t/steps/init_hints-02.t ___________________________________________________________________ Name: svn:eol-style + native Name: svn:mime-type + text/plain Name: svn:keywords + Author Date Id Revision Index: config/inter/progs.pm =================================================================== --- config/inter/progs.pm (.../trunk) (revision 29926) +++ config/inter/progs.pm (.../branches/darwin_fix_hints) (revision 29963) @@ -98,7 +98,8 @@ $ld = prompt( "What program do you want to use to build shared libraries?", $ld ) if $ask; $conf->data->set( ld => $ld ); - $ccflags = $conf->data->get('ccflags'); + $ccflags = integrate( $conf->data->get('ccflags'), + $conf->options->get('ccflags') ); # Remove some perl5-isms. $ccflags =~ s/-D((PERL|HAVE)_\w+\s*|USE_PERLIO)//g; Index: config/init/hints/darwin.pm =================================================================== --- config/init/hints/darwin.pm (.../trunk) (revision 29926) +++ config/init/hints/darwin.pm (.../branches/darwin_fix_hints) (revision 29963) @@ -6,77 +6,44 @@ use strict; use warnings; +our %defaults = ( + uname => `uname -r`, + sw_vers => `sw_vers -productVersion`, + problem_flags => [ qw( ccflags ldflags ) ], + architectures => [ qw( i386 ppc64 ppc x86_64 ) ], +); + sub runstep { my ( $self, $conf ) = @_; my $verbose = $conf->options->get('verbose'); - # @flags is the list of options that have -arch flags added to them + # %flags is the list of options that have -arch flags added to them # implicitly through config/init/defaults.pm when using Apple's Perl # 5.8 build to run Configure.pl (it's a multi-architecture build). # This doesn't play nice with getting parrot to build on PPC systems # and causes all sorts of fun issues with lipo and friends. So, it's - # time to remove all -arch flags set in $conf->data that haven't been - # requested by command-line options and force a single, native - # architecture to being the default build. - my @flags = qw(ccflags linkflags ldflags ld_share_flags ld_load_flags); - my @arches = qw(i386 ppc64 ppc x86_64); + # time to remove all -arch flags set in $conf->data and force a single, + # native architecture to being the default build. - print "\nChecking for -arch flags not explicitly added:\n" if $verbose; - for my $flag (@flags) { - my $set_flags; - if ($flag =~ /^ld/) { - $set_flags = $conf->options->get('ldflags')||''; - } - else { - $set_flags = $conf->options->get($flag)||''; - } - my $stored = $conf->data->get($flag)||''; + my $flagsref = _strip_arch_flags($conf, $verbose); - print "Checking $flag...\n" if $verbose; - print "User-specified: ".($set_flags||'(nil)')."\n" if $verbose; - print "Pre-check: ".($stored||'(nil)')."\n" if $verbose; - - for my $arch (@arches) { - if (!$set_flags || $set_flags !~ /(?:^|\W)-arch\s+$arch(?:\W|$)/) { - $stored =~ s/-arch\s+$arch//g; - $conf->data->set($flag => $stored); - } - } - print "Post-check: ".($conf->data->get($flag)||'(nil)')."\n" if $verbose; - } # And now, after possibly losing a few undesired compiler and linker # flags, on to the main Darwin config. - my ( $ccflags, $ldflags, $libs ) = $conf->data->get(qw(ccflags ldflags libs)); + my $libs = _strip_ldl_as_needed( $conf->data->get( 'libs' ) ); - my $OSVers = `uname -r`; - chomp $OSVers; - { - local $^W; - $OSVers =~ /(\d+)/; - if ( $1 >= 7 ) { - $libs =~ s/-ldl//; - } - } + _set_deployment_environment(); - unless (exists $ENV{'MACOSX_DEPLOYMENT_TARGET'}) { - my $OSX_vers = `sw_vers -productVersion`; - chomp $OSX_vers; - # remove minor version - $OSX_vers =join '.', (split /[.]/, $OSX_vers)[0,1]; - $ENV{'MACOSX_DEPLOYMENT_TARGET'} = $OSX_vers; - } - my $lib_dir = $conf->data->get('build_dir') . "/blib/lib"; - $ldflags .= " -L$lib_dir"; - $ccflags .= " -pipe -fno-common -Wno-long-double "; + $flagsref->{ldflags} .= " -L$lib_dir"; + $flagsref->{ccflags} .= " -pipe -fno-common -Wno-long-double "; $conf->data->set( darwin => 1, osx_version => $ENV{'MACOSX_DEPLOYMENT_TARGET'}, - ccflags => $ccflags, - ldflags => $ldflags, + ccflags => $flagsref->{ccflags}, + ldflags => $flagsref->{ldflags}, ccwarn => "-Wno-shadow", libs => $libs, share_ext => '.dylib', @@ -89,8 +56,10 @@ memalign => 'some_memalign', has_dynamic_linking => 1, - # RT#43147 when built against a dynamic libparrot installable_parrot records - # the path to the blib version of the library + # RT 43147: When built against a dynamic libparrot, + # installable_parrot records the path to the blib version + # of the library. + parrot_is_shared => 1, libparrot_shared => 'libparrot.$(SOVERSION)$(SHARE_EXT)', libparrot_shared_alias => 'libparrot$(SHARE_EXT)', @@ -103,6 +72,76 @@ ); } +#################### INTERNAL SUBROUTINES #################### + +sub _precheck { + my ($flag, $stored, $verbose) = @_; + if ($verbose) { + print "Checking $flag...\n"; + print "Pre-check: " . ($stored || '(nil)') . "\n"; + } +} + +sub _strip_arch_flags_engine { + my ($arches, $stored, $flagsref, $flag) = @_; + for my $arch ( @{ $defaults{architectures} } ) { + $stored =~ s/-arch\s+$arch//g; + $stored =~ s/\s+/ /g; + $flagsref->{$flag} = $stored; + } + return $flagsref; +} + +sub _postcheck { + my ($flagsref, $flag, $verbose) = @_; + if ($verbose) { + print "Post-check: ", ( $flagsref->{$flag} or '(nil)' ), "\n"; + } +} + +sub _strip_arch_flags { + my ($conf, $verbose) = @_; + my $flagsref = { map { $_ => '' } @{ $defaults{problem_flags} } }; + + print "\nStripping -arch flags due to Apple multi-architecture build problems:\n" if $verbose; + for my $flag ( keys %{ $flagsref } ) { + my $stored = $conf->data->get($flag) || ''; + + _precheck($flag, $stored, $verbose); + + $flagsref = _strip_arch_flags_engine( + $defaults{architectures}, $stored, $flagsref, $flag + ); + + _postcheck($flagsref, $flag, $verbose); + } + return $flagsref; +} + +sub _strip_ldl_as_needed { + my $libs = shift; + my $OSVers = $defaults{uname}; + chomp $OSVers; + { + local $^W; + $OSVers =~ /(\d+)/; + if ( $1 >= 7 ) { + $libs =~ s/-ldl//; + } + } + return $libs; +} + +sub _set_deployment_environment { + unless (defined $ENV{'MACOSX_DEPLOYMENT_TARGET'}) { + my $OSX_vers = $defaults{sw_vers}; + chomp $OSX_vers; + # remove minor version + $OSX_vers =join '.', (split /[.]/, $OSX_vers)[0,1]; + $ENV{'MACOSX_DEPLOYMENT_TARGET'} = $OSX_vers; + } +} + 1; # Local Variables: