aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew/build_options.rb
blob: 478fd8a84855a51b99fc81f61df85c616665f2d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
require 'options'

# This class holds the build-time options defined for a Formula,
# and provides named access to those options during install.
class BuildOptions
  include Enumerable

  attr_accessor :args
  attr_accessor :universal
  attr_reader :options
  protected :options

  def initialize args
    @args = Options.coerce(args)
    @options = Options.new
  end

  def initialize_copy(other)
    super
    @options = other.options.dup
    @args = other.args.dup
  end

  def add name, description=nil
    description ||= case name.to_s
      when "universal" then "Build a universal binary"
      when "32-bit" then "Build 32-bit only"
      when "c++11" then "Build using C++11 mode"
      end.to_s

    @options << Option.new(name, description)
  end

  def add_dep_option(dep)
    name = dep.option_name
    if dep.optional? && !has_option?("with-#{name}")
      add("with-#{name}", "Build with #{name} support")
    elsif dep.recommended? && !has_option?("without-#{name}")
      add("without-#{name}", "Build without #{name} support")
    end
  end

  def has_option? name
    any? { |opt| opt.name == name }
  end

  def empty?
    @options.empty?
  end

  def each(*args, &block)
    @options.each(*args, &block)
  end

  def as_flags
    @options.as_flags
  end

  def include? name
    args.include? '--' + name
  end

  def with? val
    if val.respond_to?(:option_name)
      name = val.option_name
    else
      name = val
    end

    if has_option? "with-#{name}"
      include? "with-#{name}"
    elsif has_option? "without-#{name}"
      not include? "without-#{name}"
    else
      false
    end
  end

  def without? name
    not with? name
  end

  def bottle?
    args.include? '--build-bottle'
  end

  def head?
    args.include? '--HEAD'
  end

  def devel?
    args.include? '--devel'
  end

  def stable?
    not (head? or devel?)
  end

  # True if the user requested a universal build.
  def universal?
    universal || args.include?('--universal') && has_option?('universal')
  end

  # True if the user requested to enable C++11 mode.
  def cxx11?
    args.include?('--c++11') && has_option?('c++11')
  end

  # Request a 32-bit only build.
  # This is needed for some use-cases though we prefer to build Universal
  # when a 32-bit version is needed.
  def build_32_bit?
    args.include?('--32-bit') && has_option?('32-bit')
  end

  def used_options
    Options.new(@options & @args)
  end

  def unused_options
    Options.new(@options - @args)
  end

  # Some options are implicitly ON because they are not explictly turned off
  # by their counterpart option. This applies only to with-/without- options.
  # implicit_options are needed because `depends_on 'spam' => 'with-stuff'`
  # complains if 'spam' has stuff as default and only defines `--without-stuff`.
  def implicit_options
    implicit = unused_options.map do |option|
      opposite_of option unless has_opposite_of? option
    end.compact
    Options.new(implicit)
  end

  def has_opposite_of? option
    @options.include? opposite_of(option)
  end

  def opposite_of option
    option = Option.new(option) unless Option === option

    if option.name =~ /^with-(.+)$/
      Option.new("without-#{$1}")
    elsif option.name =~ /^without-(.+)$/
      Option.new("with-#{$1}")
    elsif option.name =~ /^enable-(.+)$/
      Option.new("disable-#{$1}")
    elsif option.name =~ /^disable-(.+)$/
      Option.new("enable-#{$1}")
    end
  end
end