Radix cross Linux Build System

Cross-platform build system is designed to build distributions of different operating systems for a set of target devices

39 Commits   2 Branches   2 Tags
#!/bin/env perl

use FindBin;
use lib $FindBin::Bin;

use strict;
use warnings FATAL => 'all';

use IO::Handle;
use File::Basename;
use File::Temp;
use Getopt::Long;

use _kxLab;

#
# Generate .src_requires file for current directory
#
# usage:
#   $0 [options] topdir
#
# where:
#   'topdir' - is a absolute path to the top directory of checked out branch
#


# global variables
my (%all_requires, $top_dir, $opt_max_depth, %requires_depend, $requires_file, %skip_dirs);

my %all_src_requires;


sub usage
{
  print <<EOF;

Usage: build_requires [options] topdir
Options:
   --max-depth=i - where 'i' is a maximal directory depth for finding requires;
      --skip-dir - directory to be skipped (such as dist or TARGET_BUILD_DIR);
          topdir - is a absolute path to the top of checked out branch.

EOF
  exit;
}


sub requires_depend
{
  my $makefile = shift;

  if( ! exists $requires_depend{$makefile} )
  {
    print REQUIRES_DEPEND_FILE "$requires_file: $makefile\n\n";
    print REQUIRES_DEPEND_FILE "$makefile:\n\n";
    $requires_depend{$makefile} = "";
  }
}

sub read_src_requires
{
  my $makefile  = shift;

  # add a dependency to the Makefile
  requires_depend($makefile);

  my %requires;

  my $shell_output = `cat $makefile`;

  while( $shell_output =~ m/^SOURCE_REQUIRES(.+= +)(.+)/gm )
  {
    my @n = split( " ", $2 );
    foreach my $d ( @n )
    {
      if( $d eq "ALL_DIRS" )
      {
        my $dirname = dirname($makefile);

        opendir( DIR, "$dirname" ) or
          _kxLab::error( "build_src_requires: Could not open directory: $dirname: $!" );
        my @dirs = grep { ! /^\./ && -d "$_" && -f "$_/Makefile" } readdir( DIR );
        closedir DIR;

        foreach my $dir (@dirs)
        {
          requires_depend("$dirname/$dir/Makefile");
          "$dirname/$dir" =~ m!$top_dir/(.+)!;
          $requires{$1} = "";
        }
      }
      else
      {
        # Print a nice error message if the SOURCE_REQUIRES statement points to a missing directory
        _kxLab::error( "build_src_requires: SOURCE_REQUIRES '$d' in $makefile not found. Exit" ) if( ! -d "$top_dir/$d" );

        if( -f "$top_dir/$d/Makefile" )
        {
          $requires{$d} = "";
          requires_depend("$top_dir/$d/Makefile");
        }
      }
    }
  }
  return %requires;
}

sub read_requires
{
  my $makefile  = shift;

  # add a dependency to the Makefile
  requires_depend($makefile);

  my %requires;

  my $shell_output = `cat $makefile`;

  while( $shell_output =~ m/^REQUIRES(.+= +)(.+)/gm )
  {
    my @n = split( " ", $2 );
    foreach my $req ( @n )
    {
      my $d = `echo $req | cut -f 1 -d '^'`;
      $d =~ s/^\s+|\s+$//;

      if( $d eq "ALL_DIRS" )
      {
        my $dirname = dirname($makefile);

        opendir( DIR, "$dirname" ) or
          _kxLab::error( "build_src_requires: Could not open directory: $dirname: $!" );
        my @dirs = grep { ! /^\./ && -d "$_" && -f "$_/Makefile" } readdir( DIR );
        closedir DIR;

        foreach my $dir (@dirs)
        {
          requires_depend( "$dirname/$dir/Makefile" );
          "$dirname/$dir" =~ m!$top_dir/(.+)!;
          $requires{$1} = "";

          my %src_requires = read_src_requires( "$dirname/$dir/Makefile" );
          my @sort_src_requires = sort(keys %src_requires);
          foreach my $req ( @sort_src_requires )
          {
            $all_src_requires{$req} = "";
          }
        }
      }
      else
      {
        # Print a nice error message if the REQUIRES statement points to a missing directory
        _kxLab::error( "build_src_requires: REQUIRES '$d' in $makefile not found. Exit" ) if( ! -d "$top_dir/$d" );

        if( -f "$top_dir/$d/Makefile" )
        {
          $requires{$d} = "";

          my %src_requires = read_src_requires( "$top_dir/$d/Makefile" );
          my @sort_src_requires = sort(keys %src_requires);
          foreach my $req ( @sort_src_requires )
          {
            $all_src_requires{$req} = "";
          }
        }
      }
    }
  }
  return %requires;
}

