#!@PERL@ use strict; use Symbol; my @modules; my %module_dependency; my %module_library_link_opts; my %header_dependency; $|=1; # note: Mac OS X resource forks and .DS_Store files are explicity ignored print "Box build environment setup.\n"; # Modules that everything else depends on, without being explicitly specified. # Deprecated because we can't specify dependencies between them in the usual way, # and it's totally unnecessary anyway: my @implicit_deps; # work out platform variables use lib 'infrastructure'; use BoxPlatform; print "Building on '$build_os $build_os_ver' using ". ($bsd_make ? "BSD" : "GNU")." $make_command.\n\n"; # keep copy of command line args my $makebuildenv_args = join(' ',@ARGV); # make sure local files directory exists unless(-d 'local') { mkdir 'local',0755; } # flags about the environment my %env_flags; # print "Flag: $_\n" for(keys %env_flags); # seed autogen code print "Seeding autogen code...\n"; open FINDAUTOGEN,"find . -follow -name Makefile.extra |" or die "Can't use find for locating files"; while() { chomp; my $file = $_; $file =~ m~\A(.+)/[^/]+\Z~; my $dir = $1; open FL,$file or die "Can't open $_ for reading"; my %vars; $vars{_PERL} = "@PERL@"; my $do_cmds = 0; while() { chomp; if(m/\A(.+)\s+=\s+(.+)\Z/) { # is a variable $vars{$1} = $2; next; } next unless m/\S/; if(m/AUTOGEN SEEDING/) { $do_cmds = 1; } elsif(m/\A\S/) { $do_cmds = 0 if $do_cmds == 2; } else { # command, run it? if($do_cmds) { $do_cmds = 2; # flag something has been done # subsitute variables, repeatedly my $c = $_; $c =~ s/\A\s+//; while(1) { my $did_subst = 0; for my $k (keys %vars) { $did_subst = 1 if $c =~ s/\$\($k\)/$vars{$k}/g; } last unless $did_subst; } # run command unless (0 == system("(cd $dir; $c)")) { die "Couldn't run command $c " . "(in $dir) for $file"; } } } } close FL; } close FINDAUTOGEN; print "done\n\n"; # open test mail program template file my $test_template_file = 'infrastructure/buildenv-testmain-template.cpp'; open FL,$test_template_file or die "Can't open test template file\n"; my $test_template; read FL,$test_template,-s $test_template_file; close FL; # extra platform defines my $extra_platform_defines = ''; # read in module definitions file, and any files it includes my @modules_files; sub read_modules_file { my ($mf) = @_; my $f = gensym; open $f,$mf or die "Can't open modules file '$mf'\n"; while(<$f>) { if(m/\AINCLUDE\s+(\S+)\Z/) { # include another file read_modules_file($1) } else { push @modules_files,$_ } } close $f; } read_modules_file('modules.txt'); # prepare directories... mkdir "release",0755; mkdir "debug",0755; # is the library code in another directory? my $external_lib = readlink('lib'); if($external_lib ne '') { # adjust to root of the library distribution $external_lib =~ s!/lib\Z!!; $external_lib = '../'.$external_lib; # make symlinks make_obj_symlink('debug'); make_obj_symlink('release'); } sub make_obj_symlink { my $m = $_[0]; my $target = $external_lib."/$m/lib/"; my $link = "$m/lib"; # check link if(-e $link) { if(-l $link) { if(readlink($link) ne $target) { print "Warning: replacing $link with new link to $target\n"; unlink $link; } } else { die "$link already exists, but it isn't a symbolic link" } } if(!-e $link) { symlink $target,$link or die "Can't make $m/lib symlink"; } } print "Scanning code...\n"; my $modules_omitted = 0; my $modules_omitting = 0; # process lines in flattened modules files for(@modules_files) { # clean up line chomp; s/\A\s+//; s/#.*\Z//; s/\s+\Z//; s/\s+/ /g; next unless m/\S/; # omit bits on some platforms? if(m/\AEND-OMIT/) { $modules_omitting = 0; next; } next if $modules_omitting; if(m/\AOMIT:(.+)/) { if($1 eq $build_os or $1 eq $ac_target_os) { $modules_omitted = 1; $modules_omitting = 1; } next; } # split up... my ($mod, @deps_i) = split / /; # ignore this module? next if ignore_module($mod); # deps for this platform my @deps; for(@deps_i) { my ($dep,$exclude_from) = split /!/; # generic library translation $dep = $env_flags{'LIBTRANS_'.$dep} if exists($env_flags{'LIBTRANS_'.$dep}); next if $dep eq ''; if($exclude_from =~ m/\A\+(.+)\Z/) { $exclude_from = $1; my $inc = 0; for(split /,/,$exclude_from) { $inc = 1 if $_ eq $build_os } push @deps,$dep if $inc } else { my $inc = 1; for(split /,/,$exclude_from) { $inc = 0 if $_ eq $build_os } push @deps,$dep if $inc } } # check directory exists die "Module $mod can't be found\n" unless -d $mod; # and put in lists push @modules,$mod; my @md; # module dependencies my @lo; # link line options for (@deps) { if(/\A-l/) { push @lo,$_ } else { push @md,$_ unless ignore_module($_) } } $module_dependency{$mod} = [@implicit_deps,@md]; $module_library_link_opts{$mod} = [@lo]; # make directories, but not if we're using an external library and this a library module my ($s,$d) = split /\//,$mod; if ($s ne 'lib' or $external_lib eq '') { mkdir "release/$s",0755; mkdir "release/$s/$d",0755; mkdir "debug/$s",0755; mkdir "debug/$s/$d",0755; } } # make dirs for implicit dep foreach my $dep (@implicit_deps) { mkdir "release/$dep",0755; mkdir "debug/$dep",0755; } # write a list of all the modules we've configured to use open CONFIGURED_MODS,'>local/modules.h' or die "Can't write configured modules list"; print CONFIGURED_MODS <<__E; // automatically generated file, do not edit #ifndef _CONFIGURED_MODULES__H #define _CONFIGURED_MODULES__H __E for(@implicit_deps,@modules) { my $m = $_; $m =~ s~/~_~; print CONFIGURED_MODS "#define MODULE_$m\n"; } print CONFIGURED_MODS <<__E; #endif // _CONFIGURED_MODULES__H __E close CONFIGURED_MODS; # now make a list of all the .h files we can find, recording which module they're in my %hfiles; for my $mod (@modules, @implicit_deps) { opendir DIR,$mod; my @items = readdir DIR; closedir DIR; # add in items from autogen directories, and create output directories { my @autogen_items; for my $di (@items) { if($di =~ m/\Aautogen/ && -d "$mod/$di") { # Read items my $d = "$mod/$di"; opendir DIR,$d; my @i = readdir DIR; closedir DIR; for(@i) { next if m/\A\./; push @autogen_items,"$di/$_" } } } @items = (@items, @autogen_items); } for(grep /\.h\Z/i, @items) { next if /\A\._/; # Temp Mac OS Resource hack die "Header file $_ already used in module ".$hfiles{$_}. ", cannot add to $mod\n" if exists $hfiles{$_}; $hfiles{$_} = $mod } } for my $mod (@modules, @implicit_deps) { opendir DIR,$mod; for my $h (grep /\.h\Z/i, readdir DIR) { next if $h =~ /\A\./; # Ignore Mac resource forks, autosaves, etc open FL,"$mod/$h" or die "can't open $mod/$h"; my $f; read FL,$f,-s "$mod/$h"; close FL; while($f =~ m/\#include\s+"([^"]+?)"/g) { my $i = $1; # ignore autogen exceptions next if $i =~ m/\Aautogen_.+?Exception.h\Z/; # record dependency ${$header_dependency{$h}}{$i} = 1 if exists $hfiles{$i}; } } closedir DIR; } my $default_cflags = '@CFLAGS@'; my $default_cxxflags = '@CXXFLAGS@'; $default_cflags =~ s/ -O2//g; $default_cxxflags =~ s/ -O2//g; my $debug_base_dir = 'debug'; my $release_base_dir = 'release'; my $debugger = '@with_debugger@'; my $release_flags = "-O2"; if ($target_windows) { $release_flags = "-O0 -g"; } # Then write a master Makefile, and a mini-Makefile for each module print "done\n\nGenerating Makefiles...\n"; my $makefile_ifdef_prefix = $bsd_make ? "." : ""; my $autoconf_cppflags = '@CPPFLAGS@'; my $autoconf_cxxflags = '@CXXFLAGS_STRICT@'; my $autoconf_ldflags = '@LDFLAGS@'; open MASTER_MAKEFILE, ">Makefile" or die "Makefile: $!"; print MASTER_MAKEFILE <<__E; # # AUTOMATICALLY GENERATED FILE # do not edit! # # # "parcels" is defined near the end of this Makefile. default: parcels CC = @CC@ CXX = @CXX@ AR = @AR@ RANLIB = @RANLIB@ PERL = @PERL@ WINDRES = @WINDRES@ # Work around a mistake in QDBM (using includes for a file not in the # system path) by adding it to the include path with -I. DEFAULT_CFLAGS = $autoconf_cppflags $default_cflags $autoconf_cxxflags \\ $extra_platform_defines $platform_compile_line_extra \\ -DBOX_VERSION="\\"$product_version\\"" -Iqdbm DEFAULT_CXXFLAGS = $autoconf_cppflags $default_cxxflags $autoconf_cxxflags \\ $extra_platform_defines $platform_compile_line_extra \\ -DBOX_VERSION="\\"$product_version\\"" LDFLAGS += $autoconf_ldflags \@LDADD_RDYNAMIC@ $platform_link_line_extra RELEASE_CFLAGS = \$(DEFAULT_CFLAGS) -DBOX_RELEASE_BUILD $release_flags RELEASE_CXXFLAGS = \$(DEFAULT_CXXFLAGS) -DBOX_RELEASE_BUILD $release_flags RELEASE_OUTBASE = $release_base_dir # http://gcc.gnu.org/onlinedocs/libstdc++/manual/debug_mode_using.html#debug_mode.using.mode DEBUG_CFLAGS = \$(DEFAULT_CFLAGS) -g -O0 -D_GLIBCXX_DEBUG DEBUG_CXXFLAGS = \$(DEFAULT_CXXFLAGS) -g -O0 -D_GLIBCXX_DEBUG DEBUG_OUTBASE = $debug_base_dir __E if ($bsd_make) { print MASTER_MAKEFILE <<__E; .ifdef V HIDE = _CC = \$(CC) _CXX = \$(CXX) _LINK = \$(CXX) _WINDRES = \$(WINDRES) _AR = \$(AR) _RANLIB = \$(RANLIB) _PERL = \$(PERL) .else HIDE = @ _CC = @ echo " [CC] " \$(*F) && \$(CC) _CXX = @ echo " [CXX] " \$(*F) && \$(CXX) _LINK = @ echo " [LINK] " \$(*F) && \$(CXX) _WINDRES = @ echo " [WINDRES]" \$(*F) && \$(WINDRES) _AR = @ echo " [AR] " \$(*F) && \$(AR) _RANLIB = @ echo " [RANLIB] " \$(*F) && \$(RANLIB) _PERL = @ echo " [PERL] " \$(*F) && \$(PERL) >/dev/null .endif __E } else { print MASTER_MAKEFILE <<__E; HIDE = \$(if \$(V),,@) _CC = \$(if \$(V),\$(CC), @ echo " [CC] \$<" && \$(CC)) _CXX = \$(if \$(V),\$(CXX), @ echo " [CXX] \$<" && \$(CXX)) _LINK = \$(if \$(V),\$(CXX), @ echo " [LINK] \$@" && \$(CXX)) _WINDRES = \$(if \$(V),\$(WINDRES), @ echo " [WINDRES] \$<" && \$(WINDRES)) _AR = \$(if \$(V),\$(AR), @ echo " [AR] \$@" && \$(AR)) _RANLIB = \$(if \$(V),\$(RANLIB), @ echo " [RANLIB] \$@" && \$(RANLIB)) _PERL = \$(if \$(V),\$(PERL), @ echo " [PERL] \$@" && \$(PERL) >/dev/null) __E } my %module_resources_win32; my @debug_build_targets; my @release_build_targets; my @all_clean_targets; my @all_realclean_targets; my %mod_type_name; my %mod_end_targets; my %library_targets; # First, loop over all modules and quickly categorise them and generate the target filenames. # We need this to write correct dependency info into the makefile when modules are listed # out of order in modules.txt, which isn't strictly necessary but may look tidier. for my $mod (@implicit_deps, @modules) { print $mod,"\n"; my ($type,$name) = split /\//,$mod; if (not $name) { # External modules such as qdbm have no "type" in the directory path. $name = $mod; $type = 'lib'; } # is target a library? my $target_is_library = ($type ne 'bin' && $type ne 'test'); # make target name my $end_target_file = $name; if ($target_is_library) { $end_target_file .= '.a'; } else { $end_target_file .= $platform_exe_ext; } $end_target_file = '_test'.$platform_exe_ext if $type eq 'test'; $mod_type_name{$mod} = [$type, $name]; $mod_end_targets{$mod} = $end_target_file; $library_targets{$mod} = $target_is_library; } # Now loop over them again, generating makefile instructions etc. for my $mod (@implicit_deps, @modules) { my ($type,$name) = @{$mod_type_name{$mod}}; my $end_target_file = $mod_end_targets{$mod}; my $target_is_library = $library_targets{$mod}; # add additional files for tests if($type eq 'test') { my $testmain = $test_template; $testmain =~ s/TEST_NAME/$name/g; open TESTMAIN,">$mod/_main.cpp" or die "Can't open test main file for $mod for writing\n"; print TESTMAIN $testmain; close TESTMAIN; # test file... sub writetestfile { my ($filename,$runcmd,$module) = @_; open TESTFILE,">$filename" or die "Can't open " . "test script file for $module for writing\n"; print TESTFILE "#!/bin/sh\necho TEST: $module\n"; if ($target_windows) { print TESTFILE <<__E; kill_process() { if test -r testfiles/\$1.pid; then /bin/kill -0 -f `cat testfiles/\$1.pid` \\ && /bin/kill -f `cat testfiles/\$1.pid` rm testfiles/\$1.pid fi } __E } else { print TESTFILE <<__E; kill_process() { test -r testfiles/\$1.pid \\ && kill -0 `cat testfiles/\$1.pid` \\ && kill `cat testfiles/\$1.pid` } __E } if (-d "$module/testfiles") { print TESTFILE <<__E; kill_daemons() { kill_process bbackupd kill_process bbstored kill_process httpserver kill_process s3simulator } echo Killing any running daemons... kill_daemons __E } print TESTFILE <<__E; echo Removing old test files... chmod -R a+rwx testfiles rm -rf testfiles echo Copying new test files... cp -p -R ../../../$module/testfiles . __E if (-e "$module/testextra") { open FL,"$module/testextra" or die "Can't open $module/testextra"; while() {print TESTFILE} close FL; } print TESTFILE "$runcmd\nexit_status=\$?\n"; if (-d "$module/testfiles") { print TESTFILE <<__E; kill_daemons __E } print TESTFILE "exit \$exit_status\n"; close TESTFILE; } writetestfile("$mod/t", "GLIBCXX_FORCE_NEW=1 ". './_test' . $platform_exe_ext . ' "$@"', $mod); if($debugger) { writetestfile("$mod/t-gdb", "GLIBCXX_FORCE_NEW=1 ". $debugger . ' ./_test' . $platform_exe_ext . ' "$@"', $mod); } else { writetestfile("$mod/t-gdb", "echo 'No debugger was detected by configure script'\n". "exit 2", $mod); } } my @all_deps_for_module; { # work out what dependencies need to be run my @deps_raw; sub add_mod_deps { my ($arr_r,$nm) = @_; if($#{$module_dependency{$nm}} >= 0) { push @$arr_r,@{$module_dependency{$nm}}; for(@{$module_dependency{$nm}}) { add_mod_deps($arr_r,$_) } } } add_mod_deps(\@deps_raw, $mod); # and then dedup and reorder them my %d_done; foreach my $dep (reverse @deps_raw) { if(!exists $d_done{$dep}) { # insert push @all_deps_for_module, $dep; # mark as done $d_done{$dep} = 1; } } } # get the list of library things to add -- in order of dependency # so things link properly my @lib_files; my @dep_targets; my @include_search_dirs; foreach my $dep (reverse @all_deps_for_module) { my $dep_target = $mod_end_targets{$dep}; die "No output file found for $dep" unless $dep_target; $dep_target = "$dep/$dep_target"; push @dep_targets, $dep_target; if ($dep =~ m|^lib\/(.+)$|) { push @lib_files, $dep_target; push @include_search_dirs, $dep; } elsif ($dep =~ m|^([^/]+)$|) { push @lib_files, $dep_target; push @include_search_dirs, $dep; } } # make include path my $cpp_include_paths = join(' ',map {"-I$_"} @include_search_dirs); print MASTER_MAKEFILE "${type}_${name}_includes = $cpp_include_paths\n"; # adjust for outdir my $debug_end_target = "\$(DEBUG_OUTBASE)/$mod/$end_target_file"; my $release_end_target = "\$(RELEASE_OUTBASE)/$mod/$end_target_file"; push @debug_build_targets, $debug_end_target; push @release_build_targets, $release_end_target; # start the makefile open MINI_MODULE_MAKEFILE,">$mod/Makefile" or die "Can't open Makefile for $mod\n"; print MINI_MODULE_MAKEFILE <<__E; # # AUTOMATICALLY GENERATED FILE # do not edit! # ${makefile_ifdef_prefix}ifdef RELEASE TARGET = $release_base_dir/$mod/$end_target_file ${makefile_ifdef_prefix}else TARGET = $debug_base_dir/$mod/$end_target_file ${makefile_ifdef_prefix}endif .PHONY: default default: \$(MAKE) -C ../.. \$(TARGET) .PHONY: clean clean: \$(MAKE) -C ../.. clean_${type}_${name} .PHONY: realclean realclean: \$(MAKE) -C ../.. realclean_${type}_${name} __E close MINI_MODULE_MAKEFILE; opendir DIR, $mod; my @items = readdir DIR; closedir DIR; # add in items from autogen directories, and create output directories { my @autogen_items; for my $di (@items) { if($di =~ m/\Aautogen/ && -d "$mod/$di") { # Read items my $d = "$mod/$di"; opendir DIR, $d; my @i = readdir DIR; closedir DIR; for (@i) { next if m/\A\./; push @autogen_items,"$di/$_" } # output directories mkdir "release/$mod/$di",0755; mkdir "debug/$mod/$di",0755; } } @items = (@items, @autogen_items); } # first, obtain a list of dependencies within the .h files my %headers; for my $h (grep /\.h\Z/i, @items) { open FL,"$mod/$h"; my $f; read FL,$f,-s "$mod/$h"; close FL; while($f =~ m/\#include\s+"([^"]+?)"/g) { ${$headers{$h}}{$1} = 1 if exists $hfiles{$1}; } } # write the recipes for debug and release builds of each file foreach my $var_prefix ('DEBUG', 'RELEASE') { my $make; # then... do the cpp files... my @obj_base; for my $file (@items) { my $is_c = $file =~ m/\A(.+)\.c\Z/i; my $is_cpp = $file =~ m/\A(.+)\.cpp\Z/i; my $is_rc = $file =~ m/\A(.+)\.rc\Z/i; my $base = $1; # Don't try to compile .rc files except on Windows: next if not $is_c and not $is_cpp and not ($is_rc and $target_windows); next if $file =~ /\A\._/; # Temp Mac OS Resource hack # store for later push @obj_base, $base; # get the file... open FL, "$mod/$file"; my $f; read FL, $f, -s "$mod/$file"; close FL; my %dep; while($f =~ m/\#include\s+"([^"]+?)"/g) { insert_dep($1, \%dep) if exists $hfiles{$1}; } # output filename my $out_name = "\$(${var_prefix}_OUTBASE)/$mod/$base.o"; # write the line for this cpp file my @dep_paths = map { ($hfiles{$_} eq $mod) ? "$mod/$_" : $hfiles{$_}."/$_" } keys %dep; $make .= "$out_name: $mod/$file @dep_paths\n"; if ($is_c) { $make .= "\t\$(_CC) \$(${var_prefix}_CFLAGS) ". "\$(${type}_${name}_includes) -DBOX_MODULE=\"\\\"$mod\\\"\" " . "-c $mod/$file -o $out_name\n\n"; } if ($is_cpp) { $make .= "\t\$(_CXX) \$(${var_prefix}_CXXFLAGS) ". "\$(${type}_${name}_includes) -DBOX_MODULE=\"\\\"$mod\\\"\" " . "-c $mod/$file -o $out_name\n\n"; } elsif ($is_rc) { $make .= "\t\$(_WINDRES) $file $out_name\n\n"; my $res_list = $module_resources_win32{$mod}; $res_list ||= []; push @$res_list, $base.'.o'; $module_resources_win32{$mod} = $res_list; } } # need to see if the extra makefile fragments require extra object files # or include any more makefiles my @objs = @obj_base; my @makefile_includes; additional_objects_from_make_fragment("$mod/Makefile.extra", \@objs, \@makefile_includes); additional_objects_from_make_fragment("$mod/Makefile.extra.$build_os", \@objs, \@makefile_includes); my $prefixed_end_target = "\$(${var_prefix}_OUTBASE)/$mod/$end_target_file"; my $o_file_list = join(' ',map {"\$(${var_prefix}_OUTBASE)/$mod/$_.o"} sort @objs); my @prefixed_lib_files = map {"\$(${var_prefix}_OUTBASE)/$_"} @lib_files; my @prefixed_dep_targets = map {"\$(${var_prefix}_OUTBASE)/$_"} @dep_targets; print MASTER_MAKEFILE "$prefixed_end_target: $o_file_list"; print MASTER_MAKEFILE " @prefixed_dep_targets" unless $target_is_library; print MASTER_MAKEFILE "\n"; if ($target_windows) { foreach my $dep (@all_deps_for_module) { my $res_list = $module_resources_win32{$dep}; next unless $res_list; $o_file_list .= ' '.join(' ', map {"\$(${var_prefix}_OUTBASE)/$dep/$_"} @$res_list); } } # stuff to make the final target... if($target_is_library) { # make a library archive... print MASTER_MAKEFILE "\t\$(HIDE) (rm -f $prefixed_end_target)\n"; print MASTER_MAKEFILE "\t\$(_AR) cq $prefixed_end_target $o_file_list\n"; print MASTER_MAKEFILE "\t\$(_RANLIB) $prefixed_end_target\n"; } else { # work out library options # need to be... least used first, in absolute order they appear in the modules.txt file my @libops; sub libops_fill { my ($module, $libops_ref) = @_; my $library_link_opts = $module_library_link_opts{$module}; if ($library_link_opts) { push @$libops_ref, @$library_link_opts; } my $deps = $module_dependency{$module}; foreach my $dep (@$deps) { libops_fill($dep, $libops_ref); } } libops_fill($mod,\@libops); my $lo = ''; my %ldone; for(@libops) { next if exists $ldone{$_}; $lo .= ' '.$_; $ldone{$_} = 1; } # link line... print MASTER_MAKEFILE "\t\$(_LINK) \$(LDFLAGS) " . "-o $prefixed_end_target $o_file_list " . "@prefixed_lib_files $lo $platform_lib_files\n"; } # tests need to copy the test file over if($type eq 'test') { print MASTER_MAKEFILE <<__E; \$(HIDE) cp $mod/t \$(${var_prefix}_OUTBASE)/$mod/t \$(HIDE) chmod u+x \$(${var_prefix}_OUTBASE)/$mod/t \$(HIDE) cp $mod/t-gdb \$(${var_prefix}_OUTBASE)/$mod/t-gdb \$(HIDE) chmod u+x \$(${var_prefix}_OUTBASE)/$mod/t-gdb __E } print MASTER_MAKEFILE $make,"\n"; for(@makefile_includes) { print MASTER_MAKEFILE "\n.include <$_>\n"; } } print MASTER_MAKEFILE <<__E; clean_${type}_${name}: rm -rf \$(DEBUG_OUTBASE)/$mod/* rm -rf \$(RELEASE_OUTBASE)/$mod/* realclean_${type}_${name}: clean_${type}_${name} rm -f $mod/t $mod/t-gdb $mod/Makefile find $mod -name 'autogen_*' -type f -exec rm -f {} \\; __E push @all_clean_targets, "clean_${type}_${name}"; push @all_realclean_targets, "realclean_${type}_${name}"; my $includes = ""; if(-e "$mod/Makefile.extra") { $includes .= ".include <$mod/Makefile.extra>\n\n"; } if(-e "$mod/Makefile.extra.$build_os") { $includes .= ".include <$mod/Makefile.extra.$build_os>\n\n"; } if(!$bsd_make) { # need to post process this into a GNU makefile $includes =~ s/\A\.\s*(ifdef|else|endif|ifndef)/$1/; $includes =~ s/\A\.\s*include\s+<(.+?)>/include $1/; $includes =~ s/-D\s+(\w+)/$1=1/g; } print MASTER_MAKEFILE $includes; } my @parcels; my %parcel_contents; sub starts_with ($$) { my ($string,$expected) = @_; return substr($string, 0, length $expected) eq $expected; } sub os_matches ($) { my ($prefix_string) = @_; my @prefixes = split m'\,', $prefix_string; foreach my $prefix (@prefixes) { return 1 if starts_with($build_os, $prefix); return 1 if starts_with($ac_target_os, $prefix); return 1 if starts_with("$ac_target_cpu-$ac_target_os", $prefix); return 1 if starts_with($ac_target, $prefix); } return 0; } my $copy_command = "cp -p"; open PARCELS,"parcels.txt" or die "Can't open parcels file"; { my $cur_parcel = ''; while() { chomp; s/#.+\Z//; s/\s+\Z//; s/\s+/ /g; next unless m/\S/; # omit bits on some platforms? next if m/\AEND-OMIT/; if(m/\AOMIT:(.+)/) { if (os_matches($1)) { while() { last if m/\AEND-OMIT/; } } next; } if (m'\AONLY:(.+)') { if (not os_matches($1)) { while () { last if m'\AEND-ONLY'; } } next; } next if (m'\AEND-ONLY'); if (m'\AEXCEPT:(.+)') { if (os_matches($1)) { while () { last if m'\AEND-EXCEPT'; } } next; } next if (m'\AEND-EXCEPT'); # new parcel, or a new parcel definition? if(m/\A\s+(.+)\Z/) { push @{$parcel_contents{$cur_parcel}},$1 } else { $cur_parcel = $_; push @parcels,$_; } } } close PARCELS; # create parcels directory mkdir "parcels",0755; mkdir "parcels/scripts",0755; print MASTER_MAKEFILE "parcels:\t",join(' ',map {"build-".$_} @parcels),"\n\n"; my $runtest_script = $target_windows ? './infrastructure/mingw/runtest.sh' : './runtest.pl'; print MASTER_MAKEFILE <<__END_OF_FRAGMENT; .PHONY: test test: debug_tests release_tests .PHONY: debug_tests debug_tests: $runtest_script ALL debug .PHONY: release_tests release_tests: $runtest_script ALL release .PHONY: docs docs: cd docs; \$(MAKE) __END_OF_FRAGMENT my $release_flag = BoxPlatform::make_flag('RELEASE'); my @parcel_targets; for my $parcel (@parcels) { my $version = BoxPlatform::parcel_root($parcel); my $make_target = BoxPlatform::parcel_target($parcel); my $dir = BoxPlatform::parcel_dir($parcel); my @parcel_deps; # Need to use BSD install on Solaris my $install_bin = $build_os eq 'SunOS' ? '/usr/ucb/install' : 'install'; unless ($target_windows) { open SCRIPT,">parcels/scripts/install-$parcel" or die "Can't open installer script for $parcel for writing"; print SCRIPT "#!/bin/sh\n\n"; } for(@{$parcel_contents{$parcel}}) { my @args = split /\s+/; my ($type,$name,$dest) = @args; my $optional = 0; my $install = 1; if ($type eq 'optional') { $optional = 1; shift @args; ($type,$name,$dest) = @args; } if ($type eq 'noinstall') { $install = 0; shift @args; ($type,$name,$dest) = @args; } if($type eq 'bin') { my $exeext = $platform_exe_ext; print MASTER_MAKEFILE < $root.tgz )\n"; print MASTER_MAKEFILE "\n"; unless ($target_windows) { print MASTER_MAKEFILE "install-$parcel:\n"; print MASTER_MAKEFILE "\t(cd $dir; ./install-$parcel)\n\n"; } } print MASTER_MAKEFILE <local/install.msg" or die "Can't open install message file for writing"; print INSTALLMSG <<__E; Parcels need to be installed separately, and as root. Type one of the following: __E for(@parcels) { print INSTALLMSG " $make_command install-".$_."\n"; } print INSTALLMSG "\n"; close INSTALLMSG; close MASTER_MAKEFILE; print "\nType 'cd ; $make_command' to build a module\n\n"; if($modules_omitted) { print "\nNOTE: Some modules have been omitted on this platform\n\n" } sub insert_dep { my ($h,$dep_r) = @_; # stop random recusion return if exists $$dep_r{$h}; # insert more depencies insert_dep($_,$dep_r) for keys %{$header_dependency{$h}}; # mark this one as a dependency $$dep_r{$h} = 1; } sub additional_objects_from_make_fragment { my ($fn,$objs_r,$include_r) = @_; if(-e $fn) { open FL,$fn or die "Can't open $fn"; while() { chomp; if(m/link-extra:\s*(.+)\Z/) { my $extra = $1; do { my @o = split /\s+/, $extra; for(@o) { push @$objs_r,$1 if m/\A(.+)\.o\Z/; } last unless $extra =~ m'\\$'; $extra = ; } while(1); } elsif(m/include-makefile:\s*(\S+)/) { push @$include_r,$1 } } close FL; } } sub ignore_module { exists $env_flags{'IGNORE_'.$_[0]} }