Skip to content

Commit

Permalink
Merge pull request #197 from matthewrmshin/fcm-make-build-target-select
Browse files Browse the repository at this point in the history
fcm make: build: fix target select modifier
  • Loading branch information
benfitzpatrick committed Jul 3, 2015
2 parents d96faff + 982efa8 commit 393ad3e
Show file tree
Hide file tree
Showing 10 changed files with 204 additions and 43 deletions.
16 changes: 10 additions & 6 deletions doc/user_guide/annex_cfg.html
Original file line number Diff line number Diff line change
Expand Up @@ -897,20 +897,24 @@ <h3 id="make.build">FCM Make Configuration: Build</h3>

<dd>
<p><dfn>description</dfn>: Selects targets to build according to their
keys, categories, name-spaces and tasks.</p>
keys, categories and tasks.</p>

<p><dfn>modifier</dfn>: <samp>key</samp> (default if no modifier
specified), <samp>category</samp>, <samp>ns</samp> (i.e. name-space) or
<samp>task</samp></p>
specified), <samp>category</samp> or <samp>task</samp></p>

<p><dfn>namespace</dfn>: Not allowed if modifier is <samp>key</samp>.
Optional if modifier is <samp>category</samp> or <samp>task</samp>. If
specified, setting only applies to given name-spaces. Otherwise, setting
applies to all name-spaces.</p>

<p><dfn>value</dfn>: A list of space-delimited items (according to the
modifier).</p>

<p><dfn>example</dfn>:</p>
<pre>
build.target{category} = bin lib
build.target{ns} = egg/fried ham
build.target{task} = archive install link
build.target{category}[etc/namelists etc/configs] = etc
build.target{category}[src/hello src/greet src/world] = bin lib
build.target{task}[src/public] = archive install
build.target = egg.sh mince.py
</pre>
</dd>
Expand Down
23 changes: 14 additions & 9 deletions doc/user_guide/make.html
Original file line number Diff line number Diff line change
Expand Up @@ -1742,16 +1742,20 @@ <h3 id="build.target-selection">Build Targets Selection and Rename</h3>
you to select targets according to their categories, source name-spaces,
tasks and keys. The logic is demonstrated by the following example:</p>
<pre>
# Selects targets matching these keys
# Select targets matching these keys
build.target = egg.bin ham.o bacon.sh
# OR (
# those doing these tasks

# Select all targets doing tasks "install" or "link"
build.target{task} = install link
# AND in these categories

# Select targets in name-space "foo" or "bar" doing tasks "link"
build.target{task}[foo bar] = link

# Select all targets in the "bin" category
build.target{category} = bin
# AND in these name-spaces
build.target{ns} = foo bar/baz
# )

# Select targets in name-space "foo" in the "etc" category
build.target{category}[foo] = etc
</pre>

<p>There are times when an automatic target name is not what you want. In
Expand Down Expand Up @@ -2193,8 +2197,10 @@ <h3 id="preprocess.basic">Preprocess: Basic</h3>

# ... some extract configuration

# Switch off preprocessing for all
preprocess.target{task} =
# Only preprocess source files in these name-spaces
preprocess.target{ns} = foo/bar egg/fried.F90
preprocess.target{task}[foo/bar egg/fried.F90] = process
# Specifies the macro definitions for the Fortran preprocessor
preprocess.prop{fpp.defs} = THING=stuff HIGH=tall
# Specifies the macro definitions for the C preprocessor
Expand Down Expand Up @@ -2268,7 +2274,6 @@ <h3 id="preprocess.target-source">Preprocess Targets from Source Files</h3>
preprocess.target =
preprocess.target{task} = process
preprocess.target{category} =
preprocess.target{ns} =
</pre>

<p>Here is a list of what targets are available for each type of file:</p>
Expand Down
87 changes: 60 additions & 27 deletions lib/FCM/System/Make/Build.pm
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ our @FILE_TYPE_UTILS = (
);

# Default target selection
our %TARGET_SELECT_BY = (task => {});
our %TARGET_SELECT_BY = (
'category' => {},
'key' => {},
'task' => {},
);

