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
Index: build_packages_list
===================================================================
--- build_packages_list	(nonexistent)
+++ build_packages_list	(revision 5)
@@ -0,0 +1,748 @@
+#!/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 _kxLab;
+
+#
+# Generate $(HARDWARE).pkglist file for current directory
+#
+# usage:
+#   $0 topdir toolchain hardware
+#
+# where:
+#      'topdir' - is a absolute path to the top directory of checked out branch
+#   'toolchain' - is a TOOLCHAIN name
+#    'hardware' - is a HARDWARE variant
+#
+
+# global variables
+my ($build_system);
+my ($topdir, $toolchain, $hardware, $flavour);
+my ($target_build_dir, $requires_file);
+my ($pkglist_file);
+my ($system_version, $distro_name, $distro_version, $url);
+my $tarball_suffix = "txz";
+
+my %sub_trees;
+my %tree;
+
+
+sub usage
+{
+  print <<EOF;
+
+Usage: $0 topdir toolchain hardware
+Where:
+          topdir - is a absolute path to the top of checked out branch;
+       toolchain - is a TOOLCHAIN name;
+        hardware - is a HARDWARE variant.
+
+EOF
+  exit;
+}
+
+#
+# Getting information from build-system/constants.mk
+#
+sub system_version
+{
+  my $build_system = shift;
+  my $version;
+
+  open( FILE, "< $build_system/constants.mk" );
+
+  while( <FILE> )
+  {
+    if( /^SYSTEM_VERSION(.+= +)(.+)/ )
+    {
+      $version = $2;
+    }
+  }
+  close( FILE );
+
+  return $version;
+}
+
+sub distro_name
+{
+  my $build_system = shift;
+  my $name;
+
+  open( FILE, "< $build_system/constants.mk" );
+
+  while( <FILE> )
+  {
+    if( /^DISTRO_NAME(.+= +)(.+)/ )
+    {
+      $name = $2;
+    }
+  }
+  close( FILE );
+
+  return $name;
+}
+
+sub distro_version
+{
+  my $build_system = shift;
+  my $name;
+
+  open( FILE, "< $build_system/constants.mk" );
+
+  while( <FILE> )
+  {
+    if( /^DISTRO_VERSION(.+= +)(.+)/ )
+    {
+      $name = $2;
+    }
+  }
+  close( FILE );
+
+  return $name;
+}
+
+sub bug_url
+{
+  my $build_system = shift;
+  my $url;
+
+  open( FILE, "< $build_system/constants.mk" );
+
+  while( <FILE> )
+  {
+    if( /^BUG_URL(.+= +)(.+)/ )
+    {
+      $url = $2;
+    }
+  }
+  close( FILE );
+
+  return $url;
+}
+
+#
+# value_from_makefile( $makefile, $variable_name, $stop_line ):
+# ------------------------------------------------------------
+#   This function returns the value of variable defined in the
+#   Makefile on global level before od REQUIRES declaration.
+#
+#   The optional $stop_line argument presents the start of the
+#   line which terminates the analized part of Makefile.
+#
+sub value_from_makefile
+{
+  my $makefile  = shift;
+  my $vname     = shift;
+  my $stop_line = shift;
+  my $value     = "";
+
+  if( !defined $stop_line || $stop_line eq '' )
+  {
+    $stop_line = "__END_OF_REQUIRES__";
+  }
+  else
+  {
+    $stop_line = "^" . $stop_line;
+  }
+
+  my $cdir = dirname( $makefile );
+
+  my $shell_output = <<`SHELL`;
+cd $cdir
+head -n `cat Makefile | grep -n "$stop_line" | cut -f 1 -d ':'` Makefile | \
+  make TOOLCHAIN=$toolchain HARDWARE=$hardware FLAVOUR=$flavour -f - -p __build_requires__ 2>/dev/null | grep "$vname"
+exit 0
+SHELL
+
+  if( $shell_output =~ m/^$vname(.+= +)(.+)/gm )
+  {
+    $value = $2;
+  }
+
+  return $value;
+}
+
+#
+# Getting information from Makefile
+#
+sub pkg_rootfs_target
+{
+  my $makefile = shift;
+  my $install = "";
+
+  open( FILE, "< $makefile" );
+
+  while( <FILE> )
+  {
+    if( /^ROOTFS_TARGETS(.+= +)(.+)/ )
+    {
+      if( $2 ne "" ) { $install = "install"; }
+    }
+    elsif( /^ROOTFS_UPDATE_TARGETS(.+= +)(.+)/ )
+    {
+      if( $2 ne "" ) { $install = "update"; }
+    }
+  }
+  close( FILE );
+
+  if( $install eq "" ) { $install = "no";  }
+
+  return $install;
+}
+
+sub pkg_group
+{
+  my $makefile = shift;
+  my $group;
+
+  open( FILE, "< $makefile" );
+
+  while( <FILE> )
+  {
+    if( /^PKG_GROUP(.+= +)(.+)/ )
+    {
+      $group = $2;
+    }
+  }
+  close( FILE );
+
+  return $group;
+}
+
+sub pkg_name
+{
+  my $makefile = shift;
+  my $name = "";
+
+  open( FILE, "< $makefile" );
+
+  while( <FILE> )
+  {
+    if( /^[A-Z_0-9]*_PKG_NAME(.+= +)(.+)/ )
+    {
+      $name = $2;
+    }
+  }
+  close( FILE );
+
+  return $name;
+}
+
+sub pkg_version
+{
+  my $makefile = shift;
+  my $version;
+
+  my $stop_line;
+
+  open( FILE, "< $makefile" );
+
+  while( <FILE> )
+  {
+    if( /^([A-Z_0-9]*_PKG_VERSION)(.+= +)(.+)/ )
+    {
+      $stop_line  = $1;
+      $version    = $3;
+    }
+  }
+  close( FILE );
+
+  # check if version is present as a reference to some variable:
+  if( $version =~ m/^\$\((.+)\)/ )
+  {
+    my $vname = $1;
+
+    # get value of referenced variable
+    $version = value_from_makefile( $makefile, $vname, $stop_line );
+  }
+
+  return $version;
+}
+
+sub pkg_license
+{
+  my $makefile = shift;
+  my $license;
+
+  open( FILE, "< $makefile" );
+
+  while( <FILE> )
+  {
+    if( /^[A-Z_0-9]*_PKG_LICENSE(.+= +)(.+)/ )
+    {
+      $license = $2;
+    }
+  }
+  close( FILE );
+
+  return $license;
+}
+
+sub pkg_short_description
+{
+  my $makefile = shift;
+  my $description;
+
+  open( FILE, "< $makefile" );
+
+  while( <FILE> )
+  {
+    if( /^[A-Z_0-9]*_PKG_SHORT_DESCRIPTION(.+= +)(.+)/ )
+    {
+      $description = $2;
+    }
+  }
+  close( FILE );
+
+  #
+  # In Makefiles we have to mask characters '\', '&', '*', '(', ')' inside
+  # the new value in the assignment operator with backslash. So, for axample,
+  # the value "name & \ * ( ) end" we have to assign as follow
+  #
+  # ..._SHORT_DESCRIPTION = name \& \\ \* \( \) end
+  #
+  # Here we have to remove backslashes and fill escaped symbols as is:
+  #
+  $description =~ s/\\(.?)/$1/g;
+
+  return $description;
+}
+
+
+sub get_treedirs
+{
+  my @list;
+
+  seek( REQUIRES_FILE, 0, SEEK_SET );
+
+  while( <REQUIRES_FILE> )
+  {
+    if( /^TREEDIRS(.+= +)(.+)/ )
+    {
+      @list = split( ' ', $2 );
+    }
+  }
+
+  return @list;
+}
+
+sub get_root
+{
+  my $root;
+
+  seek( REQUIRES_FILE, 0, SEEK_SET );
+
+  while( <REQUIRES_FILE> )
+  {
+    if( /^# ROOT(=)(.+)/ )
+    {
+      $root = $2;
+    }
+  }
+
+  return $root;
+}
+
+sub get_deps
+{
+  my %deps;
+
+  seek( REQUIRES_FILE, 0, SEEK_SET );
+
+  while( <REQUIRES_FILE> )
+  {
+    if( /(.+)(: +)(.+)/ )
+    {
+      $deps{$1} = $3;
+    }
+  }
+  return %deps;
+}
+
+my $root_node = 1;
+
+#
+# PACKAGE HASH:
+# ============
+#
+#   name              => $(PKG_NAME)       from Makefile
+#   version           => $(PKG_VERSION)    from Makefile
+#   group             => $(PKG_GROUP)      from Makefile {app,base,dev,libs,net,...}
+#
+#   arch              => $toolchain        from comandline args
+#   hardware          => $hardware         from comandline args
+#   flavour           => $flavour          from comandline args for ROOT pkg, from REQUIRES for dependencies
+#   tarball           => "$name-$version-$arch-$distro_name-$distro_version.$tarball_suffix"
+#
+#   distro_name       => $(DISTRO_NAME)    from build-system/constants.mk
+#   distro_version    => $(DISTRO_VERSION) from build-system/constants.mk
+#   url               => $(BUG_URL)        from build-system/constants.mk
+#   license           =>                   from Makefile
+#   short_description =>                   from Makefile
+#   description       =>    first line     from .DESCRIPTION
+#   uncompressed_size =>                   from .PKGINFO
+#   total_files       =>                   from .PKGINFO
+#
+#   dir               => path to Makefile  from .$(HW)_requires
+#   children          =>
+#
+sub fill_package_info
+{
+  my $base_dir = shift;
+  my $makefile = shift;
+  my $flavour  = shift;
+  my ( $product_path, $tarball_file );
+  my %pkg;
+
+  $pkg{'dir'}     = $base_dir;
+  $pkg{'install'} = pkg_rootfs_target( $makefile );
+
+  $pkg{'name'} = pkg_name( $makefile );
+  if( $pkg{'name'} eq "" )
+  {
+    # There is no package for this Makefile
+    $pkg{'name'} = $pkg{'dir'};
+    return %pkg;
+  }
+
+  $pkg{'version'}           = pkg_version( $makefile );
+  $pkg{'arch'}              = $toolchain;
+  $pkg{'hardware'}          = $hardware;
+  $pkg{'flavour'}           = $flavour;
+  $pkg{'group'}             = pkg_group( $makefile );
+  $pkg{'distro_name'}       = $distro_name;
+  $pkg{'distro_version'}    = $distro_version;
+  $pkg{'url'}               = $url;
+  $pkg{'license'}           = pkg_license( $makefile );
+  $pkg{'short_description'} = pkg_short_description( $makefile );
+
+  $pkg{'tarball'} = $pkg{'name'}    . "-" . 
+                    $pkg{'version'} . "-" . 
+                    $pkg{'arch'}    . "-" . 
+                    $distro_name    . "-" . 
+                    $distro_version . "." . 
+                    $tarball_suffix;
+
+  return %pkg;
+}
+
+
+
+#
+# Parse the command line options
+#
+
+# Get the rest arguments of the command line
+$topdir    = shift;
+$toolchain = shift;
+$hardware  = shift;
+$flavour   = shift;
+
+my $makefile = "Makefile";
+
+if( ! defined $topdir    or $topdir eq "" )    { usage; }
+if( ! defined $toolchain or $toolchain eq "" ) { usage; }
+if( ! defined $hardware  or $hardware eq "" )  { usage; }
+if( ! defined $flavour   or $flavour eq "" )   { $flavour = ""; }
+
+_kxLab::error( "$0: $topdir is not a directory" ) if( ! -d $topdir );
+_kxLab::error( "$0: Makefile missing: $makefile" ) if ( ! -f $makefile );
+
+$build_system = $topdir . "/build-system";
+
+$system_version = system_version( $build_system );
+$distro_name    = distro_name( $build_system );
+$distro_version = distro_version( $build_system );
+$url            = bug_url( $build_system );
+
+
+if( $flavour eq "" )
+{
+  $target_build_dir  = "." . $toolchain . "/" . $hardware;
+}
+else
+{
+  $target_build_dir  = "." . $toolchain . "/" . $hardware . "/" . $flavour;
+}
+
+$requires_file  = $target_build_dir . "/.requires";
+
+if( $flavour eq "" )
+{
+  $pkglist_file   = $target_build_dir . "/" . $hardware . ".pkglist";
+}
+else
+{
+  $pkglist_file   = $target_build_dir . "/" . $hardware . "-" . $flavour . ".pkglist";
+}
+
+
+# open the intput file
+open(REQUIRES_FILE, "< $requires_file") or
+  _kxLab::error( "$0: Could not open $requires_file file: $!" );
+# open the output files
+open(PKGLIST_FILE, "> $pkglist_file") or
+  _kxLab::error( "$0: Could not open $pkglist_file file: $!" );
+
+
+my $root     = get_root();
+my @treedirs = get_treedirs();
+my %deps     = get_deps();
+
+#
+# This is the root package
+#
+%tree = fill_package_info( $root, $makefile, $flavour );
+
+my %sequence;
+my $order = 0;
+
+#################################################################
+# if( there is any dependencies )
+#
+if( %deps )
+{
+  my @dep_keys = keys %deps;
+
+  my $count = scalar( keys %deps );
+
+  foreach my $dir ( @treedirs )
+  {
+    if( ! grep { $_ eq $dir } @dep_keys )
+    {
+      my $key = $dir;
+      $sequence{$key} = ++$order;
+      @treedirs = grep { $_ ne $key } @treedirs;
+
+      # Split dir^flavour:
+      my ($d, $f);
+      $d = `echo $dir | cut -f 1 -d '^'`;
+      $d =~ s/^\s+|\s+$//;
+      if( $dir =~ m/\^/ )
+      {
+        $f = `echo $dir | cut -f 2 -d '^'`;
+        $f =~ s/^\s+|\s+$//;
+      }
+      else
+      {
+        $f = "";
+      }
+
+      # Insert into sub_trees:
+      my %pkg = fill_package_info( $d, $topdir . "/" . $d . "/Makefile", $f );
+      $sub_trees{$dir} = \%pkg;
+
+      delete $deps{$dir};
+    }
+  }
+
+
+  for( my $i = 0; $i < $count; ++$i )
+  {
+    my @installed = keys %sequence;
+
+    foreach my $key (sort keys %deps)
+    {
+      my $ok = 1;
+      my @dirs = split( ' ', $deps{$key} );
+
+      if( $key ne "all" )
+      {
+        foreach my $dir ( @dirs )
+        {
+          if( ! grep { $_ eq $dir } @installed )
+          {
+            $ok = 0;
+          }
+        }
+
+        if( $ok == 1 )
+        {
+          $sequence{$key} = ++$order;
+
+          # Split dir^flavour:
+          my ($d, $f);
+          $d = `echo $key | cut -f 1 -d '^'`;
+          $d =~ s/^\s+|\s+$//;
+          if( $key =~ m/\^/ )
+          {
+            $f = `echo $key | cut -f 2 -d '^'`;
+            $f =~ s/^\s+|\s+$//;
+          }
+          else
+          {
+            $f = "";
+          }
+
+          # create package node:
+          my %pkg = fill_package_info( $d, $topdir . "/" . $d . "/Makefile", $f );
+          # add children:
+          foreach my $dir ( @dirs )
+          {
+            my $child = $sub_trees{$dir};
+            push( @{$pkg{'children'}}, $child );
+          }
+
+          # insert new sub tree into $sub_tree:
+          $sub_trees{$key} = \%pkg;
+
+          delete $deps{$key};
+        }
+      }
+    }
+  }
+
+  #
+  # The root node children
+  #
+  my @dirs = split( ' ', $deps{'all'} );
+  foreach my $dir ( @dirs )
+  {
+    my $child = $sub_trees{$dir};
+    push( @{$tree{'children'}}, $child );
+  }
+
+}
+else
+{
+  my %pkg;
+
+  $pkg{'dir'}  = "void";
+  $pkg{'name'} = "void";
+
+  push( @{$tree{'children'}}, \%pkg );
+}
+#
+# End if( there is any dependencies )
+#################################################################
+
+
+#################################################################
+# Building Required Packages List:
+#
+sub compare_order
+{
+  $sequence{$a} <=> $sequence{$b};
+}
+
+print PKGLIST_FILE "#\n";
+print PKGLIST_FILE "# file format:\n";
+print PKGLIST_FILE "# ===========\n";
+print PKGLIST_FILE "#\n";
+print PKGLIST_FILE "# Each line contains six fields separated by colon symbol ':' like following.\n";
+print PKGLIST_FILE "#\n";
+print PKGLIST_FILE "# pkgname:version:description:tarball:procedure:priority\n";
+print PKGLIST_FILE "#\n";
+print PKGLIST_FILE "# where:\n";
+print PKGLIST_FILE "#\n";
+print PKGLIST_FILE "#   pkgname     - should be the same as the value of pkgname  in the '.DESCRIPTION' file;\n";
+print PKGLIST_FILE "#   version     - package version for showing in check list  dialog box  if this file is\n";
+print PKGLIST_FILE "#                 used to complete common check dialog for installing group  of packages;\n";
+print PKGLIST_FILE "#   description - short description for showing in check list dialog box if this file is\n";
+print PKGLIST_FILE "#                 used to complete common check dialog for installing  group of packages;\n";
+print PKGLIST_FILE "#   tarball     - should end in '." . $tarball_suffix . "';\n";
+print PKGLIST_FILE "#   procedure   - installation procedure {install | update}:\n";
+print PKGLIST_FILE "#                  * 'install' - if package requires normal installation,\n";
+print PKGLIST_FILE "#                  * 'update'  - if already installed package should be updated by this\n";
+print PKGLIST_FILE "#                                package archive;\n";
+print PKGLIST_FILE "#   priority    - { REQUIRED|RECOMMENDED|OPTIONAL|SKIP }\n";
+print PKGLIST_FILE "#                  synonims:\n";
+print PKGLIST_FILE "#                    { REQUIRED    | required    | REQ | req }\n";
+print PKGLIST_FILE "#                    { RECOMMENDED | recommended | REC | rec }\n";
+print PKGLIST_FILE "#                    { OPTIONAL    | optional    | OPT | opt }\n";
+print PKGLIST_FILE "#                    { SKIP        | skip        | SKP | skp }\n";
+print PKGLIST_FILE "#\n";
+
+
+my $packages_done = 0;
+
+sub print_result
+{
+  my $out_string = sprintf( "####### Packages Install List (done: %4d packages)\n", $packages_done );
+
+  print $out_string;
+}
+
+print "#######\n";
+
+foreach my $dir (sort compare_order( (keys %sequence) ))
+{
+  my $package;
+
+  if( $dir ne "all" )
+  {
+    $package = $sub_trees{$dir};
+    #
+    # Currently gcc-runtime has not ROOTFS_TARGET and not all packages requires GCC.
+    # We will not add GCC in this procedure forcibly. But developers have to care about
+    # competing packages GCC and gcc-runtime.
+    #
+    if( $package->{'install'} ne "no" )
+    {
+      if( $package->{'flavour'} eq "" )
+      {
+        print PKGLIST_FILE $package->{'name'}              . ":" .
+                           $package->{'version'}           . ":" .
+                           $package->{'short_description'} . ":" .
+                           $package->{'group'}             . "/" .
+                           $package->{'tarball'}           . ":" .
+                           $package->{'install'}           . ":REQUIRED\n";
+      }
+      else
+      {
+        print PKGLIST_FILE $package->{'name'}              . ":" .
+                           $package->{'version'}           . ":" .
+                           $package->{'short_description'} . ":" .
+                           $package->{'group'}             . "/" .
+                           $package->{'flavour'}           . "/" .
+                           $package->{'tarball'}           . ":" .
+                           $package->{'install'}           .  ":REQUIRED\n";
+      }
+      ++$packages_done;
+    }
+  }
+}
+
+if( $tree{'install'} ne "no" )
+{
+  if( $tree{'flavour'} eq "" )
+  {
+    print PKGLIST_FILE $tree{'name'}              . ":" .
+                       $tree{'version'}           . ":" .
+                       $tree{'short_description'} . ":" .
+                       $tree{'group'}             . "/" .
+                       $tree{'tarball'}           . ":" .
+                       $tree{'install'}           . ":REQUIRED\n";
+  }
+  else
+  {
+    print PKGLIST_FILE $tree{'name'}              . ":" .
+                       $tree{'version'}           . ":" .
+                       $tree{'short_description'} . ":" .
+                       $tree{'group'}             . "/" .
+                       $tree{'flavour'}           . "/" .
+                       $tree{'tarball'}           . ":" .
+                       $tree{'install'}           .  ":REQUIRED\n";
+  }
+  ++$packages_done;
+}
+
+print_result();
+print "#######\n";
+#
+# End of Building Required Packages List.
+#################################################################
+
+# close input files
+close REQUIRES_FILE;
+# close output files
+close PKGLIST_FILE;

Property changes on: build_packages_list
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property