3
3
from __future__ import print_function
4
4
5
5
import argparse
6
+ from distutils import file_util
6
7
import os
8
+ import json
7
9
import platform
8
10
import shutil
9
11
import subprocess
10
12
import sys
13
+ import errno
14
+
15
+ if platform .system () == 'Darwin' :
16
+ shared_lib_ext = '.dylib'
17
+ else :
18
+ shared_lib_ext = '.so'
19
+ macos_deployment_target = '10.15'
20
+ macos_target_architectures = ['x86_64' ,'arm64' ]
11
21
12
22
# Tools constructed as a part of the a development build toolchain
13
23
driver_toolchain_tools = ['swift' , 'swift-frontend' , 'clang' , 'swift-help' ,
14
24
'swift-autolink-extract' , 'lldb' ]
15
25
26
+ def mkdir_p (path ):
27
+ """Create the given directory, if it does not exist."""
28
+ try :
29
+ os .makedirs (path )
30
+ except OSError as e :
31
+ # Ignore EEXIST, which may occur during a race condition.
32
+ if e .errno != errno .EEXIST :
33
+ raise
34
+
16
35
def call_output (cmd , cwd = None , stderr = False , verbose = False ):
17
36
"""Calls a subprocess for its return data."""
18
37
if verbose :
@@ -76,26 +95,26 @@ def get_swiftpm_options(args):
76
95
77
96
return swiftpm_args
78
97
79
- def install (swiftpm_bin_path , toolchain ):
80
- toolchain_bin = os .path .join (toolchain , 'bin' )
81
- for exe in ['swift-driver' , 'swift-help' ]:
82
- install_binary (exe , swiftpm_bin_path , toolchain_bin , toolchain , is_executable = True )
83
-
84
- def install_binary (file , source_dir , install_dir , toolchain , is_executable ):
98
+ def install_binary (file , source_dir , install_dir , verbose ):
99
+ print ('Installing %s into: %s' % (file , install_dir ))
85
100
cmd = ['rsync' , '-a' , os .path .join (source_dir .decode ('UTF-8' ), file ), install_dir ]
86
- print (' ' .join (cmd ))
87
- subprocess .check_call (cmd )
88
-
89
- if platform .system () == 'Darwin' and is_executable :
90
- result_path = os .path .join (install_dir , file )
91
- stdlib_rpath = os .path .join (toolchain , 'lib' , 'swift' , 'macosx' )
92
- delete_rpath (stdlib_rpath , result_path )
93
-
94
- def delete_rpath (rpath , binary ):
95
- cmd = ["install_name_tool" , "-delete_rpath" , rpath , binary ]
96
- print (' ' .join (cmd ))
101
+ if verbose :
102
+ print (' ' .join (cmd ))
97
103
subprocess .check_call (cmd )
98
104
105
+ def delete_rpath (rpath , binary , verbose ):
106
+ cmd = ['install_name_tool' , '-delete_rpath' , rpath , binary ]
107
+ if verbose :
108
+ print (' ' .join (cmd ))
109
+ installToolProcess = subprocess .Popen (cmd ,
110
+ stdout = subprocess .PIPE ,
111
+ stderr = subprocess .PIPE )
112
+ stdout , stderr = installToolProcess .communicate ()
113
+ if installToolProcess .returncode != 0 :
114
+ print ('install_name_tool command failed: ' )
115
+ print (stderr )
116
+ if verbose :
117
+ print (stdout )
99
118
100
119
def should_test_parallel ():
101
120
if platform .system () == 'Linux' :
@@ -105,7 +124,6 @@ def should_test_parallel():
105
124
return False
106
125
return True
107
126
108
-
109
127
def handle_invocation (toolchain_bin , args ):
110
128
swiftpm_args = get_swiftpm_options (args )
111
129
@@ -138,19 +156,255 @@ def handle_invocation(toolchain_bin, args):
138
156
test_args += ['--parallel' ]
139
157
swiftpm ('test' , swift_exec , test_args , env )
140
158
elif args .action == 'install' :
141
- bin_path = swiftpm_bin_path (swift_exec , swiftpm_args , env )
142
- swiftpm ('build' , swift_exec , swiftpm_args , env )
143
- install (bin_path , args .toolchain )
159
+ if platform .system () == 'Darwin' :
160
+ distribution_build_dir = os .path .join (args .build_path , 'dist' )
161
+ build_for_distribution (args , toolchain_bin , distribution_build_dir )
162
+ install (args , distribution_build_dir )
163
+ else :
164
+ bin_path = swiftpm_bin_path (swift_exec , swiftpm_args , env )
165
+ swiftpm ('build' , swift_exec , swiftpm_args , env )
166
+ non_darwin_install (bin_path , args .toolchain , args .verbose )
144
167
else :
145
168
assert False , 'unknown action \' {}\' ' .format (args .action )
146
169
147
170
171
+ # Installation flow for non-darwin platforms, only copies over swift-driver and swift-help
172
+ # TODO: Unify CMake-based installation flow used on Darwin with this
173
+ def non_darwin_install (swiftpm_bin_path , toolchain , verbose ):
174
+ toolchain_bin = os .path .join (toolchain , 'bin' )
175
+ for exe in ['swift-driver' , 'swift-help' ]:
176
+ install_binary (exe , swiftpm_bin_path , toolchain_bin , verbose )
177
+
178
+ def install (args , build_dir ):
179
+ # Construct and install universal swift-driver, swift-help executables
180
+ # and libSwiftDriver, libSwiftOptions libraries
181
+ toolchain_bin = os .path .join (args .toolchain , 'bin' )
182
+ toolchain_lib = os .path .join (args .toolchain , 'lib' , 'swift' , 'macosx' )
183
+ universal_dir = os .path .join (build_dir , 'universal-apple-macos%s' % macos_deployment_target )
184
+ bin_dir = os .path .join (universal_dir , 'bin' )
185
+ lib_dir = os .path .join (universal_dir , 'lib' )
186
+ mkdir_p (universal_dir )
187
+ mkdir_p (bin_dir )
188
+ mkdir_p (lib_dir )
189
+
190
+ # swift-driver and swift-help
191
+ install_executables (args , build_dir , bin_dir , toolchain_bin )
192
+
193
+ # libSwiftDriver and libSwiftOptions
194
+ install_libraries (args , build_dir , lib_dir , toolchain_lib )
195
+
196
+ # SwiftDriver.swiftmodule and SwiftOptions.swiftmodule
197
+ install_modules (args , build_dir , toolchain_lib )
198
+
199
+ def install_executables (args , build_dir , universal_bin_dir , toolchain_bin_dir ):
200
+ for exe in ['swift-driver' , 'swift-help' ]:
201
+ # Fixup rpaths
202
+ for arch in macos_target_architectures :
203
+ exe_bin_path = os .path .join (build_dir , arch + '-apple-macos' + macos_deployment_target ,
204
+ 'swift-driver' , 'bin' , exe )
205
+ help_bin_path = os .path .join (build_dir , arch + '-apple-macos' + macos_deployment_target ,
206
+ 'swift-driver' , 'bin' , 'swift-help' )
207
+ driver_lib_dir_path = os .path .join (build_dir , arch + '-apple-macos' + macos_deployment_target ,
208
+ 'swift-driver' , 'lib' )
209
+ delete_rpath (driver_lib_dir_path , exe_bin_path , args .verbose )
210
+ # Only swift-driver requires libllbuild
211
+ if exe == 'swift-driver' :
212
+ llbuild_lib_dir_path = os .path .join (build_dir , arch + '-apple-macos' + macos_deployment_target ,
213
+ 'llbuild' , 'lib' )
214
+ delete_rpath (llbuild_lib_dir_path , exe_bin_path , args .verbose )
215
+
216
+ # Merge the multiple architecture binaries into a universal binary and install
217
+ output_bin_path = os .path .join (universal_bin_dir , exe )
218
+ lipo_cmd = ['lipo' ]
219
+ # Inputs
220
+ for arch in macos_target_architectures :
221
+ input_bin_path = os .path .join (build_dir , arch + '-apple-macos' + macos_deployment_target ,
222
+ 'swift-driver' , 'bin' , exe )
223
+ lipo_cmd .append (input_bin_path )
224
+ lipo_cmd .extend (['-create' , '-output' , output_bin_path ])
225
+ subprocess .check_call (lipo_cmd )
226
+ install_binary (exe , universal_bin_dir , toolchain_bin_dir , args .verbose )
227
+
228
+ def install_libraries (args , build_dir , universal_lib_dir , toolchain_lib_dir ):
229
+ # Fixup the rpath for libSwiftDriver (libSwiftOptions does not link against these libraries)
230
+ for arch in macos_target_architectures :
231
+ lib_path = os .path .join (build_dir , arch + '-apple-macos' + macos_deployment_target ,
232
+ 'swift-driver' , 'lib' , 'libSwiftDriver' + shared_lib_ext )
233
+ driver_lib_dir_path = os .path .join (build_dir , arch + '-apple-macos' + macos_deployment_target ,
234
+ 'swift-driver' , 'lib' )
235
+ llbuild_lib_dir_path = os .path .join (build_dir , arch + '-apple-macos' + macos_deployment_target ,
236
+ 'llbuild' , 'lib' )
237
+ delete_rpath (driver_lib_dir_path , lib_path , args .verbose )
238
+ delete_rpath (llbuild_lib_dir_path , lib_path , args .verbose )
239
+
240
+ # Install the libSwiftDriver and libSwiftOptions shared libraries into the toolchain lib
241
+ for lib in ['libSwiftDriver' , 'libSwiftOptions' ]:
242
+ dylib_file = lib + shared_lib_ext
243
+ output_dylib_path = os .path .join (universal_lib_dir , dylib_file )
244
+ lipo_cmd = ['lipo' ]
245
+ for arch in macos_target_architectures :
246
+ input_lib_path = os .path .join (build_dir , arch + '-apple-macos' + macos_deployment_target ,
247
+ 'swift-driver' , 'lib' , dylib_file )
248
+ lipo_cmd .append (input_lib_path )
249
+ lipo_cmd .extend (['-create' , '-output' , output_dylib_path ])
250
+ subprocess .check_call (lipo_cmd )
251
+ install_binary (dylib_file , universal_lib_dir , toolchain_lib_dir , args .verbose )
252
+
253
+ def install_modules (args , build_dir , toolchain_lib_dir ):
254
+ for module in ['SwiftDriver' , 'SwiftOptions' ]:
255
+ toolchain_module_dir = os .path .join (toolchain_lib_dir , module + '.swiftmodule' )
256
+ mkdir_p (toolchain_module_dir )
257
+ for arch in macos_target_architectures :
258
+ swift_dir = os .path .join (build_dir , arch + '-apple-macos' + macos_deployment_target ,
259
+ 'swift-driver' , 'swift' )
260
+ for fileext in ['.swiftmodule' , '.swiftdoc' ]:
261
+ install_binary (module + fileext , swift_dir , toolchain_module_dir , args .verbose )
262
+ os .rename (os .path .join (toolchain_module_dir , module + fileext ),
263
+ os .path .join (toolchain_module_dir , arch + '-apple-macos' + fileext ))
264
+
265
+ def build_for_distribution (args , toolchain_bin , build_dir ):
266
+ print ('Preparing SwiftDriver for distribution using CMake.' )
267
+ swiftc_exec = os .path .join (toolchain_bin , 'swiftc' )
268
+
269
+ # Targets for which we must build swift-driver to distribute
270
+ if platform .system () == 'Darwin' :
271
+ targets = [x + '-apple-macos' + macos_deployment_target for x in macos_target_architectures ]
272
+ else :
273
+ targets = [get_build_target (swiftc_path , args )]
274
+
275
+ for target in targets :
276
+ base_cmake_flags = [
277
+ '-DCMAKE_Swift_FLAGS=-target %s' % target ,
278
+ ]
279
+ if platform .system () == 'Darwin' :
280
+ base_cmake_flags .append ('-DCMAKE_OSX_DEPLOYMENT_TARGET=%s' % macos_deployment_target )
281
+
282
+ # Target directory to build distribution artifacts
283
+ cmake_target_dir = os .path .join (build_dir , target )
284
+ # LLBuild
285
+ build_llbuild_using_cmake (args , target , swiftc_exec , cmake_target_dir , base_cmake_flags )
286
+ # TSC
287
+ build_tsc_using_cmake (args , target , swiftc_exec , cmake_target_dir , base_cmake_flags )
288
+ # Argument Parser
289
+ build_argument_parser_using_cmake (args , target , swiftc_exec , cmake_target_dir , base_cmake_flags )
290
+ # Yams
291
+ build_yams_using_cmake (args , target , swiftc_exec , cmake_target_dir , base_cmake_flags )
292
+ # SwiftDriver
293
+ build_swift_driver_using_cmake (args , target , swiftc_exec , cmake_target_dir , base_cmake_flags )
294
+
295
+ def build_llbuild_using_cmake (args , target , swiftc_exec , cmake_target_dir , base_cmake_flags ):
296
+ print ('Building llbuild for target: %s' % target )
297
+ llbuild_source_dir = os .path .join (args .package_path , '..' , 'llbuild' )
298
+ llbuild_build_dir = os .path .join (cmake_target_dir , 'llbuild' )
299
+ llbuild_api_dir = os .path .join (llbuild_build_dir , '.cmake/api/v1/query' )
300
+ mkdir_p (llbuild_api_dir )
301
+ subprocess .check_call (['touch' , os .path .join (llbuild_api_dir , 'codemodel-v2' )])
302
+ flags = [
303
+ '-DBUILD_SHARED_LIBS=OFF' ,
304
+ '-DCMAKE_C_COMPILER:=clang' ,
305
+ '-DCMAKE_CXX_COMPILER:=clang++' ,
306
+ '-DCMAKE_CXX_FLAGS=-target %s' % target ,
307
+ '-DLLBUILD_SUPPORT_BINDINGS:=Swift'
308
+ ]
309
+ if platform .system () == 'Darwin' :
310
+ flags .append ('-DCMAKE_OSX_ARCHITECTURES=%s' % target .split ('-' )[0 ])
311
+ llbuild_cmake_flags = base_cmake_flags + flags
312
+ if args .sysroot :
313
+ llbuild_cmake_flags .append ('-DSQLite3_INCLUDE_DIR=%s/usr/include' % args .sysroot )
314
+ cmake_build (args , swiftc_exec , llbuild_cmake_flags , llbuild_source_dir , llbuild_build_dir )
315
+
316
+ def build_tsc_using_cmake (args , target , swiftc_exec , cmake_target_dir , base_cmake_flags ):
317
+ print ('Building TSC for target: %s' % target )
318
+ tsc_source_dir = os .path .join (args .package_path , '..' , 'swift-tools-support-core' )
319
+ tsc_build_dir = os .path .join (cmake_target_dir , 'swift-tools-support-core' )
320
+ tsc_flags = base_cmake_flags + ['-DBUILD_SHARED_LIBS=OFF' ]
321
+ cmake_build (args , swiftc_exec , tsc_flags , tsc_source_dir , tsc_build_dir )
322
+
323
+ def build_yams_using_cmake (args , target , swiftc_exec , cmake_target_dir , base_cmake_flags ):
324
+ print ('Building Yams for target: %s' % target )
325
+ yams_source_dir = os .path .join (args .package_path , '..' , 'yams' )
326
+ yams_build_dir = os .path .join (cmake_target_dir , 'yams' )
327
+ yams_flags = base_cmake_flags + ['-DBUILD_SHARED_LIBS=OFF' , '-DCMAKE_C_FLAGS=-target %s' % target ]
328
+ cmake_build (args , swiftc_exec , yams_flags , yams_source_dir , yams_build_dir )
329
+
330
+ def build_argument_parser_using_cmake (args , target , swiftc_exec , cmake_target_dir , base_cmake_flags ):
331
+ print ('Building Argument Parser for target: %s' % target )
332
+ parser_source_dir = os .path .join (args .package_path , '..' , 'swift-argument-parser' )
333
+ parser_build_dir = os .path .join (cmake_target_dir , 'swift-argument-parser' )
334
+ custom_flags = ['-DBUILD_SHARED_LIBS=OFF' , '-DBUILD_TESTING=NO' , '-DBUILD_EXAMPLES=NO' ]
335
+ parser_flags = base_cmake_flags + custom_flags
336
+ cmake_build (args , swiftc_exec , parser_flags , parser_source_dir , parser_build_dir )
337
+ return
338
+
339
+ def build_swift_driver_using_cmake (args , target , swiftc_exec , cmake_target_dir , base_cmake_flags ):
340
+ print ('Building Swift Driver for target: %s' % target )
341
+ driver_source_dir = args .package_path
342
+ driver_build_dir = os .path .join (cmake_target_dir , 'swift-driver' )
343
+ # TODO: Enable Library Evolution for swift-driver
344
+ #swift_flags = '-DCMAKE_Swift_FLAGS=' + '-enable-library-evolution' + ' -emit-module-interface-path ' + os.path.join(cmake_target_dir, 'swift-driver', 'SwiftDriver.swiftinterface') + ' -Xfrontend -module-interface-preserve-types-as-written'
345
+ swift_flags = ''
346
+ flags = [
347
+ '-DLLBuild_DIR=' + os .path .join (os .path .join (cmake_target_dir , 'llbuild' ), 'cmake/modules' ),
348
+ '-DTSC_DIR=' + os .path .join (os .path .join (cmake_target_dir , 'swift-tools-support-core' ), 'cmake/modules' ),
349
+ '-DYams_DIR=' + os .path .join (os .path .join (cmake_target_dir , 'yams' ), 'cmake/modules' ),
350
+ '-DArgumentParser_DIR=' + os .path .join (os .path .join (cmake_target_dir , 'swift-argument-parser' ), 'cmake/modules' ),
351
+ swift_flags
352
+ ]
353
+ driver_cmake_flags = base_cmake_flags + flags
354
+ cmake_build (args , swiftc_exec , driver_cmake_flags , driver_source_dir , driver_build_dir )
355
+
356
+ def cmake_build (args , swiftc_exec , cmake_args , source_path , build_dir ):
357
+ """Configure with CMake and build with Ninja"""
358
+ swift_flags = ''
359
+ if args .sysroot :
360
+ swift_flags = '-sdk %s' % args .sysroot
361
+ cmd = [
362
+ args .cmake_bin , '-G' , 'Ninja' ,
363
+ '-DCMAKE_MAKE_PROGRAM=%s' % args .ninja_bin ,
364
+ '-DCMAKE_BUILD_TYPE:=Release' ,
365
+ '-DCMAKE_Swift_FLAGS=' + swift_flags ,
366
+ '-DCMAKE_Swift_COMPILER:=%s' % (swiftc_exec ),
367
+ ] + cmake_args + [source_path ]
368
+ if args .verbose :
369
+ print (' ' .join (cmd ))
370
+ mkdir_p (build_dir )
371
+ subprocess .check_output (cmd , cwd = build_dir )
372
+
373
+ # Invoke Ninja
374
+ ninja_cmd = [args .ninja_bin ]
375
+ if args .verbose :
376
+ ninja_cmd .append ('-v' )
377
+ print (' ' .join (ninja_cmd ))
378
+ ninjaProcess = subprocess .Popen (ninja_cmd , cwd = build_dir ,
379
+ stdout = subprocess .PIPE ,
380
+ stderr = subprocess .PIPE ,
381
+ env = os .environ )
382
+ stdout , stderr = ninjaProcess .communicate ()
383
+ if ninjaProcess .returncode != 0 :
384
+ print ('Ninja invocation failed: ' )
385
+ print (stderr )
386
+ sys .exit (ninjaProcess .returncode )
387
+ if args .verbose :
388
+ print (stdout )
389
+
390
+ def get_build_target (swiftc_path , args ):
391
+ """Returns the target-triple of the current machine."""
392
+ try :
393
+ target_info_json = subprocess .check_output ([swiftc_path , '-print-target-info' ],
394
+ stderr = subprocess .PIPE ,
395
+ universal_newlines = True ).strip ()
396
+ args .target_info = json .loads (target_info_json )
397
+ return args .target_info ['target' ]['unversionedTriple' ]
398
+ except Exception as e :
399
+ error (str (e ))
400
+
148
401
def main ():
149
402
parser = argparse .ArgumentParser (description = 'Build along with the Swift build-script.' )
150
403
def add_common_args (parser ):
151
404
parser .add_argument ('--package-path' , metavar = 'PATH' , help = 'directory of the package to build' , default = '.' )
152
405
parser .add_argument ('--toolchain' , required = True , metavar = 'PATH' , help = 'build using the toolchain at PATH' )
153
406
parser .add_argument ('--ninja-bin' , metavar = 'PATH' , help = 'ninja binary to use for testing' )
407
+ parser .add_argument ('--cmake-bin' , metavar = 'PATH' , help = 'cmake binary to use for building' )
154
408
parser .add_argument ('--build-path' , metavar = 'PATH' , default = '.build' , help = 'build in the given path' )
155
409
parser .add_argument ('--configuration' , '-c' , default = 'debug' , help = 'build using configuration (release|debug)' )
156
410
parser .add_argument ('--no-local-deps' , action = 'store_true' , help = 'use normal remote dependencies when building' )
0 commit comments