sub start_depend
{
  my $req = shift;

  print REQUIRES_FILE "$req:";
}

sub depend
{
  my $req = shift;

  print REQUIRES_FILE " $req";
}

sub end_depend
{
  print REQUIRES_FILE "\n\n";
}

sub make_sub_requires
{
  my $req = shift;

  if( ! exists $all_requires{$req} )
  {
    $all_requires{$req} = "";

    my $d = `echo $req | cut -f 1 -d '^'`;
    $d =~ s/^\s+|\s+$//;

    # Read sub requires
    my $makefile = "$top_dir/$d/Makefile";
    my %sub_requires = read_requires( $makefile );
    if( scalar(%sub_requires) )
    {
      # Make sub sub requires
      my @sorted_sub_requires = sort(keys %sub_requires);
      foreach my $sub_req ( @sorted_sub_requires )
      {
        make_sub_requires( $sub_req );
      }
    }
  }
}


#
# Parse the command line options
#
$opt_max_depth = 10;
my @opt_skip_dirs;
GetOptions( "max-depth=i" => \$opt_max_depth, "skip-dir=s" => \@opt_skip_dirs );
%skip_dirs = map { $_ => "" } @opt_skip_dirs;

# get the rest of the command line
my $topdir   = shift;
my $makefile = "Makefile";

if( ! defined $topdir or $topdir eq "" ) { usage; }

_kxLab::error( "build_requires: $topdir is not a directory" ) if( ! -d $topdir );
_kxLab::error( "build_requires: Makefile missing: $makefile" ) if ( ! -f $makefile );

# setup $top_build_dir
$top_dir = $topdir;

$requires_file = ".src_requires";
my $requires_depend_file = $requires_file . "_depend";


# open the output files
open(REQUIRES_FILE, "> $requires_file") or
  _kxLab::error( "build_requires: Could not open $requires_file file: $!" );
open(REQUIRES_DEPEND_FILE, "> $requires_depend_file") or
  _kxLab::error( "build_requires: Could not open $requires_depend_file file: $!" );


# root component
my $pwd = `pwd`;
chomp $pwd;
$pwd =~ m!$top_dir(.*)!;
my $root;
if( $1 eq "" )
{
  $root = "all";
}
else
{
  $1 =~ m!/(.+)!;
  $root = $1;
}

print REQUIRES_FILE "# ROOT=$root\n\n";
print REQUIRES_DEPEND_FILE "\n";

# read the makefile
%all_src_requires = read_src_requires( "$pwd/$makefile" );
my %requires = read_requires( "$pwd/$makefile" );


# check the "build-system" sub dependencies implicitly (excluding sources directories)
#$requires{"build-system"} = "";


# build sub dependencies
my @sorted_requires = sort(keys %requires);
foreach my $req ( @sorted_requires )
{
  make_sub_requires( $req );
}

# build the all: rule
start_depend( "all" );
my @sorted_src_requires = sort(keys %all_src_requires);
foreach my $req ( @sorted_src_requires )
{
  depend( $req );
}
end_depend();


# Finish by including tree.mk
print REQUIRES_FILE "TREEDIRS = ", join(" ", sort(keys %all_src_requires)), "\n\n";
print REQUIRES_FILE "include \$(BUILDSYSTEM)/tree-src.mk\n";


# close output files
close REQUIRES_FILE;
close REQUIRES_DEPEND_FILE;