Created
September 22, 2018 08:50
-
-
Save nkh/5e9ac3a486df785f2c581a9f58d5c8ea to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use File::Slurp ; | |
use File::Path ; | |
use PBS::Rules::Builders ; | |
use POSIX qw(strftime); | |
#------------------------------------------------------------------------------- | |
# C depender for object files (not part of the core pbs but distributed with it) | |
# old C depender: | |
# created dependency files during the depend step | |
# handled a complex cache creation and verification | |
# had for goal to present a complete dependency graph before the build | |
# | |
# some points were good enough but "wrong", dependencies belonged to the | |
# C file except one could not do variant nodes on the fly, that was | |
# a goal for pbs but not implemented, in a way the depender was too advanced | |
# | |
# the dependencies were computed sequentially | |
# the new depender: | |
# creates dependency files during the build and in a post build step | |
# | |
# this the following advantages: | |
# | |
# very little code specific to the depender, this sub,read_dependencies_cache and two rules | |
# | |
# the cache code is much simpler and most is handled by the pbs core mechanism | |
# | |
# builds are triggered properly if no dependency cache is found but the cache generation | |
# is handled by the compiler, in gcc example, as a side effect of the build | |
# | |
# No need to wait for the dependency of all the C files, starts building directly | |
# | |
# the cache is generated in parallel, if the build is done with -j option | |
# | |
# the dependencies are merged back to the graph in a post build step, this is necessary | |
# as the nodes are build in separate processes that do not share the graph | |
# | |
# each node is responsible for integrating its dependencies, this means that the mechanism | |
# is open for other types of nodes not just object files dependencies | |
# | |
# the cache is specific for the object node even if they share C nodes, no more configuration | |
# dependencies for the dependency cache, it's just a list of source header files | |
# | |
# warp, pre and post-build, is handled properly as object nodes regenerate their digest and the | |
# digest of their dependencies after the build | |
# | |
# in case a dependency cache is invalid, its contents are not added to the pre-build warp file, | |
# insuring validity of the warp cache which would retrigger the dependency step if necessary | |
# | |
# it's one tenth of the old code size | |
my $cache_header = "C dependencies PBS generated at " ; | |
my $cache_footer = 'END C dependencies PBS' ; | |
#------------------------------------------------------------------------------- | |
sub read_dependencies_cache | |
{ | |
my (undef, undef, $tree) = @_ ; | |
my $file_to_build = $tree->{__BUILD_NAME} || PBS::Rules::Builders::GetBuildName($tree->{__NAME}, $tree) ; | |
my $dependency_file = "$file_to_build.dependencies" ; | |
my @node_dependencies = ($dependency_file) ; # worse case: the non valid dependency cache | |
my @dependencies_cache ; | |
if | |
( | |
( -e $file_to_build && -e $dependency_file) | |
&& ( @dependencies_cache = read_file($dependency_file, chomp => 1) ) | |
&& ( $dependencies_cache[0] =~ /^$cache_header/ && $dependencies_cache[-1] =~ /^$cache_footer/ ) | |
) | |
{ | |
# valid cache, remove header and footer | |
shift @dependencies_cache ; pop @dependencies_cache ; | |
# use the cache, unless it points to a non-existing header files | |
@node_dependencies = @dependencies_cache | |
unless grep { ! -e $_ } @dependencies_cache ; | |
} | |
$tree->{__PBS_POST_BUILD} = \&InsertDependencyNodes ; | |
return [1, @node_dependencies] ; # triggered | |
} | |
#------------------------------------------------------------------------------- | |
sub InsertDependencyNodes | |
{ | |
my ($node, $inserted_nodes) = @_ ; | |
return unless exists $node->{__BUILD_DONE} ; | |
my $build_name = $node->{__BUILD_NAME} ; | |
my $dependency_file = "$build_name.dependencies" ; # was generated by compiler | |
use File::Slurp ; | |
my $o_dependencies = read_file $dependency_file ; | |
$o_dependencies =~ s/^.*:\s+// ; | |
$o_dependencies =~ s/\\/ /g ; | |
$o_dependencies =~ s/\n/:/g ; | |
$o_dependencies =~ s/\s+/:/g ; | |
my %dependencies = map { $_ => 1 } grep { /\.h$/ } split(/:+/, $o_dependencies) ; | |
my @dependencies = sort map { $_ = "./$_" unless (/^\// || /^\.\//); $_} keys %dependencies ; | |
my $now = strftime "%a %b %e %H:%M:%S %Y", gmtime; | |
my $cache = $cache_header . __FILE__ . ':' . __LINE__ . " $now\n" ; | |
my $insertion_data = | |
{ | |
INSERTING_NODE => $node->{__NAME}, | |
INSERTION_RULE => 'c_depender', | |
INSERTION_FILE => __FILE__ . ':' . __LINE__, | |
INSERTION_PACKAGE=> 'NA', | |
INSERTION_TIME => Time::HiRes::time, | |
} ; | |
for my $d (@dependencies, $dependency_file) | |
{ | |
$cache .= "$d\n" ; | |
if(exists $inserted_nodes->{$d}) | |
{ | |
$node->{$d}{__MD5} = GetFileMD5($d) ; | |
$node->{$d} = $inserted_nodes->{$d} ; | |
} | |
else | |
{ | |
$inserted_nodes->{$d} = $node->{$d} = | |
{ | |
__NAME => $d, | |
__BUILD_NAME => $d, | |
__BUILD_DONE => 1, | |
__INSERTED_AT => $insertion_data, | |
__PBS_CONFIG => $node->{__PBS_CONFIG}, | |
__LOAD_PACKAGE => $node->{__LOAD_PACKAGE}, | |
__MD5 => GetFileMD5($d), | |
} ; | |
} | |
} | |
$cache .= "$cache_footer\n" ; | |
write_file $dependency_file, $cache ; | |
# make sure object file digest doesn't use the temporary dependency file hash | |
PBS::Digest::FlushMd5Cache($dependency_file) ; | |
$inserted_nodes->{$dependency_file}{__MD5} = GetFileMD5($dependency_file) ; | |
# regenerate our own digest | |
eval { PBS::Digest::GenerateNodeDigest($node) } ; | |
die "Error Generating node digest: $@\n" if $@ ; | |
} | |
#------------------------------------------------------------------------------- | |
1 ; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment