-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathbuild
executable file
·170 lines (135 loc) · 6.03 KB
/
build
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#!/usr/bin/python3
import os, shutil, subprocess, argparse, json
def shell(arguments, silent = False, environment = {}):
print(' '.join(arguments))
result = subprocess.run(arguments, capture_output = silent, encoding = 'utf-8',
env = { ** os.environ, ** environment })
# if not silent and result.stderr:
# print(result.stderr)
result.check_returncode()
return result.stdout
def filter_files( * extensions , directory = '.', root = None, basename = None):
for current_root, directories, files in os.walk(directory):
if root is str and current_root != root:
continue
for file in files:
for suffix in extensions:
if type(suffix) is str:
suffix = (suffix,)
name = file
for extension in reversed(suffix):
name, tail = os.path.splitext(name)
if tail != '.{0}'.format(extension):
break
else:
if basename is None or name == basename:
yield os.path.join(current_root, '{0}{1}'.format(name, tail))
break
def clear_files( * extensions , directory = '.', root = None, basename = None):
for file in filter_files( * extensions, directory = directory, root = root, basename = basename):
os.remove(file)
# remove empty directories
for current_root, directories, files in os.walk(directory, topdown = False):
if not directories and not files:
os.rmdir(current_root)
# swift libraries cannot be reloaded, see
# https://forums.swift.org/t/what-happens-to-static-variables-when-a-shared-swift-library-gets-reloaded/47211
def emit_gdnlib(resource_path, product):
return """[general]
singleton=false
load_once=true
symbol_prefix="godot_"
reloadable=false
[entry]
X11.64="{0}/lib{1}.so"
Windows.64=""
OSX.64=""
[dependencies]
X11.64=[]
Windows.64=[]
OSX.64=[]
""".format(resource_path, product)
def emit_gdns(resource_path, symbol):
return """[gd_resource type="NativeScript" load_steps=2 format=2]
[ext_resource path="{0}/library.gdnlib" type="GDNativeLibrary" id=1]
[resource]
resource_name = "{1}"
class_name = "{1}"
library = ExtResource( 1 )
""".format(resource_path, symbol)
def godot_project_root(install):
install = os.path.abspath(install)
directory = os.path.dirname(install)
while not os.path.isdir(directory) or 'project.godot' not in os.listdir(directory):
parent = os.path.dirname(directory)
if directory != parent:
directory = parent
else:
return None, None
# always use '/' separator for resource paths
return directory, 'res:/{0}'.format('/'.join(os.path.split(os.path.relpath(install, start = directory))))
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--configuration', type = str, choices = ('debug', 'release'),
default = 'debug',
help = 'build configuration')
parser.add_argument('-i', '--install', type = str,
default = None,
help = 'installation directory')
parser.add_argument('--use-cached-interface',action = 'store_true',
help = 'use cached library interface')
options = parser.parse_args()
# emit settings.json
os.makedirs('.godot-swift', exist_ok = True)
with open(os.path.join('.godot-swift', 'settings.json'), 'w') as file:
json.dump({'update_interface': not options.use_cached_interface}, file)
flags = (argument for flag in (
(
'-DENABLE_ARC_SANITIZER',
'-Xfrontend', '-warn-long-expression-type-checking=500',
) if options.configuration == 'debug' else ())
for argument in ('-Xswiftc', '{0}'.format(flag)))
# build the library
shell(('swift', 'build', '-c', options.configuration, * flags ),
environment = {'SWIFTPM_ENABLE_PLUGINS': '1'})
if options.install is None:
return
# find project.godot root
project_root, resource_path = godot_project_root(options.install)
if project_root is None:
message = 'installation directory \'{0}\' is not located in a godot project (could not find \'project.godot\')'.format(options.install)
raise FileNotFoundError(message)
else:
print('installing to \'{0}/\' in project \'{1}\''.format(resource_path, project_root))
# look for library.json configuration files
library = {}
for path in filter_files('json',
directory = os.path.join('.build', 'plugins', 'outputs'),
root = 'GodotNativeScript',
basename = 'library'):
with open(path, 'r') as file:
product = json.load(file)
if product['product'] not in library:
library[product['product']] = set()
library[product['product']].update(product['symbols'])
if os.path.isdir(options.install):
clear_files('gdns', 'gdnlib', 'so', directory = options.install)
os.makedirs(os.path.abspath(options.install), exist_ok = True)
# copy the shared libraries
for object in filter_files('so', 'dylib', 'dll',
directory = os.path.join('.build', options.configuration)):
shutil.copy(object, options.install)
for product, symbols in library.items():
product_prefix = os.path.join(options.install, product)
resource_prefix = '{0}/{1}'.format(resource_path, product)
os.makedirs(product_prefix, exist_ok = True)
# generate the godot resource files
with open(os.path.join(product_prefix, 'library.gdnlib'), 'w') as file:
file.write(emit_gdnlib(resource_path, product))
for symbol in symbols:
with open(os.path.join(product_prefix, '{0}.gdns'.format(symbol)), 'w') as file:
file.write(emit_gdns(resource_prefix, symbol))
if __name__ == '__main__':
# set cwd
os.chdir(os.path.dirname(__file__))
main()