New URL for NEMO forge!   http://forge.nemo-ocean.eu

Since March 2022 along with NEMO 4.2 release, the code development moved to a self-hosted GitLab.
This present forge is now archived and remained online for history.
Link.pm in vendors/lib/FCM/System/Make/Build/Task – NEMO

source: vendors/lib/FCM/System/Make/Build/Task/Link.pm @ 10669

Last change on this file since 10669 was 10669, checked in by nicolasmartin, 5 years ago

Import latest FCM release from Github into the repository for testing

File size: 6.2 KB
Line 
1# ------------------------------------------------------------------------------
2# (C) British Crown Copyright 2006-17 Met Office.
3#
4# This file is part of FCM, tools for managing and building source code.
5#
6# FCM is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# FCM is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with FCM. If not, see <http://www.gnu.org/licenses/>.
18# ------------------------------------------------------------------------------
19use strict;
20use warnings;
21# ------------------------------------------------------------------------------
22package FCM::System::Make::Build::Task::Link;
23use base qw{FCM::Class::CODE};
24
25use FCM::Context::Event;
26use FCM::System::Exception;
27use FCM::System::Make::Build::Task::Archive;
28use FCM::System::Make::Build::Task::Share qw{_props_to_opts};
29use File::Basename qw{basename};
30use File::Path qw{mkpath rmtree};
31use File::Spec::Functions qw{abs2rel catfile};
32use File::Temp qw{tempdir};
33use List::Util qw{first};
34use Text::ParseWords qw{shellwords};
35
36my $E = 'FCM::System::Exception';
37
38our %PROP_OF = (
39    %FCM::System::Make::Build::Task::Archive::PROP_OF,
40    'ld' => '',
41    'link-without-ar' => '',
42    'keep-lib-o' => '',
43);
44
45__PACKAGE__->class(
46    {name => '$', prop_of => '%', util => '&'},
47    {action_of => {main => \&_main, prop_of => sub {$_[0]->{prop_of}}}},
48);
49
50sub _main {
51    my ($attrib_ref, $target) = @_;
52    my $NAME  = $attrib_ref->{name};
53    my $P     = sub {$target->get_prop_of($_[0])};
54    # Selects the correct dependent objects
55    my @paths = @{$target->get_info_of('paths')};
56    my %dep_keys_of = %{$target->get_info_of('deps')};
57    my %paths_of = (o => [], 'o.special' => []);
58    my $abs2rel_func
59        = sub {index($_[0], $paths[0]) == 0 ? abs2rel($_[0], $paths[0]) : $_[0]};
60    while (my ($type, $key_list_ref) = each(%dep_keys_of)) {
61        for my $key (@{$key_list_ref}) {
62            my $path = first {-e} map {catfile($_, 'o', $key)} @paths;
63            if ($path) {
64                push(@{$paths_of{$type}}, $abs2rel_func->($path));
65            }
66        }
67    }
68    my $path_of_main_o = shift(@{$paths_of{o}});
69    my @command_list_refs;
70    my %opt_of = (
71        o => $P->($NAME . '.flag-output'),
72        L => $P->($NAME . '.flag-lib-path'),
73        l => $P->($NAME . '.flag-lib'),
74    );
75    # Create an intermediate archive library
76    # (when linking multiple objects and "link-without-ar" is not set)
77    my $link_with_ar = @{$paths_of{o}} && !$P->('link-without-ar');
78    my ($keep_lib_o, $lib_o_dir, $lib_o, @o_args);
79    if ($link_with_ar) {
80        # Archive (when linking multiple objects)
81        $keep_lib_o = $P->('keep-lib-o');
82        if ($keep_lib_o) {
83            $lib_o_dir = $target->CT_LIB;
84            mkpath($lib_o_dir);
85        }
86        else {
87            $lib_o_dir = tempdir(CLEANUP => 1);
88        }
89        my $root = (
90            $attrib_ref->{util}->file_ext(basename($target->get_key())))[1];
91        $lib_o = catfile($lib_o_dir, "lib$root.a");
92        push(@command_list_refs, [
93            shellwords($P->('ar')),
94            shellwords($P->('ar.flags')),
95            $lib_o,
96            @{$paths_of{o}},
97        ]);
98        @o_args = (
99            _props_to_opts($opt_of{L}, $lib_o_dir),
100            _props_to_opts($opt_of{l}, $root),
101        );
102    }
103    else {
104        @o_args = @{$paths_of{o}};
105    }
106    # Link
107    push(@command_list_refs, [
108        ($P->('ld') ? shellwords($P->('ld')) : shellwords($P->($NAME))),
109        _props_to_opts($opt_of{o}, $abs2rel_func->($target->get_path())),
110        $path_of_main_o,
111        @{$paths_of{'o.special'}},
112        @o_args,
113        _props_to_opts($opt_of{L}, shellwords($P->($NAME .  '.lib-paths'))),
114        _props_to_opts($opt_of{l}, shellwords($P->($NAME .  '.libs'))),
115        shellwords($P->($NAME . '.flag-omp')),
116        shellwords($P->($NAME . '.flags-ld')),
117    ]);
118    for my $command_list_ref (@command_list_refs) {
119        my %value_of = %{$attrib_ref->{util}->shell_simple($command_list_ref)};
120        if ($value_of{rc}) {
121            return $E->throw(
122                $E->SHELL,
123                {command_list => $command_list_ref, %value_of},
124                $value_of{e},
125            );
126        }
127        $attrib_ref->{util}->event(
128            FCM::Context::Event->MAKE_BUILD_SHELL_OUT, @value_of{qw{o e}},
129        );
130    }
131    if ($link_with_ar && !$keep_lib_o) {
132        unlink($lib_o);
133        rmtree($lib_o_dir);
134    }
135    $target;
136}
137
138# ------------------------------------------------------------------------------
1391;
140__END__
141
142=head1 NAME
143
144FCM::System::Make::Build::Task::Link
145
146=head1 SYNOPSIS
147
148    use FCM::System::Make::Build::Task::Link;
149    my $build_task = FCM::System::Make::Build::Task::Link->new(\%attrib);
150    $build_task->main($target);
151
152=head1 DESCRIPTION
153
154Invokes the linker to create the target executable.
155
156=head1 METHODS
157
158=over 4
159
160=item $class->new(\%attrib)
161
162Creates and returns a new instance. %attrib should contain:
163
164=over 4
165
166=item {name}
167
168The property name of the linker.
169
170=item {prop_of}
171
172A HASH to map the property names (used by this task) to their default values.
173
174=item {util}
175
176An instance of L<FCM::Util|FCM::Util>.
177
178=back
179
180=item $instance->main($target)
181
182Invokes the linker to create the $target executable. It uses the
183$target->get_info_of('deps')->{o} ARRAY and
184$target->get_info_of('deps')->{"o.special"} ARRAY as dependencies. The first
185type "o" dependency item is expected to be the object file containing the main
186program. All other "o" dependency items are placed in a temporary archive
187before invoking the linker command. The main object and "o.special" dependency
188items are entered into the command line of the linker to produce the
189executable.
190
191=item $instance->prop_of()
192
193Returns the HASH that maps the property names (used by this task) to their
194default values.
195
196=back
197
198=head1 COPYRIGHT
199
200(C) Crown copyright Met Office. All rights reserved.
201
202=cut
Note: See TracBrowser for help on using the repository browser.