1111import zlib
1212from collections import namedtuple
1313
14- DEPS = {"llvm" : ["LLVMSupport" ],
15- "swift" : ["swiftFrontendTool" ]}
16-
1714
1815def getoptions ():
1916 parser = argparse .ArgumentParser (description = "package swift for codeql compilation" )
20- for p in DEPS :
21- parser .add_argument (f"--{ p } " , required = True , type = resolve ,
22- metavar = "DIR" , help = f"path to { p } build root" )
17+ parser .add_argument (f"--llvm-build-tree" , required = True , type = resolve ,
18+ metavar = "DIR" , help = f"path to LLVM build tree" )
19+ parser .add_argument (f"--swift-build-tree" , required = True , type = resolve ,
20+ metavar = "DIR" , help = f"path to Swift build tree" )
21+ parser .add_argument (f"--swift-source-tree" , required = True , type = resolve ,
22+ metavar = "DIR" , help = f"path to Swift source tree" )
23+
2324 default_output = f"swift-prebuilt-{ get_platform ()} "
24- parser .add_argument ("--keep-tmp-dir" , "-K" , action = "store_true" ,
25- help = "do not clean up the temporary directory" )
2625 parser .add_argument ("--output" , "-o" , type = pathlib .Path , metavar = "DIR_OR_ZIP" ,
2726 help = "output zip file or directory "
2827 f"(by default the filename is { default_output } )" )
29- update_help_fmt = "Only update the {} library in DIR, triggering rebuilds of required files"
30- parser .add_argument ("--update-shared" , "-u" , metavar = "DIR" , type = pathlib .Path ,
31- help = update_help_fmt .format ("shared" ))
32- parser .add_argument ("--update-static" , "-U" , metavar = "DIR" , type = pathlib .Path ,
33- help = update_help_fmt .format ("static" ))
28+
3429 opts = parser .parse_args ()
35- if opts .output and (opts .update_shared or opts .update_static ):
36- parser .error ("provide --output or one of --update-*, not both" )
3730 if opts .output is None :
3831 opts .output = pathlib .Path ()
3932 opts .output = get_tgt (opts .output , default_output )
40- return opts
41-
4233
43- Libs = namedtuple ("Libs" , ("archive" , "static" , "shared" ))
44-
45- DEPLIST = [x for d in DEPS .values () for x in d ]
46-
47- CMAKELISTS_DUMMY = f"""
48- cmake_minimum_required(VERSION 3.12.4)
49-
50- project(dummy C CXX)
34+ return opts
5135
52- find_package(LLVM REQUIRED CONFIG PATHS ${{LLVM_ROOT}}/lib/cmake/llvm NO_DEFAULT_PATH)
53- find_package(Clang REQUIRED CONFIG PATHS ${{LLVM_ROOT}}/lib/cmake/clang NO_DEFAULT_PATH)
54- find_package(Swift REQUIRED CONFIG PATHS ${{SWIFT_ROOT}}/lib/cmake/swift NO_DEFAULT_PATH)
5536
56- add_executable(dummy empty.cpp)
57- target_link_libraries(dummy PRIVATE { " " .join (DEPLIST )} )
58- """
37+ Libs = namedtuple ("Libs" , ("archive" , "static" , "shared" , "linker_flags" ))
5938
6039EXPORTED_LIB = "CodeQLSwiftFrontendTool"
6140
62- CMAKELISTS_EXPORTED_FMT = """
63- add_library({exported} INTERFACE)
64-
65- if (BUILD_SHARED_LIBS)
66- if (APPLE)
67- set(EXT "dylib")
68- else()
69- set(EXT "so")
70- endif()
71- else()
72- set(EXT "a")
73- endif()
74-
75- set (SwiftLLVMWrapperLib libCodeQLSwiftFrontendTool.${{EXT}})
76- set (input ${{CMAKE_CURRENT_LIST_DIR}}/${{SwiftLLVMWrapperLib}})
77- set (output ${{CMAKE_BINARY_DIR}}/${{SwiftLLVMWrapperLib}})
78-
79- add_custom_command(OUTPUT ${{output}}
80- COMMAND ${{CMAKE_COMMAND}} -E copy_if_different ${{input}} ${{output}}
81- DEPENDS ${{input}})
82- add_custom_target(copy-llvm-swift-wrapper DEPENDS ${{output}})
83-
84- target_include_directories({exported} INTERFACE ${{CMAKE_CURRENT_LIST_DIR}}/include)
85- target_link_libraries({exported} INTERFACE
86- ${{output}}
87- {libs}
88- )
89- add_dependencies(swiftAndLlvmSupport copy-llvm-swift-wrapper)
90- """
91-
92-
93- class TempDir :
94- def __init__ (self , cleanup = True ):
95- self .path = None
96- self .cleanup = cleanup
97-
98- def __enter__ (self ):
99- self .path = pathlib .Path (tempfile .mkdtemp ())
100- return self .path
101-
102- def __exit__ (self , * args ):
103- if self .cleanup :
104- shutil .rmtree (self .path )
105-
10641
10742def resolve (p ):
10843 return pathlib .Path (p ).resolve ()
@@ -118,53 +53,29 @@ def run(prog, *, cwd, env=None, input=None):
11853 subprocess .run (prog , cwd = cwd , env = runenv , input = input , text = True )
11954
12055
121- def build (dir , targets ):
122- print (f"building { ' ' .join (targets )} in { dir } " )
123- cmd = ["cmake" , "--build" , "." , "--" ]
124- cmd .extend (targets )
125- run (cmd , cwd = dir )
126-
127-
12856def get_platform ():
12957 return "linux" if platform .system () == "Linux" else "macos"
13058
13159
132- def create_empty_cpp (path ):
133- with open (path / "empty.cpp" , "w" ):
134- pass
135-
136-
137- def install (tmp , opts ):
138- print ("installing dependencies" )
139- tgt = tmp / "install"
140- for p in DEPS :
141- builddir = getattr (opts , p )
142- run (["cmake" , "--build" , "." , "--" , "install" ], cwd = builddir , env = {"DESTDIR" : tgt })
143- if sys .platform != 'linux' :
144- return tgt / "Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain"
145- return tgt
146-
147-
148- def configure_dummy_project (tmp , * , llvm = None , swift = None , installed = None ):
60+ def configure_dummy_project (tmp , * , llvm = None , swift = None ):
14961 print ("configuring dummy cmake project" )
150- if installed is not None :
151- swift = llvm = installed / "usr"
152- with open (tmp / "CMakeLists.txt" , "w" ) as out :
153- out .write (CMAKELISTS_DUMMY )
154- create_empty_cpp (tmp )
62+ script_dir = pathlib .Path (os .path .realpath (__file__ )).parent
63+ print (script_dir )
64+ shutil .copy (script_dir / "CMakeLists.txt" , tmp / "CMakeLists.txt" )
65+ shutil .copy (script_dir / "empty.cpp" , tmp / "empty.cpp" )
15566 tgt = tmp / "build"
15667 tgt .mkdir ()
157- run (["cmake" , f"-DLLVM_ROOT ={ llvm } " , f"-DSWIFT_ROOT= { swift } " , "-DBUILD_SHARED_LIBS=OFF" , ".." ],
68+ run (["cmake" , f"-DCMAKE_PREFIX_PATH ={ llvm } ; { swift } " , "-DBUILD_SHARED_LIBS=OFF" , ".." ],
15869 cwd = tgt )
15970 return tgt
16071
16172
16273def get_libs (configured ):
16374 print ("extracting linking information from dummy project" )
164- with open (configured / "CMakeFiles" / "dummy .dir" / "link.txt" ) as link :
75+ with open (configured / "CMakeFiles" / "codeql-swift-artifacts .dir" / "link.txt" ) as link :
16576 libs = link .read ().split ()
166- libs = libs [libs .index ('dummy ' )+ 1 :] # skip up to -o dummy
167- ret = Libs ([], [], [])
77+ libs = libs [libs .index ('codeql-swift-artifacts ' )+ 1 :] # skip up to -o dummy
78+ ret = Libs ([], [], [], [] )
16879 for l in libs :
16980 if l .endswith (".a" ):
17081 ret .static .append (str ((configured / l ).resolve ()))
@@ -173,11 +84,10 @@ def get_libs(configured):
17384 ret .shared .append (f"-l{ l [3 :]} " ) # drop 'lib' prefix and '.so' suffix
17485 elif l .startswith ("-l" ):
17586 ret .shared .append (l )
87+ elif l .startswith ("-L" ) or l .startswith ("-Wl" ):
88+ ret .linker_flags .append (l )
17689 else :
17790 raise ValueError (f"cannot understand link.txt: " + l )
178- # move direct dependencies into archive
179- ret .archive [:] = ret .static [:len (DEPLIST )]
180- ret .static [:len (DEPLIST )] = []
18191 return ret
18292
18393
@@ -195,7 +105,6 @@ def create_static_lib(tgt, libs):
195105 mriscript = f"create { tgt } \n { includedlibs } \n save\n end"
196106 run (["ar" , "-M" ], cwd = tgt .parent , input = mriscript )
197107 else :
198- includedlibs = " " .join (f"{ l } " for l in libs .archive + libs .static )
199108 libtool_args = ["libtool" , "-static" ]
200109 libtool_args .extend (libs .archive )
201110 libtool_args .extend (libs .static )
@@ -214,6 +123,7 @@ def create_shared_lib(tgt, libs):
214123 print (f"packaging { libname } " )
215124 compiler = os .environ .get ("CC" , "clang" )
216125 cmd = [compiler , "-shared" ]
126+ cmd .extend (libs .linker_flags )
217127
218128 if sys .platform == 'linux' :
219129 cmd .append ("-Wl,--whole-archive" )
@@ -239,17 +149,17 @@ def create_shared_lib(tgt, libs):
239149def copy_includes (src , tgt ):
240150 print ("copying includes" )
241151 for dir , exts in (("include" , ("h" , "def" , "inc" )), ("stdlib" , ("h" ,))):
242- srcdir = src / "usr" / dir
152+ srcdir = src / dir
243153 for ext in exts :
244154 for srcfile in srcdir .rglob (f"*.{ ext } " ):
245155 tgtfile = tgt / dir / srcfile .relative_to (srcdir )
246156 tgtfile .parent .mkdir (parents = True , exist_ok = True )
247157 shutil .copy (srcfile , tgtfile )
248158
249159
250- def create_sdk ( installed , tgt ):
160+ def export_sdk ( tgt , swift_source_tree , swift_build_tree ):
251161 print ("assembling sdk" )
252- srcdir = installed / "usr" / "lib" / "swift"
162+ srcdir = swift_build_tree / "lib" / "swift"
253163 tgtdir = tgt / "usr" / "lib" / "swift"
254164 if get_platform () == "linux" :
255165 srcdir /= "linux"
@@ -258,24 +168,30 @@ def create_sdk(installed, tgt):
258168 srcdir /= "macosx"
259169 for mod in srcdir .glob ("*.swiftmodule" ):
260170 shutil .copytree (mod , tgtdir / mod .name )
261- shutil .copytree (installed / "usr" / "stdlib" / "public" / "SwiftShims" ,
262- tgt / "usr" / "include" / "SwiftShims" )
171+ shutil .copytree (swift_source_tree / "stdlib" / "public" / "SwiftShims" ,
172+ tgt / "usr" / "include" / "SwiftShims" ,
173+ ignore = shutil .ignore_patterns ('CMakeLists.txt' ))
263174
264175
265- def create_export_dir (tmp , installed , libs ):
266- print ("assembling prebuilt directory" )
267- exportedlibs = [create_static_lib (tmp , libs ), create_shared_lib (tmp , libs )]
268- tgt = tmp / "exported"
269- tgt .mkdir ()
176+ def export_libs (exported_dir , libs ):
177+ print ("exporting libraries" )
178+ exportedlibs = [
179+ create_static_lib (exported_dir , libs ),
180+ create_shared_lib (exported_dir , libs )
181+ ]
270182 for l in exportedlibs :
271- l .rename (tgt / l .name )
272- with open (tgt / "swift_llvm_prebuilt.cmake" , "w" ) as out :
273- # drop -l prefix here
274- sharedlibs = " " .join (l [2 :] for l in libs .shared )
275- out .write (CMAKELISTS_EXPORTED_FMT .format (exported = EXPORTED_LIB , libs = sharedlibs ))
276- copy_includes (installed , tgt )
277- create_sdk (installed , tgt / "sdk" )
278- return tgt
183+ l .rename (exported_dir / l .name )
184+
185+
186+ def export_headers (exported_dir , swift_source_tree , llvm_build_tree , swift_build_tree ):
187+ print ("exporting headers" )
188+ # Assuming default checkout where LLVM sources are placed next to Swift sources
189+ llvm_source_tree = swift_source_tree .parent / 'llvm-project/llvm'
190+ clang_source_tree = swift_source_tree .parent / 'llvm-project/clang'
191+ clang_tools_build_tree = llvm_build_tree / 'tools/clang'
192+ header_dirs = [ llvm_source_tree , clang_source_tree , swift_source_tree , llvm_build_tree , swift_build_tree , clang_tools_build_tree ]
193+ for h in header_dirs :
194+ copy_includes (h , exported_dir )
279195
280196
281197def zip_dir (src , tgt ):
@@ -296,27 +212,17 @@ def main(opts):
296212 if os .path .exists (tmp ):
297213 shutil .rmtree (tmp )
298214 os .mkdir (tmp )
299- if opts .update_shared or opts .update_static :
300- for project , deps in DEPS .items ():
301- build (getattr (opts , project ), deps )
302- configured = configure_dummy_project (tmp , llvm = opts .llvm , swift = opts .swift )
303- libs = get_libs (configured )
304- if opts .update_shared :
305- create_shared_lib (opts .update_shared , libs )
306- if opts .update_static :
307- create_static_lib (opts .update_static , libs )
308- else :
309- installed = install (tmp , opts )
310- swift_syntax_build = opts .swift / "include/swift/Syntax/"
311- swift_syntax_install = installed / "usr/include/swift/Syntax/"
312- for header in os .listdir (swift_syntax_build ):
313- if header .endswith ('.h' ) or header .endswith ('.def' ):
314- shutil .copy (swift_syntax_build / header , swift_syntax_install / header )
315- configured = configure_dummy_project (tmp , installed = installed )
316- libs = get_libs (configured )
317- exported = create_export_dir (tmp , installed , libs )
318- zip_dir (exported , opts .output )
319- tar_dir (exported , opts .output )
215+ configured = configure_dummy_project (tmp , llvm = opts .llvm_build_tree , swift = opts .swift_build_tree )
216+ libs = get_libs (configured )
217+
218+ exported = tmp / "exported"
219+ exported .mkdir ()
220+ export_libs (exported , libs )
221+ export_headers (exported , opts .swift_source_tree , opts .llvm_build_tree , opts .swift_build_tree )
222+ export_sdk (exported / "sdk" , opts .swift_source_tree , opts .swift_build_tree )
223+
224+ zip_dir (exported , opts .output )
225+ tar_dir (exported , opts .output )
320226
321227
322228if __name__ == "__main__" :
0 commit comments