77import subprocess
88import sys
99import tempfile
10-
10+ import errno
11+ import platform
1112
1213PACKAGE_DIR = os .path .dirname (os .path .realpath (__file__ ))
1314WORKSPACE_DIR = os .path .realpath (PACKAGE_DIR + '/..' )
2223def printerr (message ):
2324 print (message , file = sys .stderr )
2425
26+ def note (message ):
27+ print ("--- %s: note: %s" % (os .path .basename (sys .argv [0 ]), message ))
28+ sys .stdout .flush ()
2529
2630def fatal_error (message ):
2731 printerr (message )
@@ -129,6 +133,14 @@ def generate_gyb_files(verbose, add_source_locations):
129133
130134## Building swiftSyntax
131135
136+ def get_installed_name ():
137+ # we have to use this name in the installed dylib so that the compiler will
138+ # treat it as a part of stdlib to copy the dylib to the framework dir.
139+ return 'swiftSwiftSyntax'
140+
141+ def get_installed_dylib_name ():
142+ return 'lib' + get_installed_name () + '.dylib'
143+
132144def get_swiftpm_invocation (spm_exec , build_dir , release ):
133145 if spm_exec == 'swift build' :
134146 swiftpm_call = ['swift' , 'build' ]
@@ -143,6 +155,8 @@ def get_swiftpm_invocation(spm_exec, build_dir, release):
143155 if build_dir :
144156 swiftpm_call .extend (['--build-path' , build_dir ])
145157
158+ # Swift compiler needs to know the module link name.
159+ swiftpm_call .extend (['-Xswiftc' , '-module-link-name' , '-Xswiftc' , get_installed_name ()])
146160 return swiftpm_call
147161
148162
@@ -285,6 +299,48 @@ def run_xctests(swift_test_exec, build_dir, release, swiftc_exec, verbose):
285299
286300 return call (swiftpm_call , env = subenv , verbose = verbose ) == 0
287301
302+ def delete_rpath (rpath , binary ):
303+ if platform .system () == 'Darwin' :
304+ cmd = ["install_name_tool" , "-delete_rpath" , rpath , binary ]
305+ note ("removing RPATH from %s: %s" % (binary , ' ' .join (cmd )))
306+ result = subprocess .call (cmd )
307+ if result != 0 :
308+ fatal_error ("command failed with exit status %d" % (result ,))
309+ else :
310+ fatal_error ("unable to remove RPATHs on this platform" )
311+
312+ def change_id_rpath (rpath , binary ):
313+ if platform .system () == 'Darwin' :
314+ cmd = ["install_name_tool" , "-id" , rpath , binary ]
315+ note ("changing id in %s: %s" % (binary , ' ' .join (cmd )))
316+ result = subprocess .call (cmd )
317+ if result != 0 :
318+ fatal_error ("command failed with exit status %d" % (result ,))
319+ else :
320+ fatal_error ("unable to invoke install_name_tool on this platform" )
321+
322+ def check_and_sync (file_path , install_path ):
323+ cmd = ["rsync" , "-a" , file_path , install_path ]
324+ note ("installing %s: %s" % (os .path .basename (file_path ), ' ' .join (cmd )))
325+ result = subprocess .check_call (cmd )
326+ if result != 0 :
327+ fatal_error ("install failed with exit status %d" % (result ,))
328+
329+ def install (build_dir , dylib_dir , swiftmodule_dir , stdlib_rpath ):
330+ dylibPath = build_dir + '/libSwiftSyntax.dylib'
331+ modulePath = build_dir + '/SwiftSyntax.swiftmodule'
332+ docPath = build_dir + '/SwiftSyntax.swiftdoc'
333+ # users should find the dylib as if it's a part of stdlib.
334+ change_id_rpath ('@rpath/' + get_installed_dylib_name (), dylibPath )
335+ # we don't wanna hard-code the stdlib dylibs into rpath.
336+ delete_rpath (stdlib_rpath , dylibPath )
337+ check_and_sync (file_path = dylibPath ,
338+ install_path = dylib_dir + '/' + get_installed_dylib_name ())
339+ # Optionally install .swiftmodule
340+ if swiftmodule_dir :
341+ check_and_sync (file_path = modulePath ,install_path = swiftmodule_dir )
342+ check_and_sync (file_path = docPath ,install_path = swiftmodule_dir )
343+ return
288344
289345### Main
290346
@@ -324,7 +380,18 @@ def main():
324380 help = '''
325381 Insert ###sourceLocation comments in generated code for line-directive.
326382 ''' )
327-
383+ basic_group .add_argument ('--install' , action = 'store_true' ,
384+ help = '''
385+ Install the build artifact to a specified toolchain directory.
386+ ''' )
387+ basic_group .add_argument ('--dylib-dir' ,
388+ help = '''
389+ The directory to where the .dylib should be installed.
390+ ''' )
391+ basic_group .add_argument ('--swiftmodule-dir' ,
392+ help = '''
393+ The directory to where the .swiftmodule should be installed.
394+ ''' )
328395 testing_group = parser .add_argument_group ('Testing' )
329396 testing_group .add_argument ('-t' , '--test' , action = 'store_true' ,
330397 help = 'Run tests' )
@@ -355,6 +422,21 @@ def main():
355422
356423 args = parser .parse_args (sys .argv [1 :])
357424
425+ if args .install :
426+ if not args .dylib_dir :
427+ fatal_error ('Must specify directory to install' )
428+ if not args .build_dir :
429+ fatal_error ('Must specify build directory to copy from' )
430+ if args .release :
431+ build_dir = args .build_dir + '/release'
432+ else :
433+ # will this ever happen?
434+ build_dir = args .build_dir + '/debug'
435+ stdlib_rpath = realpath (os .path .dirname (args .swiftc_exec ) + '/../lib/swift/macosx/' )
436+ install (build_dir = build_dir , dylib_dir = args .dylib_dir ,
437+ swiftmodule_dir = args .swiftmodule_dir ,
438+ stdlib_rpath = stdlib_rpath )
439+ sys .exit (0 )
358440
359441 try :
360442 generate_gyb_files (verbose = args .verbose ,
0 commit comments