Module: OS::Mac::Xcode

Defined in:
Library/Homebrew/os/mac/xcode.rb

Constant Summary collapse

DEFAULT_BUNDLE_PATH =
Pathname.new("/Applications/Xcode.app").freeze
BUNDLE_ID =
"com.apple.dt.Xcode".freeze
OLD_BUNDLE_ID =
"com.apple.Xcode".freeze

Class Method Summary collapse

Class Method Details

.below_minimum_version?Boolean

Returns:

  • (Boolean)


38
39
40
41
# File 'Library/Homebrew/os/mac/xcode.rb', line 38

def below_minimum_version?
  return false unless installed?
  version < minimum_version
end

.bundle_pathObject



83
84
85
86
87
88
89
90
91
# File 'Library/Homebrew/os/mac/xcode.rb', line 83

def bundle_path
  # Use the default location if it exists.
  return DEFAULT_BUNDLE_PATH if DEFAULT_BUNDLE_PATH.exist?

  # Ask Spotlight where Xcode is. If the user didn't install the
  # helper tools and installed Xcode in a non-conventional place, this
  # is our only option. See: https://superuser.com/questions/390757
  MacOS.app_with_bundle_id(BUNDLE_ID, OLD_BUNDLE_ID)
end

.default_prefix?Boolean

Returns:

  • (Boolean)


181
182
183
184
185
186
187
# File 'Library/Homebrew/os/mac/xcode.rb', line 181

def default_prefix?
  if version < "4.3"
    prefix.to_s.start_with? "/Developer"
  else
    prefix.to_s == "/Applications/Xcode.app/Contents/Developer"
  end
end

.detect_versionObject



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
# File 'Library/Homebrew/os/mac/xcode.rb', line 121

def detect_version
  # This is a separate function as you can't cache the value out of a block
  # if return is used in the middle, which we do many times in here.
  return if !MacOS::Xcode.installed? && !MacOS::CLT.installed?

  %W[
    #{prefix}/usr/bin/xcodebuild
    #{which("xcodebuild")}
  ].uniq.each do |xcodebuild_path|
    next unless File.executable? xcodebuild_path
    xcodebuild_output = Utils.popen_read(xcodebuild_path, "-version")
    next unless $CHILD_STATUS.success?

    xcode_version = xcodebuild_output[/Xcode (\d(\.\d)*)/, 1]
    return xcode_version if xcode_version

    # Xcode 2.x's xcodebuild has a different version string
    case xcodebuild_output[/DevToolsCore-(\d+\.\d)/, 1]
    when "515.0" then return "2.0"
    when "798.0" then return "2.5"
    end
  end

  detect_version_from_clang_version
end

.detect_version_from_clang_versionObject



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'Library/Homebrew/os/mac/xcode.rb', line 147

def detect_version_from_clang_version
  # This logic provides a fake Xcode version based on the
  # installed CLT version. This is useful as they are packaged
  # simultaneously so workarounds need to apply to both based on their
  # comparable version.
  case (DevelopmentTools.clang_version.to_f * 10).to_i
  when 0       then "dunno"
  when 1..14   then "3.2.2"
  when 15      then "3.2.4"
  when 16      then "3.2.5"
  when 17..20  then "4.0"
  when 21      then "4.1"
  when 22..30  then "4.2"
  when 31      then "4.3"
  when 40      then "4.4"
  when 41      then "4.5"
  when 42      then "4.6"
  when 50      then "5.0"
  when 51      then "5.1"
  when 60      then "6.0"
  when 61      then "6.1"
  when 70      then "7.0"
  when 73      then "7.3"
  when 80      then "8.0"
  when 81      then "8.3"
  when 90      then "9.0"
  else              "9.0"
  end
end

.installed?Boolean

Returns:

  • (Boolean)


93
94
95
# File 'Library/Homebrew/os/mac/xcode.rb', line 93

def installed?
  !prefix.nil?
end

.latest_sdk_version?Boolean

Returns:

  • (Boolean)


43
44
45
# File 'Library/Homebrew/os/mac/xcode.rb', line 43

def latest_sdk_version?
  OS::Mac.version == OS::Mac.latest_sdk_version
end

.latest_versionObject



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'Library/Homebrew/os/mac/xcode.rb', line 10

def latest_version
  case MacOS.version
  when "10.4"  then "2.5"
  when "10.5"  then "3.1.4"
  when "10.6"  then "3.2.6"
  when "10.7"  then "4.6.3"
  when "10.8"  then "5.1.1"
  when "10.9"  then "6.2"
  when "10.10" then "7.2.1"
  when "10.11" then "8.2.1"
  when "10.12" then "9.2"
  when "10.13" then "9.2"
  else
    raise "macOS '#{MacOS.version}' is invalid" unless OS::Mac.prerelease?

    # Default to newest known version of Xcode for unreleased macOS versions.
    "9.2"
  end
end

.minimum_versionObject



30
31
32
33
34
35
36
# File 'Library/Homebrew/os/mac/xcode.rb', line 30

def minimum_version
  case MacOS.version
  when "10.13" then "9.0"
  when "10.12" then "8.0"
  else "2.0"
  end
end

.needs_clt_installed?Boolean

Returns:

  • (Boolean)


47
48
49
50
# File 'Library/Homebrew/os/mac/xcode.rb', line 47

def needs_clt_installed?
  return false if latest_sdk_version?
  without_clt?
end

.outdated?Boolean

Returns:

  • (Boolean)


52
53
54
55
# File 'Library/Homebrew/os/mac/xcode.rb', line 52

def outdated?
  return false unless installed?
  version < latest_version
end

.prefixObject

Returns a Pathname object corresponding to Xcode.app's Developer directory or nil if Xcode.app is not installed



63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'Library/Homebrew/os/mac/xcode.rb', line 63

def prefix
  @prefix ||=
    begin
      dir = MacOS.active_developer_dir

      if dir.empty? || dir == CLT::PKG_PATH || !File.directory?(dir)
        path = bundle_path
        path/"Contents/Developer" if path
      else
        # Use cleanpath to avoid pathological trailing slash
        Pathname.new(dir).cleanpath
      end
    end
end

.provides_gcc?Boolean

Returns:

  • (Boolean)


177
178
179
# File 'Library/Homebrew/os/mac/xcode.rb', line 177

def provides_gcc?
  version < "4.3"
end

.toolchain_pathObject



78
79
80
81
# File 'Library/Homebrew/os/mac/xcode.rb', line 78

def toolchain_path
  return if version < "4.3"
  Pathname.new("#{prefix}/Toolchains/XcodeDefault.xctoolchain")
end

.update_instructionsObject



97
98
99
100
101
102
103
104
105
106
107
108
# File 'Library/Homebrew/os/mac/xcode.rb', line 97

def update_instructions
  if MacOS.version >= "10.9" && !OS::Mac.prerelease?
    <<~EOS
      Xcode can be updated from the App Store.
    EOS
  else
    <<~EOS
      Xcode can be updated from
        https://developer.apple.com/download/more/
    EOS
  end
end

.versionObject



110
111
112
113
114
115
116
117
118
119
# File 'Library/Homebrew/os/mac/xcode.rb', line 110

def version
  # may return a version string
  # that is guessed based on the compiler, so do not
  # use it in order to check if Xcode is installed.
  if @version ||= detect_version
    ::Version.new @version
  else
    ::Version::NULL
  end
end

.without_clt?Boolean

Returns:

  • (Boolean)


57
58
59
# File 'Library/Homebrew/os/mac/xcode.rb', line 57

def without_clt?
  version >= "4.3" && !MacOS::CLT.installed?
end