# Configuration parser label to action map
our %CONFIG_PARSER_OF = (
Expand Down Expand Up @@ -181,8 +185,16 @@ sub _config_parse_inherit_hook {
while (my ($key, $value) = each(%{$i_ctx->get_target_key_of()})) {
$ctx->get_target_key_of()->{$key} = $value;
}
while (my ($key, $value) = each(%{$i_ctx->get_target_select_by()})) {
$ctx->get_target_select_by()->{$key} = dclone($value);
while (my ($key, $item_ref) = each(%{$i_ctx->get_target_select_by()})) {
while (my ($key2, $attr_set) = each(%{$item_ref})) {
if (ref($attr_set)) {
$ctx->get_target_select_by()->{$key}{$key2} = {%{$attr_set}};
}
else {
# Backward compat, $key2 is an $attr
$ctx->get_target_select_by()->{$key}{q{}}{$key2} = 1;
}
}
}
_config_parse_inherit_hook_prop($attrib_ref, $ctx, $i_ctx);
}
Expand Down Expand Up @@ -211,15 +223,24 @@ sub _config_parse_source {
sub _config_parse_target {
my ($attrib_ref, $ctx, $entry) = @_;
my %modifier_of = %{$entry->get_modifier_of()};
if (!keys(%modifier_of)) {
if (!(%modifier_of)) {
%modifier_of = (key => 1);
}
my @ns_list = map {$_ eq q{/} ? q{} : $_} @{$entry->get_ns_list()};
if (exists($modifier_of{'key'}) && grep {$_} @ns_list) {
return $E->throw($E->CONFIG_NS, $entry);
}
if (!@ns_list) {
@ns_list = (q{});
}
while (my $name = each(%modifier_of)) {
if (!grep {$_ eq $name} qw{category key ns task}) {
if (!grep {$_ eq $name} qw{category key task}) {
return $E->throw($E->CONFIG_MODIFIER, $entry);
}
$ctx->get_target_select_by()->{$name}
= {map {$_ eq q{/} ? (q{} => 1) : ($_ => 1)} $entry->get_values()};
my %attr_set = map {($_ => 1)} $entry->get_values();
for my $ns (@ns_list) {
$ctx->get_target_select_by()->{$name}{$ns} = \%attr_set;
}
}
}

Expand Down Expand Up @@ -282,13 +303,20 @@ sub _config_unparse {
: ()
),
( map {
FCM::Context::ConfigEntry->new({
label => $LABEL_OF{'target'},
modifier_of => {$_ => 1},
value => _config_unparse_join(
keys(%{$ctx->get_target_select_by()->{$_}}),
),
});
my $modifier = $_;
map {
my $ns = $_;
my @values = sort(keys(
%{$ctx->get_target_select_by()->{$modifier}{$ns}}
));
FCM::Context::ConfigEntry->new({
label => $LABEL_OF{'target'},
modifier_of => {$modifier => 1},
ns_list => [$ns],
value => _config_unparse_join(@values),
});
}
sort keys(%{$ctx->get_target_select_by()->{$modifier}});
}
sort keys(%{$ctx->get_target_select_by()})
),
Expand Down Expand Up @@ -1035,18 +1063,23 @@ sub _targets_select {
my %target_set;
my %has_ns_in; # available sets of name-spaces
for my $target (@{$targets_ref}) {
if ( exists($select_by{key}{$target->get_key()})
|| ( !exists($select_by{category})
|| exists($select_by{category}{$target->get_category()})
)
&& ( !exists($select_by{task})
|| exists($select_by{task}{$target->get_task()})
)
&& ( !exists($select_by{ns})
|| $UTIL->ns_in_set($target->get_ns(), $select_by{ns})
)
ATTR_NAME:
for (
#$attr_name, $attr_func
['key' , sub {$_[0]->get_key()}],
['category', sub {$_[0]->get_category()}],
['task' , sub {$_[0]->get_task()}],
) {
$target_set{$target->get_key()} = 1;
my ($attr_name, $attr_func) = @{$_};
for my $ns (sort keys(%{$select_by{$attr_name}})) {
my %attr_set = %{$select_by{$attr_name}->{$ns}};
if ( exists($attr_set{$attr_func->($target)})
&& (!$ns || $UTIL->ns_in_set($target->get_ns(), {$ns => 1}))
) {
$target_set{$target->get_key()} = 1;
last ATTR_NAME;
}
}
}
if (exists($target_of{$target->get_key()})) {
if (!exists($targets_of{$target->get_key()})) {
Expand Down Expand Up @@ -1250,8 +1283,8 @@ sub _targets_select {
if (keys(%missing_deps_in)) {
return $E->throw($E->BUILD_TARGET_DEP, \%missing_deps_in);
}
if (exists($select_by{key})) {
my @bad_keys = grep {!exists($state_of{$_})} keys(%{$select_by{key}});
if (exists($select_by{key}{q{}})) {
my @bad_keys = grep {!exists($state_of{$_})} keys(%{$select_by{key}{q{}}});
if (@bad_keys) {
return $E->throw($E->BUILD_TARGET_BAD, \@bad_keys);
}
Expand Down
6 changes: 5 additions & 1 deletion lib/FCM/System/Make/Preprocess.pm
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ use FCM::System::Make::Build::FileType::FPP;
use FCM::System::Make::Build::FileType::H ;

# Default target selection
our %TARGET_SELECT_BY = (task => {'process' => 1});
our %TARGET_SELECT_BY = (
'category' => {},
'key' => {},
'task' => {q{} => {'process' => 1}},
);

# Classes for working with typed source files
our @FILE_TYPE_UTILS = (
Expand Down
93 changes: 93 additions & 0 deletions t/fcm-make/47-build-target-modifier-ns.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/bin/bash
#-------------------------------------------------------------------------------
# (C) British Crown Copyright 2006-15 Met Office.
#
# This file is part of FCM, tools for managing and building source code.
#
# FCM is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# FCM is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with FCM. If not, see <http://www.gnu.org/licenses/>.
#-------------------------------------------------------------------------------
# Test "fcm make", build.target{category} and build.target{task} with namespace.
#-------------------------------------------------------------------------------
. "$(dirname "$0")/test_header"
#-------------------------------------------------------------------------------
tests 12
mkdir 'i0'
cp -r "${TEST_SOURCE_DIR}/${TEST_KEY_BASE}/"* 'i0'
#-------------------------------------------------------------------------------
TEST_KEY="${TEST_KEY_BASE}"
run_pass "${TEST_KEY}" fcm make -C 'i0'

grep -F 'build.target{category}' 'i0/.fcm-make/config-on-success.cfg' \
>'edited-config-on-success.cfg'
file_cmp "${TEST_KEY}-edited-config-on-success.cfg" \
'edited-config-on-success.cfg' <<'__CFG__'
build.target{category}[hello] = bin
__CFG__

find 'i0/build' -type f | sort >'find-i0-build.out'
file_cmp "${TEST_KEY}-find-i0-build.out" 'find-i0-build.out' <<'__FIND__'
i0/build/bin/hello
i0/build/o/hello.o
__FIND__

"${PWD}/i0/build/bin/hello" <<<'&world_nl /' >'hello.out'
file_cmp "${TEST_KEY}-hello.out" 'hello.out' <<<'Hello World'
#-------------------------------------------------------------------------------
TEST_KEY="${TEST_KEY_BASE}-inherit"
run_pass "${TEST_KEY}" fcm make -C 'i1' \
"use=${PWD}/i0" \
'build.target{category}[greet] = etc'

grep -F 'build.target{category}' 'i1/.fcm-make/config-on-success.cfg' \
>'edited-config-on-success.cfg'
file_cmp "${TEST_KEY}-edited-config-on-success.cfg" \
'edited-config-on-success.cfg' <<'__CFG__'
build.target{category}[greet] = etc
build.target{category}[hello] = bin
__CFG__

find 'i1/build' -type f | sort >'find-i1-build.out'
file_cmp "${TEST_KEY}-find-i1-build.out" 'find-i1-build.out' <<'__FIND__'
i1/build/bin/hello
i1/build/etc/greet/.etc
i1/build/etc/greet/world.nl
__FIND__

"${PWD}/i1/build/bin/hello" <'i1/build/etc/greet/world.nl' >'hello.out'
file_cmp "${TEST_KEY}-hello.out" 'hello.out' <<<'Hello Earth'
#-------------------------------------------------------------------------------
TEST_KEY="${TEST_KEY_BASE}-inherit-incr"
touch 'before'
run_pass "${TEST_KEY}" fcm make -C 'i1' \
"use=${PWD}/i0" \
'build.target{category}[greet] = bin etc'

grep -F 'build.target{category}' 'i1/.fcm-make/config-on-success.cfg' \
>'edited-config-on-success.cfg'
file_cmp "${TEST_KEY}-edited-config-on-success.cfg" \
'edited-config-on-success.cfg' <<'__CFG__'
build.target{category}[greet] = bin etc
build.target{category}[hello] = bin
__CFG__

find 'i1/build' -type f -newer 'before' | sort >'find-i1-build.out'
file_cmp "${TEST_KEY}-find-i1-build.out" 'find-i1-build.out' <<'__FIND__'
i1/build/bin/greet
i1/build/o/greet.o
__FIND__

"${PWD}/i1/build/bin/greet" <'i1/build/etc/greet/world.nl' >'greet.out'
file_cmp "${TEST_KEY}-greet.out" 'greet.out' <<<'Greet Earth'
#-------------------------------------------------------------------------------
exit 0
4 changes: 4 additions & 0 deletions t/fcm-make/47-build-target-modifier-ns/fcm-make.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
steps=build
build.source=$HERE/src
build.prop{file-ext.bin}=
build.target{category}[hello] = bin
6 changes: 6 additions & 0 deletions t/fcm-make/47-build-target-modifier-ns/src/greet/greet.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
program greet
character(31) :: world = 'World'
namelist /world_nl/ world
read(*, nml=world_nl)
write(*, '(a,1x,a)') 'Greet', trim(world)
end program greet
3 changes: 3 additions & 0 deletions t/fcm-make/47-build-target-modifier-ns/src/greet/world.nl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
&world_nl
world='Earth',
/
6 changes: 6 additions & 0 deletions t/fcm-make/47-build-target-modifier-ns/src/hello/hello.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
program hello
character(31) :: world = 'World'
namelist /world_nl/ world
read(*, nml=world_nl)
write(*, '(a,1x,a)') 'Hello', trim(world)
end program hello
3 changes: 3 additions & 0 deletions t/fcm-make/47-build-target-modifier-ns/src/hello/world.nl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
&world_nl
world='Jupiter',
/

0 comments on commit 393ad3e

Please sign in to comment.