Dpkg::BuildFlags: Add missing feature area to is_maintainer_modified() POD
[dpkg.git] / scripts / Dpkg / BuildFlags.pm
blob3000a73f5dd844c711ee1e56a1c05e80dfa4ffa2
1 # Copyright © 2010-2011 Raphaël Hertzog <hertzog@debian.org>
2 # Copyright © 2012-2022 Guillem Jover <guillem@debian.org>
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <https://www.gnu.org/licenses/>.
17 package Dpkg::BuildFlags;
19 use strict;
20 use warnings;
22 our $VERSION = '1.05';
24 use Dpkg ();
25 use Dpkg::Gettext;
26 use Dpkg::Build::Env;
27 use Dpkg::ErrorHandling;
28 use Dpkg::Vendor qw(run_vendor_hook);
30 =encoding utf8
32 =head1 NAME
34 Dpkg::BuildFlags - query build flags
36 =head1 DESCRIPTION
38 This class is used by dpkg-buildflags and can be used
39 to query the same information.
41 =head1 METHODS
43 =over 4
45 =item $bf = Dpkg::BuildFlags->new()
47 Create a new Dpkg::BuildFlags object. It will be initialized based
48 on the value of several configuration files and environment variables.
50 If the option B<vendor_defaults> is set to false, then no vendor defaults are
51 initialized (it defaults to true).
53 =cut
55 sub new {
56 my ($this, %opts) = @_;
57 my $class = ref($this) || $this;
59 my $self = {
61 bless $self, $class;
63 $opts{vendor_defaults} //= 1;
65 if ($opts{vendor_defaults}) {
66 $self->load_vendor_defaults();
67 } else {
68 $self->_init_vendor_defaults();
70 return $self;
73 sub _init_vendor_defaults {
74 my $self = shift;
76 $self->{features} = {};
77 $self->{optvals} = {};
78 $self->{flags} = {
79 ASFLAGS => '',
80 CPPFLAGS => '',
81 CFLAGS => '',
82 CXXFLAGS => '',
83 OBJCFLAGS => '',
84 OBJCXXFLAGS => '',
85 GCJFLAGS => '',
86 DFLAGS => '',
87 FFLAGS => '',
88 FCFLAGS => '',
89 LDFLAGS => '',
91 $self->{origin} = {
92 ASFLAGS => 'vendor',
93 CPPFLAGS => 'vendor',
94 CFLAGS => 'vendor',
95 CXXFLAGS => 'vendor',
96 OBJCFLAGS => 'vendor',
97 OBJCXXFLAGS => 'vendor',
98 GCJFLAGS => 'vendor',
99 DFLAGS => 'vendor',
100 FFLAGS => 'vendor',
101 FCFLAGS => 'vendor',
102 LDFLAGS => 'vendor',
104 $self->{maintainer} = {
105 ASFLAGS => 0,
106 CPPFLAGS => 0,
107 CFLAGS => 0,
108 CXXFLAGS => 0,
109 OBJCFLAGS => 0,
110 OBJCXXFLAGS => 0,
111 GCJFLAGS => 0,
112 DFLAGS => 0,
113 FFLAGS => 0,
114 FCFLAGS => 0,
115 LDFLAGS => 0,
119 =item $bf->load_vendor_defaults()
121 Reset the flags stored to the default set provided by the vendor.
123 =cut
125 sub load_vendor_defaults {
126 my $self = shift;
128 $self->_init_vendor_defaults();
130 # The vendor hook will add the feature areas build flags.
131 run_vendor_hook('update-buildflags', $self);
134 =item $bf->load_system_config()
136 Update flags from the system configuration.
138 =cut
140 sub load_system_config {
141 my $self = shift;
143 $self->update_from_conffile("$Dpkg::CONFDIR/buildflags.conf", 'system');
146 =item $bf->load_user_config()
148 Update flags from the user configuration.
150 =cut
152 sub load_user_config {
153 my $self = shift;
155 my $confdir = $ENV{XDG_CONFIG_HOME};
156 $confdir ||= $ENV{HOME} . '/.config' if length $ENV{HOME};
157 if (length $confdir) {
158 $self->update_from_conffile("$confdir/dpkg/buildflags.conf", 'user');
162 =item $bf->load_environment_config()
164 Update flags based on user directives stored in the environment. See
165 dpkg-buildflags(1) for details.
167 =cut
169 sub load_environment_config {
170 my $self = shift;
172 foreach my $flag (keys %{$self->{flags}}) {
173 my $envvar = 'DEB_' . $flag . '_SET';
174 if (Dpkg::Build::Env::has($envvar)) {
175 $self->set($flag, Dpkg::Build::Env::get($envvar), 'env');
177 $envvar = 'DEB_' . $flag . '_STRIP';
178 if (Dpkg::Build::Env::has($envvar)) {
179 $self->strip($flag, Dpkg::Build::Env::get($envvar), 'env');
181 $envvar = 'DEB_' . $flag . '_APPEND';
182 if (Dpkg::Build::Env::has($envvar)) {
183 $self->append($flag, Dpkg::Build::Env::get($envvar), 'env');
185 $envvar = 'DEB_' . $flag . '_PREPEND';
186 if (Dpkg::Build::Env::has($envvar)) {
187 $self->prepend($flag, Dpkg::Build::Env::get($envvar), 'env');
192 =item $bf->load_maintainer_config()
194 Update flags based on maintainer directives stored in the environment. See
195 dpkg-buildflags(1) for details.
197 =cut
199 sub load_maintainer_config {
200 my $self = shift;
202 foreach my $flag (keys %{$self->{flags}}) {
203 my $envvar = 'DEB_' . $flag . '_MAINT_SET';
204 if (Dpkg::Build::Env::has($envvar)) {
205 $self->set($flag, Dpkg::Build::Env::get($envvar), undef, 1);
207 $envvar = 'DEB_' . $flag . '_MAINT_STRIP';
208 if (Dpkg::Build::Env::has($envvar)) {
209 $self->strip($flag, Dpkg::Build::Env::get($envvar), undef, 1);
211 $envvar = 'DEB_' . $flag . '_MAINT_APPEND';
212 if (Dpkg::Build::Env::has($envvar)) {
213 $self->append($flag, Dpkg::Build::Env::get($envvar), undef, 1);
215 $envvar = 'DEB_' . $flag . '_MAINT_PREPEND';
216 if (Dpkg::Build::Env::has($envvar)) {
217 $self->prepend($flag, Dpkg::Build::Env::get($envvar), undef, 1);
223 =item $bf->load_config()
225 Call successively load_system_config(), load_user_config(),
226 load_environment_config() and load_maintainer_config() to update the
227 default build flags defined by the vendor.
229 =cut
231 sub load_config {
232 my $self = shift;
234 $self->load_system_config();
235 $self->load_user_config();
236 $self->load_environment_config();
237 $self->load_maintainer_config();
240 =item $bf->unset($flag)
242 Unset the build flag $flag, so that it will not be known anymore.
244 =cut
246 sub unset {
247 my ($self, $flag) = @_;
249 delete $self->{flags}->{$flag};
250 delete $self->{origin}->{$flag};
251 delete $self->{maintainer}->{$flag};
254 =item $bf->set($flag, $value, $source, $maint)
256 Update the build flag $flag with value $value and record its origin as
257 $source (if defined). Record it as maintainer modified if $maint is
258 defined and true.
260 =cut
262 sub set {
263 my ($self, $flag, $value, $src, $maint) = @_;
264 $self->{flags}->{$flag} = $value;
265 $self->{origin}->{$flag} = $src if defined $src;
266 $self->{maintainer}->{$flag} = $maint if $maint;
269 =item $bf->set_feature($area, $feature, $enabled)
271 Update the boolean state of whether a specific feature within a known
272 feature area has been enabled. The only currently known feature areas
273 are "future", "qa", "sanitize", "optimize", "hardening" and "reproducible".
275 =cut
277 sub set_feature {
278 my ($self, $area, $feature, $enabled) = @_;
279 $self->{features}{$area}{$feature} = $enabled;
282 =item $bf->use_feature($area, $feature)
284 Returns true if the given feature within a known feature areas has been
285 enabled, and false otherwise.
286 The only currently recognized feature areas are "future", "qa", "sanitize",
287 "optimize", "hardening" and "reproducible".
289 =cut
291 sub use_feature {
292 my ($self, $area, $feature) = @_;
294 return 0 if ! $self->has_features($area);
295 return 0 if ! $self->{features}{$area}{$feature};
296 return 1;
299 =item $bf->set_option_value($option, $value)
301 B<Private> method to set the value of a build option.
302 Do not use outside of the dpkg project.
304 =cut
306 sub set_option_value {
307 my ($self, $option, $value) = @_;
309 $self->{optvals}{$option} = $value;
312 =item $bf->get_option_value($option)
314 B<Private> method to get the value of a build option.
315 Do not use outside of the dpkg project.
317 =cut
319 sub get_option_value {
320 my ($self, $option) = @_;
322 return $self->{optvals}{$option};
325 =item $bf->strip($flag, $value, $source, $maint)
327 Update the build flag $flag by stripping the flags listed in $value and
328 record its origin as $source (if defined). Record it as maintainer modified
329 if $maint is defined and true.
331 =cut
333 sub strip {
334 my ($self, $flag, $value, $src, $maint) = @_;
335 foreach my $tostrip (split(/\s+/, $value)) {
336 next unless length $tostrip;
337 $self->{flags}->{$flag} =~ s/(^|\s+)\Q$tostrip\E(\s+|$)/ /g;
339 $self->{flags}->{$flag} =~ s/^\s+//g;
340 $self->{flags}->{$flag} =~ s/\s+$//g;
341 $self->{origin}->{$flag} = $src if defined $src;
342 $self->{maintainer}->{$flag} = $maint if $maint;
345 =item $bf->append($flag, $value, $source, $maint)
347 Append the options listed in $value to the current value of the flag $flag.
348 Record its origin as $source (if defined). Record it as maintainer modified
349 if $maint is defined and true.
351 =cut
353 sub append {
354 my ($self, $flag, $value, $src, $maint) = @_;
355 if (length($self->{flags}->{$flag})) {
356 $self->{flags}->{$flag} .= " $value";
357 } else {
358 $self->{flags}->{$flag} = $value;
360 $self->{origin}->{$flag} = $src if defined $src;
361 $self->{maintainer}->{$flag} = $maint if $maint;
364 =item $bf->prepend($flag, $value, $source, $maint)
366 Prepend the options listed in $value to the current value of the flag $flag.
367 Record its origin as $source (if defined). Record it as maintainer modified
368 if $maint is defined and true.
370 =cut
372 sub prepend {
373 my ($self, $flag, $value, $src, $maint) = @_;
374 if (length($self->{flags}->{$flag})) {
375 $self->{flags}->{$flag} = "$value " . $self->{flags}->{$flag};
376 } else {
377 $self->{flags}->{$flag} = $value;
379 $self->{origin}->{$flag} = $src if defined $src;
380 $self->{maintainer}->{$flag} = $maint if $maint;
384 =item $bf->update_from_conffile($file, $source)
386 Update the current build flags based on the configuration directives
387 contained in $file. See dpkg-buildflags(1) for the format of the directives.
389 $source is the origin recorded for any build flag set or modified.
391 =cut
393 sub update_from_conffile {
394 my ($self, $file, $src) = @_;
395 local $_;
397 return unless -e $file;
398 open(my $conf_fh, '<', $file) or syserr(g_('cannot read %s'), $file);
399 while (<$conf_fh>) {
400 chomp;
401 next if /^\s*#/; # Skip comments
402 next if /^\s*$/; # Skip empty lines
403 if (/^(append|prepend|set|strip)\s+(\S+)\s+(\S.*\S)\s*$/i) {
404 my ($op, $flag, $value) = ($1, $2, $3);
405 unless (exists $self->{flags}->{$flag}) {
406 warning(g_('line %d of %s mentions unknown flag %s'), $., $file, $flag);
407 $self->{flags}->{$flag} = '';
409 if (lc($op) eq 'set') {
410 $self->set($flag, $value, $src);
411 } elsif (lc($op) eq 'strip') {
412 $self->strip($flag, $value, $src);
413 } elsif (lc($op) eq 'append') {
414 $self->append($flag, $value, $src);
415 } elsif (lc($op) eq 'prepend') {
416 $self->prepend($flag, $value, $src);
418 } else {
419 warning(g_('line %d of %s is invalid, it has been ignored'), $., $file);
422 close($conf_fh);
425 =item $bf->get($flag)
427 Return the value associated to the flag. It might be undef if the
428 flag doesn't exist.
430 =cut
432 sub get {
433 my ($self, $key) = @_;
434 return $self->{flags}{$key};
437 =item $bf->get_feature_areas()
439 Return the feature areas (i.e. the area values has_features will return
440 true for).
442 =cut
444 sub get_feature_areas {
445 my $self = shift;
447 return keys %{$self->{features}};
450 =item $bf->get_features($area)
452 Return, for the given area, a hash with keys as feature names, and values
453 as booleans indicating whether the feature is enabled or not.
455 =cut
457 sub get_features {
458 my ($self, $area) = @_;
459 return %{$self->{features}{$area}};
462 =item $bf->get_origin($flag)
464 Return the origin associated to the flag. It might be undef if the
465 flag doesn't exist.
467 =cut
469 sub get_origin {
470 my ($self, $key) = @_;
471 return $self->{origin}{$key};
474 =item $bf->is_maintainer_modified($flag)
476 Return true if the flag is modified by the maintainer.
478 =cut
480 sub is_maintainer_modified {
481 my ($self, $key) = @_;
482 return $self->{maintainer}{$key};
485 =item $bf->has_features($area)
487 Returns true if the given area of features is known, and false otherwise.
488 The only currently recognized feature areas are "future", "qa", "sanitize",
489 "optimize", "hardening" and "reproducible".
491 =cut
493 sub has_features {
494 my ($self, $area) = @_;
495 return exists $self->{features}{$area};
498 =item $bf->has($option)
500 Returns a boolean indicating whether the flags exists in the object.
502 =cut
504 sub has {
505 my ($self, $key) = @_;
506 return exists $self->{flags}{$key};
509 =item @flags = $bf->list()
511 Returns the list of flags stored in the object.
513 =cut
515 sub list {
516 my $self = shift;
517 my @list = sort keys %{$self->{flags}};
518 return @list;
521 =back
523 =head1 CHANGES
525 =head2 Version 1.05 (dpkg 1.21.14)
527 New option: 'vendor_defaults' in new().
529 New methods: $bf->load_vendor_defaults(), $bf->use_feature().
531 =head2 Version 1.04 (dpkg 1.20.0)
533 New method: $bf->unset().
535 =head2 Version 1.03 (dpkg 1.16.5)
537 New method: $bf->get_feature_areas() to list possible values for
538 $bf->get_features.
540 New method $bf->is_maintainer_modified() and new optional parameter to
541 $bf->set(), $bf->append(), $bf->prepend(), $bf->strip().
543 =head2 Version 1.02 (dpkg 1.16.2)
545 New methods: $bf->get_features(), $bf->has_features(), $bf->set_feature().
547 =head2 Version 1.01 (dpkg 1.16.1)
549 New method: $bf->prepend() very similar to append(). Implement support of
550 the prepend operation everywhere.
552 New method: $bf->load_maintainer_config() that update the build flags
553 based on the package maintainer directives.
555 =head2 Version 1.00 (dpkg 1.15.7)
557 Mark the module as public.
559 =cut