2 # Copyright (c) 2015 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """This script will check out llvm and clang, and then package the results up
19 THIS_DIR
= os
.path
.dirname(__file__
)
20 THIRD_PARTY_DIR
= os
.path
.join(THIS_DIR
, '..', '..', '..', 'third_party')
21 LLVM_DIR
= os
.path
.join(THIRD_PARTY_DIR
, 'llvm')
22 LLVM_BOOTSTRAP_DIR
= os
.path
.join(THIRD_PARTY_DIR
, 'llvm-bootstrap')
23 LLVM_BOOTSTRAP_INSTALL_DIR
= os
.path
.join(THIRD_PARTY_DIR
,
24 'llvm-bootstrap-install')
25 LLVM_BUILD_DIR
= os
.path
.join(THIRD_PARTY_DIR
, 'llvm-build')
26 LLVM_RELEASE_DIR
= os
.path
.join(LLVM_BUILD_DIR
, 'Release+Asserts')
27 STAMP_FILE
= os
.path
.join(LLVM_BUILD_DIR
, 'cr_build_revision')
30 def Tee(output
, logfile
):
35 def TeeCmd(cmd
, logfile
, fail_hard
=True):
36 """Runs cmd and writes the output to both stdout and logfile."""
37 # Reading from PIPE can deadlock if one buffer is full but we wait on a
38 # different one. To work around this, pipe the subprocess's stderr to
39 # its stdout buffer and don't give it a stdin.
40 # shell=True is required in cmd.exe since depot_tools has an svn.bat, and
41 # bat files only work with shell=True set.
42 proc
= subprocess
.Popen(cmd
, bufsize
=1, shell
=sys
.platform
== 'win32',
43 stdin
=open(os
.devnull
), stdout
=subprocess
.PIPE
,
44 stderr
=subprocess
.STDOUT
)
45 for line
in iter(proc
.stdout
.readline
,''):
47 if proc
.poll() is not None:
49 exit_code
= proc
.wait()
50 if exit_code
!= 0 and fail_hard
:
55 def PrintTarProgress(tarinfo
):
56 print 'Adding', tarinfo
.name
61 parser
= argparse
.ArgumentParser(description
='build and package clang')
62 parser
.add_argument('--gcc-toolchain',
63 help="the prefix for the GCC version used for building. "
64 "For /opt/foo/bin/gcc, pass "
65 "'--gcc-toolchain '/opt/foo'")
67 args
= parser
.parse_args()
69 with
open('buildlog.txt', 'w') as log
:
70 Tee('Diff in llvm:\n', log
)
71 TeeCmd(['svn', 'stat', LLVM_DIR
], log
, fail_hard
=False)
72 TeeCmd(['svn', 'diff', LLVM_DIR
], log
, fail_hard
=False)
73 Tee('Diff in llvm/tools/clang:\n', log
)
74 TeeCmd(['svn', 'stat', os
.path
.join(LLVM_DIR
, 'tools', 'clang')],
76 TeeCmd(['svn', 'diff', os
.path
.join(LLVM_DIR
, 'tools', 'clang')],
78 # TODO(thakis): compiler-rt is in projects/compiler-rt on Windows but
79 # llvm/compiler-rt elsewhere. So this diff call is currently only right on
81 Tee('Diff in llvm/compiler-rt:\n', log
)
82 TeeCmd(['svn', 'stat', os
.path
.join(LLVM_DIR
, 'projects', 'compiler-rt')],
84 TeeCmd(['svn', 'diff', os
.path
.join(LLVM_DIR
, 'projects', 'compiler-rt')],
86 Tee('Diff in llvm/projects/libcxx:\n', log
)
87 TeeCmd(['svn', 'stat', os
.path
.join(LLVM_DIR
, 'projects', 'libcxx')],
89 TeeCmd(['svn', 'diff', os
.path
.join(LLVM_DIR
, 'projects', 'libcxx')],
91 Tee('Diff in llvm/projects/libcxxabi:\n', log
)
92 TeeCmd(['svn', 'stat', os
.path
.join(LLVM_DIR
, 'projects', 'libcxxabi')],
94 TeeCmd(['svn', 'diff', os
.path
.join(LLVM_DIR
, 'projects', 'libcxxabi')],
97 Tee('Starting build\n', log
)
100 shutil
.rmtree(LLVM_BOOTSTRAP_DIR
, ignore_errors
=True)
101 shutil
.rmtree(LLVM_BOOTSTRAP_INSTALL_DIR
, ignore_errors
=True)
102 shutil
.rmtree(LLVM_BUILD_DIR
, ignore_errors
=True)
104 build_cmd
= [sys
.executable
, os
.path
.join(THIS_DIR
, 'update.py'),
105 '--bootstrap', '--force-local-build', '--run-tests',
107 if args
.gcc_toolchain
is not None:
108 build_cmd
.extend(['--gcc-toolchain', args
.gcc_toolchain
])
109 TeeCmd(build_cmd
, log
)
111 stamp
= open(STAMP_FILE
).read().rstrip()
112 pdir
= 'clang-' + stamp
114 shutil
.rmtree(pdir
, ignore_errors
=True)
116 # Copy a whitelist of files to the directory we're going to tar up.
117 # This supports the same patterns that the fnmatch module understands.
118 exe_ext
= '.exe' if sys
.platform
== 'win32' else ''
119 want
= ['bin/llvm-symbolizer' + exe_ext
,
120 'lib/clang/*/asan_blacklist.txt',
121 # Copy built-in headers (lib/clang/3.x.y/include).
122 'lib/clang/*/include/*',
124 if sys
.platform
== 'win32':
125 want
.append('bin/clang-cl.exe')
127 so_ext
= 'dylib' if sys
.platform
== 'darwin' else 'so'
128 want
.extend(['bin/clang',
129 'lib/libFindBadConstructs.' + so_ext
,
130 'lib/libBlinkGCPlugin.' + so_ext
,
132 if sys
.platform
== 'darwin':
133 want
.extend(['bin/libc++.1.dylib',
134 # Copy only the OSX (ASan and profile) and iossim (ASan)
136 'lib/clang/*/lib/darwin/*asan_osx*',
137 'lib/clang/*/lib/darwin/*asan_iossim*',
138 'lib/clang/*/lib/darwin/*profile_osx*',
140 elif sys
.platform
.startswith('linux'):
142 # lib/clang/*/lib/linux/libclang_rt.{[atm]san,san,ubsan,profile}-*.a ,
144 want
.extend(['lib/clang/*/lib/linux/*[atm]san*',
145 'lib/clang/*/lib/linux/*ubsan*',
146 'lib/clang/*/lib/linux/*libclang_rt.san*',
147 'lib/clang/*/lib/linux/*profile*',
148 'lib/clang/*/msan_blacklist.txt',
150 elif sys
.platform
== 'win32':
151 want
.extend(['lib/clang/*/lib/windows/clang_rt.asan*.dll',
152 'lib/clang/*/lib/windows/clang_rt.asan*.lib',
153 'lib/clang/*/include_sanitizer/*',
155 if args
.gcc_toolchain
is not None:
156 # Copy the stdlibc++.so.6 we linked Clang against so it can run.
157 want
.append('lib/libstdc++.so.6')
159 for root
, dirs
, files
in os
.walk(LLVM_RELEASE_DIR
):
160 # root: third_party/llvm-build/Release+Asserts/lib/..., rel_root: lib/...
161 rel_root
= root
[len(LLVM_RELEASE_DIR
)+1:]
162 rel_files
= [os
.path
.join(rel_root
, f
) for f
in files
]
163 wanted_files
= list(set(itertools
.chain
.from_iterable(
164 fnmatch
.filter(rel_files
, p
) for p
in want
)))
166 # Guaranteed to not yet exist at this point:
167 os
.makedirs(os
.path
.join(pdir
, rel_root
))
168 for f
in wanted_files
:
169 src
= os
.path
.join(LLVM_RELEASE_DIR
, f
)
170 dest
= os
.path
.join(pdir
, f
)
171 shutil
.copy(src
, dest
)
173 if sys
.platform
== 'darwin' and f
.endswith('.dylib'):
174 # Fix LC_ID_DYLIB for the ASan dynamic libraries to be relative to
176 # TODO(glider): this is transitional. We'll need to fix the dylib
177 # name either in our build system, or in Clang. See also
178 # http://crbug.com/344836.
179 subprocess
.call(['install_name_tool', '-id',
180 '@executable_path/' + os
.path
.basename(dest
), dest
])
181 subprocess
.call(['strip', '-x', dest
])
182 elif (sys
.platform
.startswith('linux') and
183 os
.path
.splitext(f
)[1] in ['.so', '.a']):
184 subprocess
.call(['strip', '-g', dest
])
187 if sys
.platform
!= 'win32':
188 os
.symlink('clang', os
.path
.join(pdir
, 'bin', 'clang++'))
189 os
.symlink('clang', os
.path
.join(pdir
, 'bin', 'clang-cl'))
190 if sys
.platform
== 'darwin':
191 os
.symlink('libc++.1.dylib', os
.path
.join(pdir
, 'bin', 'libc++.dylib'))
192 # Also copy libc++ headers.
193 shutil
.copytree(os
.path
.join(LLVM_BOOTSTRAP_INSTALL_DIR
, 'include', 'c++'),
194 os
.path
.join(pdir
, 'include', 'c++'))
196 # Copy buildlog over.
197 shutil
.copy('buildlog.txt', pdir
)
200 tar_entries
= ['bin', 'lib', 'buildlog.txt']
201 if sys
.platform
== 'darwin':
202 tar_entries
+= ['include']
203 with tarfile
.open(pdir
+ '.tgz', 'w:gz') as tar
:
204 for entry
in tar_entries
:
205 tar
.add(os
.path
.join(pdir
, entry
), arcname
=entry
, filter=PrintTarProgress
)
207 if sys
.platform
== 'darwin':
209 elif sys
.platform
== 'win32':
212 platform
= 'Linux_x64'
214 print 'To upload, run:'
215 print ('gsutil cp -a public-read %s.tgz '
216 'gs://chromium-browser-clang/%s/%s.tgz') % (pdir
, platform
, pdir
)
218 # Zip up gold plugin on Linux.
219 if sys
.platform
.startswith('linux'):
220 golddir
= 'llvmgold-' + stamp
221 shutil
.rmtree(golddir
, ignore_errors
=True)
222 os
.makedirs(os
.path
.join(golddir
, 'lib'))
223 shutil
.copy(os
.path
.join(LLVM_RELEASE_DIR
, 'lib', 'LLVMgold.so'),
224 os
.path
.join(golddir
, 'lib'))
225 with tarfile
.open(golddir
+ '.tgz', 'w:gz') as tar
:
226 tar
.add(os
.path
.join(golddir
, 'lib'), arcname
='lib',
227 filter=PrintTarProgress
)
228 print ('gsutil cp -a public-read %s.tgz '
229 'gs://chromium-browser-clang/%s/%s.tgz') % (golddir
, platform
,
232 # FIXME: Warn if the file already exists on the server.
235 if __name__
== '__main__':