Skip to content

Commit af6f844

Browse files
author
Harlan Haskins
committed
[build_support] Added generic 'toolchain' lookup
1 parent 2de0a6f commit af6f844

File tree

4 files changed

+147
-99
lines changed

4 files changed

+147
-99
lines changed

utils/build-script

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,14 @@ from SwiftBuildSupport import (
3939

4040
sys.path.append(os.path.join(os.path.dirname(__file__), 'swift_build_support'))
4141

42-
import swift_build_support.clang # noqa (E402 module level import not at top of file)
43-
import swift_build_support.cmake # noqa (E402)
44-
import swift_build_support.debug # noqa (E402)
42+
# E402 means module level import not at top of file
43+
import swift_build_support.toolchain # noqa (E402)
44+
import swift_build_support.cmake # noqa (E402)
45+
import swift_build_support.debug # noqa (E402)
4546
from swift_build_support.migration import migrate_impl_args # noqa (E402)
46-
import swift_build_support.ninja # noqa (E402)
47-
import swift_build_support.tar # noqa (E402)
48-
import swift_build_support.targets # noqa (E402)
47+
import swift_build_support.ninja # noqa (E402)
48+
import swift_build_support.tar # noqa (E402)
49+
import swift_build_support.targets # noqa (E402)
4950

5051

5152
# Main entry point for the preset mode.
@@ -1018,7 +1019,7 @@ the number of parallel build jobs to use""",
10181019
if args.clean and os.path.isdir(build_dir):
10191020
shutil.rmtree(build_dir)
10201021

1021-
host_clang = swift_build_support.clang.host_clang(
1022+
host_clang = swift_build_support.toolchain.host_clang(
10221023
xcrun_toolchain=args.darwin_xcrun_toolchain)
10231024
if not host_clang:
10241025
print_with_argv0(

utils/swift_build_support/swift_build_support/clang.py

Lines changed: 0 additions & 90 deletions
This file was deleted.
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# -*- python -*-
2+
# swift_build_support/toolchain.py - Detect host machine's versioned executables
3+
#
4+
# This source file is part of the Swift.org open source project
5+
#
6+
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
7+
# Licensed under Apache License v2.0 with Runtime Library Exception
8+
#
9+
# See http://swift.org/LICENSE.txt for license information
10+
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
11+
#
12+
# ----------------------------------------------------------------------------
13+
#
14+
# Find the path to a Clang executable on the host machine that is most
15+
# suitable for building Swift.
16+
#
17+
# ----------------------------------------------------------------------------
18+
19+
from __future__ import absolute_import
20+
21+
import collections
22+
import platform
23+
import subprocess
24+
25+
from . import xcrun
26+
from .which import which
27+
28+
29+
class Toolchain(object):
30+
"""
31+
A class that stores accessible paths to system commands.
32+
33+
It requires a 'cc' and 'cxx' tool in its keyword args.
34+
"""
35+
def __init__(self, cc=None, cxx=None, **kwargs):
36+
self.cc = cc
37+
self.cxx = cxx
38+
self.tools = [cc, cxx]
39+
for tool, path in kwargs.iteritems():
40+
self.tools.append(path)
41+
setattr(self, tool, path)
42+
43+
44+
def _freebsd_release_date():
45+
"""
46+
Return the release date for FreeBSD operating system on this host.
47+
If the release date cannot be ascertained, return None.
48+
"""
49+
try:
50+
# For details on `sysctl`, see:
51+
# http://www.freebsd.org/cgi/man.cgi?sysctl(8)
52+
return int(subprocess.check_output(
53+
['sysctl', '-n', 'kern.osreldate']).rstrip())
54+
except subprocess.CalledProcessError:
55+
return None
56+
57+
58+
def _first_common_toolchain(tools, suffixes=None):
59+
"""
60+
Return a Toolchain of resolved paths where each path has
61+
the same suffix.
62+
63+
If there is no common version of all binaries found, return None.
64+
"""
65+
if suffixes is None:
66+
# No suffixes provided, default to using empty suffix only
67+
suffixes = ['']
68+
for suffix in suffixes:
69+
path_map = dict()
70+
for name, tool in tools.iteritems():
71+
path = which(tool + suffix)
72+
if not path:
73+
break
74+
path_map[name] = path
75+
if len(path_map) == len(tools):
76+
return Toolchain(**path_map)
77+
return None
78+
79+
80+
def host_toolchain(xcrun_toolchain='default', tools=None, suffixes=None):
81+
"""
82+
Return a Toolchain with the first available versions of all
83+
specified tools, plus clang and clang++, searching in the order of the
84+
given suffixes.
85+
86+
If no matching executables are found, return None.
87+
"""
88+
if tools is None:
89+
tools = dict()
90+
tools['cc'] = 'clang'
91+
tools['cxx'] = 'clang++'
92+
if platform.system() == 'Darwin':
93+
path_map = {}
94+
for name, tool in tools.iteritems():
95+
path = xcrun.find(xcrun_toolchain, tool)
96+
if not path:
97+
return None
98+
path_map[name] = path
99+
return Toolchain(**path_map)
100+
else:
101+
return _first_common_toolchain(tools, suffixes=suffixes)
102+
103+
104+
def host_clang(xcrun_toolchain):
105+
"""
106+
Return a Toolchain for the host platform.
107+
If no appropriate compilers can be found, return None.
108+
"""
109+
if platform.system() == 'FreeBSD':
110+
# See: https://github.com/apple/swift/pull/169
111+
# Building Swift from source requires a recent version of the Clang
112+
# compiler with C++14 support.
113+
freebsd_release_date = _freebsd_release_date()
114+
if freebsd_release_date and freebsd_release_date >= 1100000:
115+
# On newer releases of FreeBSD, the default Clang is sufficient.
116+
return host_toolchain(xcrun_toolchain)
117+
else:
118+
# On older releases, or on releases for which we cannot determine
119+
# the release date, we search for the most modern version
120+
# available.
121+
return host_toolchain(xcrun_toolchain,
122+
suffixes=['38', '37', '36', '35'])
123+
return host_toolchain(xcrun_toolchain,
124+
suffixes=['-3.8', '-3.7', '-3.6', '-3.5'])

utils/swift_build_support/tests/test_clang.py renamed to utils/swift_build_support/tests/test_toolchain.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# test_clang.py - Unit tests for swift_build_support.clang -*- python -*-
1+
# -*- python -*-
2+
# test_toolchain.py - Unit tests for swift_build_support.toolchain
23
#
34
# This source file is part of the Swift.org open source project
45
#
@@ -11,7 +12,7 @@
1112
import os
1213
import unittest
1314

14-
from swift_build_support.clang import host_clang
15+
from swift_build_support.toolchain import host_clang, host_toolchain
1516

1617

1718
class HostClangTestCase(unittest.TestCase):
@@ -26,6 +27,18 @@ def test_clang_available_on_this_platform(self):
2627
self.assertTrue(os.path.split(clang.cc)[-1].startswith('clang'))
2728
self.assertTrue(os.path.split(clang.cxx)[-1].startswith('clang++'))
2829

30+
def test_found_executables_match(self):
31+
# Test that the raw incovation of _first_common_executables
32+
# either returns None or matching paths.
33+
suffixes = ['', '-3.8', '-3.7', '-3.6']
34+
toolchain = host_toolchain(suffixes=suffixes)
35+
self.assertTrue(len(toolchain.tools) == 2)
36+
37+
exec_names = {'foo': 'a-tool-that-does-not-exist'}
38+
toolchain = host_toolchain(tools=exec_names,
39+
suffixes=suffixes)
40+
self.assertIsNone(toolchain)
41+
2942

3043
if __name__ == '__main__':
3144
unittest.main()

0 commit comments

Comments
 (0)