11
11
import zlib
12
12
from collections import namedtuple
13
13
14
- DEPS = {"llvm" : ["LLVMSupport" ],
15
- "swift" : ["swiftFrontendTool" ]}
16
-
17
14
18
15
def getoptions ():
19
16
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
+
23
24
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" )
26
25
parser .add_argument ("--output" , "-o" , type = pathlib .Path , metavar = "DIR_OR_ZIP" ,
27
26
help = "output zip file or directory "
28
27
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
+
34
29
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" )
37
30
if opts .output is None :
38
31
opts .output = pathlib .Path ()
39
32
opts .output = get_tgt (opts .output , default_output )
40
- return opts
41
-
42
33
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
51
35
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)
55
36
56
- add_executable(dummy empty.cpp)
57
- target_link_libraries(dummy PRIVATE { " " .join (DEPLIST )} )
58
- """
37
+ Libs = namedtuple ("Libs" , ("archive" , "static" , "shared" , "linker_flags" ))
59
38
60
39
EXPORTED_LIB = "CodeQLSwiftFrontendTool"
61
40
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
-
106
41
107
42
def resolve (p ):
108
43
return pathlib .Path (p ).resolve ()
@@ -118,53 +53,27 @@ def run(prog, *, cwd, env=None, input=None):
118
53
subprocess .run (prog , cwd = cwd , env = runenv , input = input , text = True )
119
54
120
55
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
-
128
56
def get_platform ():
129
57
return "linux" if platform .system () == "Linux" else "macos"
130
58
131
59
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 ):
149
61
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
+ shutil .copy ("CMakeLists.txt" , tmp / "CMakeLists.txt" )
63
+ shutil .copy ("empty.cpp" , tmp / "empty.cpp" )
155
64
tgt = tmp / "build"
156
65
tgt .mkdir ()
157
- run (["cmake" , f"-DLLVM_ROOT ={ llvm } " , f"-DSWIFT_ROOT= { swift } " , "-DBUILD_SHARED_LIBS=OFF" , ".." ],
66
+ run (["cmake" , f"-DCMAKE_PREFIX_PATH ={ llvm } ; { swift } " , "-DBUILD_SHARED_LIBS=OFF" , ".." ],
158
67
cwd = tgt )
159
68
return tgt
160
69
161
70
162
71
def get_libs (configured ):
163
72
print ("extracting linking information from dummy project" )
164
- with open (configured / "CMakeFiles" / "dummy .dir" / "link.txt" ) as link :
73
+ with open (configured / "CMakeFiles" / "codeql-swift-artifacts .dir" / "link.txt" ) as link :
165
74
libs = link .read ().split ()
166
- libs = libs [libs .index ('dummy ' )+ 1 :] # skip up to -o dummy
167
- ret = Libs ([], [], [])
75
+ libs = libs [libs .index ('codeql-swift-artifacts ' )+ 1 :] # skip up to -o dummy
76
+ ret = Libs ([], [], [], [] )
168
77
for l in libs :
169
78
if l .endswith (".a" ):
170
79
ret .static .append (str ((configured / l ).resolve ()))
@@ -173,11 +82,10 @@ def get_libs(configured):
173
82
ret .shared .append (f"-l{ l [3 :]} " ) # drop 'lib' prefix and '.so' suffix
174
83
elif l .startswith ("-l" ):
175
84
ret .shared .append (l )
85
+ elif l .startswith ("-L" ) or l .startswith ("-Wl" ):
86
+ ret .linker_flags .append (l )
176
87
else :
177
88
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 )] = []
181
89
return ret
182
90
183
91
@@ -195,7 +103,6 @@ def create_static_lib(tgt, libs):
195
103
mriscript = f"create { tgt } \n { includedlibs } \n save\n end"
196
104
run (["ar" , "-M" ], cwd = tgt .parent , input = mriscript )
197
105
else :
198
- includedlibs = " " .join (f"{ l } " for l in libs .archive + libs .static )
199
106
libtool_args = ["libtool" , "-static" ]
200
107
libtool_args .extend (libs .archive )
201
108
libtool_args .extend (libs .static )
@@ -214,6 +121,7 @@ def create_shared_lib(tgt, libs):
214
121
print (f"packaging { libname } " )
215
122
compiler = os .environ .get ("CC" , "clang" )
216
123
cmd = [compiler , "-shared" ]
124
+ cmd .extend (libs .linker_flags )
217
125
218
126
if sys .platform == 'linux' :
219
127
cmd .append ("-Wl,--whole-archive" )
@@ -239,17 +147,17 @@ def create_shared_lib(tgt, libs):
239
147
def copy_includes (src , tgt ):
240
148
print ("copying includes" )
241
149
for dir , exts in (("include" , ("h" , "def" , "inc" )), ("stdlib" , ("h" ,))):
242
- srcdir = src / "usr" / dir
150
+ srcdir = src / dir
243
151
for ext in exts :
244
152
for srcfile in srcdir .rglob (f"*.{ ext } " ):
245
153
tgtfile = tgt / dir / srcfile .relative_to (srcdir )
246
154
tgtfile .parent .mkdir (parents = True , exist_ok = True )
247
155
shutil .copy (srcfile , tgtfile )
248
156
249
157
250
- def create_sdk ( installed , tgt ):
158
+ def export_sdk ( tgt , swift_source_tree , swift_build_tree ):
251
159
print ("assembling sdk" )
252
- srcdir = installed / "usr" / "lib" / "swift"
160
+ srcdir = swift_build_tree / "lib" / "swift"
253
161
tgtdir = tgt / "usr" / "lib" / "swift"
254
162
if get_platform () == "linux" :
255
163
srcdir /= "linux"
@@ -258,24 +166,30 @@ def create_sdk(installed, tgt):
258
166
srcdir /= "macosx"
259
167
for mod in srcdir .glob ("*.swiftmodule" ):
260
168
shutil .copytree (mod , tgtdir / mod .name )
261
- shutil .copytree (installed / "usr" / "stdlib" / "public" / "SwiftShims" ,
262
- tgt / "usr" / "include" / "SwiftShims" )
169
+ shutil .copytree (swift_source_tree / "stdlib" / "public" / "SwiftShims" ,
170
+ tgt / "usr" / "include" / "SwiftShims" ,
171
+ ignore = shutil .ignore_patterns ('CMakeLists.txt' ))
263
172
264
173
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 ()
174
+ def export_libs (exported_dir , libs ):
175
+ print ("exporting libraries" )
176
+ exportedlibs = [
177
+ create_static_lib (exported_dir , libs ),
178
+ create_shared_lib (exported_dir , libs )
179
+ ]
270
180
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
181
+ l .rename (exported_dir / l .name )
182
+
183
+
184
+ def export_headers (exported_dir , swift_source_tree , llvm_build_tree , swift_build_tree ):
185
+ print ("exporting headers" )
186
+ # Assuming default checkout where LLVM sources are placed next to Swift sources
187
+ llvm_source_tree = swift_source_tree .parent / 'llvm-project/llvm'
188
+ clang_source_tree = swift_source_tree .parent / 'llvm-project/clang'
189
+ clang_tools_build_tree = llvm_build_tree / 'tools/clang'
190
+ header_dirs = [ llvm_source_tree , clang_source_tree , swift_source_tree , llvm_build_tree , swift_build_tree , clang_tools_build_tree ]
191
+ for h in header_dirs :
192
+ copy_includes (h , exported_dir )
279
193
280
194
281
195
def zip_dir (src , tgt ):
@@ -296,27 +210,17 @@ def main(opts):
296
210
if os .path .exists (tmp ):
297
211
shutil .rmtree (tmp )
298
212
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 )
213
+ configured = configure_dummy_project (tmp , llvm = opts .llvm_build_tree , swift = opts .swift_build_tree )
214
+ libs = get_libs (configured )
215
+
216
+ exported = tmp / "exported"
217
+ exported .mkdir ()
218
+ export_libs (exported , libs )
219
+ export_headers (exported , opts .swift_source_tree , opts .llvm_build_tree , opts .swift_build_tree )
220
+ export_sdk (exported / "sdk" , opts .swift_source_tree , opts .swift_build_tree )
221
+
222
+ zip_dir (exported , opts .output )
223
+ tar_dir (exported , opts .output )
320
224
321
225
322
226
if __name__ == "__main__" :
0 commit comments