52
52
import argparse
53
53
import io
54
54
import os
55
- import re
56
55
import shutil
57
56
import subprocess
58
57
import sys
62
61
63
62
assert sys .pycache_prefix is None
64
63
65
- JAVA_LAUNCHER = "Py2BinLauncher"
66
- JAVA_LAUNCHER_FILE = f"{ JAVA_LAUNCHER } .java"
67
- JAVA_LAUNCHER_PATH = f"launcher/{ JAVA_LAUNCHER_FILE } "
64
+ MVN_COMPILER_SOURCE = "17"
65
+ MVN_COMPILER_TARGET = "17"
66
+ MVN_JAR_PLUGIN = "3.1.0"
67
+ MVN_GRAAL_SDK_VERSION = "23.0.0"
68
+ MVN_NATIVE_IMAGE_MVN_PLUGIN = "0.9.23"
69
+
70
+ MVN_POM_FILE = "pom.xml"
71
+
72
+ VFS_PREFIX = "vfs"
73
+ VFS_HOME = "home"
74
+ VFS_HOME_PREFIX = f"{ VFS_PREFIX } /{ VFS_HOME } "
75
+ VFS_VENV_PREFIX = VFS_PREFIX + "/venv"
76
+ VFS_PROJ_PREFIX = VFS_PREFIX + "/proj"
77
+
78
+ VFS_JAVA_PKG = "package com.mycompany.javapython;"
79
+
80
+ VFS_JAVA_FILE = "VirtualFileSystem.java"
81
+ VFS_JAVA_FILE_TEMPLATE = f"templates/{ VFS_JAVA_FILE } "
82
+
83
+ JAVA_BINDING_LAUNCHER = "Py2BinLauncher"
84
+ JAVA_BINDING_LAUNCHER_FILE = f"{ JAVA_BINDING_LAUNCHER } .java"
85
+ JAVA_BINDING_LAUNCHER_TEMPLATE_PATH = f"templates/{ JAVA_BINDING_LAUNCHER_FILE } "
86
+ JAVA_BINDING_POM_TEMPLATE_PATH = "templates/java_bindings_pom.xml"
87
+
88
+ NATIVE_EXEC_LAUNCHER = JAVA_BINDING_LAUNCHER
89
+
90
+ POLYGLOT_APP_LAUNCHER_FILE = "Main.java"
91
+ POLYGLOT_APP_LAUNCHER_TEMPLATE_PATH = f"templates/{ POLYGLOT_APP_LAUNCHER_FILE } "
92
+ POLYGLOT_APP_POM_TEMPLATE_PATH = "templates/polyglot_app_pom.xml"
68
93
69
- VIRTUAL_FILESYSTEM_TEMPLATE_FILE = "VirtualFileSystem.java"
70
- VIRTUAL_FILESYSTEM_TEMPLATE_PATH = f"shared/{ VIRTUAL_FILESYSTEM_TEMPLATE_FILE } "
71
94
NATIVE_IMAGE_PROXY_CONF_PATH = f"shared/native-image-proxy-configuration.json"
72
95
NATIVE_IMAGE_RESOURCES_FILE = "native-image-resources.json"
73
96
NATIVE_IMAGE_RESOURCES_PATH = f"shared/{ NATIVE_IMAGE_RESOURCES_FILE } "
74
97
98
+ FILES_LIST_NAME = "fileslist.txt"
99
+ FILES_LIST_PATH = VFS_PREFIX + "/" + FILES_LIST_NAME
100
+
75
101
CMD_NATIVE_EXECUTABLE = "native"
76
102
CMD_JAVA_BINDINGS = "java_bindings"
77
103
CMD_JAVA_PYTHON_APP = "polyglot_app"
80
106
MVN_CODE_PREFIX = "src/main/java"
81
107
MVN_RESOURCE_PREFIX = "src/main/resources"
82
108
109
+ def get_file (* paths ):
110
+ return os .path .join (os .path .dirname (__file__ ), * paths )
111
+
83
112
class AbstractStandalone :
84
113
85
114
def __init__ (self , parsed_args ):
86
115
self .parsed_args = parsed_args
87
- self .virtual_filesystem_template = self .get_file (VIRTUAL_FILESYSTEM_TEMPLATE_PATH )
88
- vfs_prefix , vfs_fileslist_path = self .parse_vfs_prefix_constant ()
89
- self .vfs_prefix = vfs_prefix
90
- self .vfs_fileslist_path = vfs_fileslist_path
91
116
92
117
@abc .abstractmethod
93
118
def create (self ):
94
119
pass
95
120
96
- @staticmethod
97
- def get_file (* paths ):
98
- return os .path .join (os .path .dirname (__file__ ), * paths )
99
-
100
- def create_virtual_filesystem_file (self , target_file , java_pkg = "" ):
101
- lines = open (self .virtual_filesystem_template , 'r' ).readlines ()
102
- with open (target_file , 'w' ) as f :
121
+ def create_virtual_filesystem_file (self , vfs_file , java_pkg = "" ):
122
+ lines = open (get_file (VFS_JAVA_FILE_TEMPLATE ), 'r' ).readlines ()
123
+ with open (vfs_file , 'w' ) as f :
103
124
for line in lines :
104
125
if "{java-pkg}" in line :
105
126
line = line .replace ("{java-pkg}" , java_pkg )
127
+ if "{vfs-prefix}" in line :
128
+ line = line .replace ("{vfs-prefix}" , VFS_PREFIX )
129
+ if "{files-list-name}" in line :
130
+ line = line .replace ("{files-list-name}" , FILES_LIST_NAME )
106
131
f .write (line )
107
-
108
- def parse_vfs_prefix_constant (self ):
109
- """
110
- Determine the vitual filesystem prefix.
111
- """
112
-
113
- with open (self .virtual_filesystem_template ) as f :
114
- content = f .read ()
115
- vfs_prefix = re .search (
116
- 'static final String VFS_PREFIX = "/([^"]+)"' , content
117
- ).group (1 )
118
- fileslist_path = re .search (
119
- 'static final String FILES_LIST_PATH = "/([^"]+)"' , content
120
- ).group (1 )
121
- return vfs_prefix , fileslist_path
122
-
132
+
133
+ def create_pom_file (self , template , pom ):
134
+ lines = open (template , 'r' ).readlines ()
135
+ with open (pom , 'w' ) as f :
136
+ for line in lines :
137
+ if "{mvn-compiler-source}" in line :
138
+ line = line .replace ("{mvn-compiler-source}" , MVN_COMPILER_SOURCE )
139
+ if "{mvn-compiler-target}" in line :
140
+ line = line .replace ("{mvn-compiler-target}" , MVN_COMPILER_TARGET )
141
+ if "{mvn-jar-plugin}" in line :
142
+ line = line .replace ("{mvn-jar-plugin}" , MVN_JAR_PLUGIN )
143
+ if "{graal-sdk-version}" in line :
144
+ line = line .replace ("{graal-sdk-version}" , MVN_GRAAL_SDK_VERSION )
145
+ if "{native-image-mvn-plugin}" in line :
146
+ line = line .replace ("{native-image-mvn-plugin}" , MVN_NATIVE_IMAGE_MVN_PLUGIN )
147
+ if "{vfs-prefix}" in line :
148
+ line = line .replace ("{vfs-prefix}" , VFS_PREFIX )
149
+ if "{vfs-home-prefix}" in line :
150
+ line = line .replace ("{vfs-home-prefix}" , VFS_HOME_PREFIX )
151
+ if "{vfs-venv-prefix}" in line :
152
+ line = line .replace ("{vfs-venv-prefix}" , VFS_VENV_PREFIX )
153
+ if "{files-list-name}" in line :
154
+ line = line .replace ("{files-list-name}" , FILES_LIST_NAME )
155
+ f .write (line )
156
+
157
+ def create_launcher_file (self , template , launcher ):
158
+ lines = open (template , 'r' ).readlines ()
159
+ with open (launcher , 'w' ) as f :
160
+ for line in lines :
161
+ if "{vfs-home-prefix}" in line :
162
+ line = line .replace ("{vfs-home-prefix}" , VFS_HOME_PREFIX )
163
+ if "{vfs-venv-prefix}" in line :
164
+ line = line .replace ("{vfs-venv-prefix}" , VFS_VENV_PREFIX )
165
+ if "{vfs-proj-prefix}" in line :
166
+ line = line .replace ("{vfs-proj-prefix}" , VFS_PROJ_PREFIX )
167
+ f .write (line )
168
+
123
169
def check_output_directory (self ):
124
170
if hasattr (self .parsed_args , "module" ) and os .path .abspath (self .parsed_args .output_directory ).startswith (os .path .abspath (self .parsed_args .module )):
125
171
print (
@@ -150,75 +196,46 @@ def create(self):
150
196
# java sources
151
197
shutil .copytree (os .path .join (os .path .dirname (__file__ ), "app/src" ), os .path .join (target_dir , "src" ))
152
198
153
- virtual_filesystem_java_file = os .path .join (target_dir , MVN_CODE_PREFIX , "com" , "mycompany" , "javapython" , VIRTUAL_FILESYSTEM_TEMPLATE_FILE )
154
- self .create_virtual_filesystem_file (virtual_filesystem_java_file , "package com.mycompany.javapython;" )
199
+ virtual_filesystem_java_file = os .path .join (target_dir , MVN_CODE_PREFIX , "com" , "mycompany" , "javapython" , VFS_JAVA_FILE )
200
+ self .create_virtual_filesystem_file (virtual_filesystem_java_file , VFS_JAVA_PKG )
201
+
202
+ launcher_java_file = os .path .join (target_dir , MVN_CODE_PREFIX , "com" , "mycompany" , "javapython" , POLYGLOT_APP_LAUNCHER_FILE )
203
+ self .create_launcher_file (get_file (POLYGLOT_APP_LAUNCHER_TEMPLATE_PATH ), launcher_java_file )
155
204
156
205
# std lib
157
- vfs_home = os .path .join (target_dir , MVN_RESOURCE_PREFIX , self . vfs_prefix , "home" )
206
+ vfs_home = os .path .join (target_dir , MVN_RESOURCE_PREFIX , VFS_PREFIX , VFS_HOME )
158
207
os .makedirs (vfs_home , exist_ok = True )
159
208
shutil .copytree (__graalpython__ .capi_home , os .path .join (vfs_home , "lib-graalpython" ))
160
209
shutil .copytree (__graalpython__ .stdlib_home , os .path .join (vfs_home , "lib-python" , "3" ))
161
210
162
211
# misc
163
- shutil .copy (os . path . join ( os . path . dirname ( __file__ ), NATIVE_IMAGE_RESOURCES_PATH ), target_dir )
164
- shutil .copy (os . path . join ( os . path . dirname ( __file__ ), NATIVE_IMAGE_PROXY_CONF_PATH ), target_dir )
165
- shutil . copy ( os .path .join (os . path . dirname ( __file__ ), "app/pom.xml" ), target_dir )
166
-
212
+ shutil .copy (get_file ( NATIVE_IMAGE_RESOURCES_PATH ), target_dir )
213
+ shutil .copy (get_file ( NATIVE_IMAGE_PROXY_CONF_PATH ), target_dir )
214
+ self . create_pom_file ( get_file ( POLYGLOT_APP_POM_TEMPLATE_PATH ), os .path .join (target_dir , MVN_POM_FILE ) )
215
+
167
216
class Standalone (AbstractStandalone ):
168
217
def __init__ (self , parsed_args ):
169
218
super ().__init__ (parsed_args )
170
- self .parsed_args = parsed_args
171
-
172
- self .java_launcher_template = self .get_file (JAVA_LAUNCHER_PATH )
173
-
174
- (home_prefix , venv_prefix , proj_prefix ,) = self .parse_standalone_path_constants (self .java_launcher_template )
175
- self .home_prefix = home_prefix
176
- self .venv_prefix = venv_prefix
177
- self .proj_prefix = proj_prefix
178
-
179
- def parse_standalone_path_constants (self , javafile ):
180
- """
181
- Determine the constants used by the Java launcher pertaining to the layout
182
- of the resources file.
183
- """
184
-
185
- with open (javafile ) as f :
186
- content = f .read ()
187
-
188
- home_prefix = re .search (
189
- r'static final String HOME_PREFIX = VirtualFileSystem\.VFS_PREFIX \+ "/([^"]+)"' , content
190
- ).group (1 )
191
- venv_prefix = re .search (
192
- r'static final String VENV_PREFIX = VirtualFileSystem\.VFS_PREFIX \+ "/([^"]+)"' , content
193
- ).group (1 )
194
- proj_prefix = re .search (
195
- r'static final String PROJ_PREFIX = VirtualFileSystem\.VFS_PREFIX \+ "/([^"]+)"' , content
196
- ).group (1 )
197
- return home_prefix , venv_prefix , proj_prefix
198
219
199
220
def create_target_directory (self ):
200
221
if self .parsed_args .verbose :
201
222
print (f"Bundling Python resources into { self .target_dir } " )
202
223
203
224
self .bundle_python_resources (
204
- os .path .join (self .target_dir , self .resource_prefix ),
205
- self .vfs_prefix ,
206
- self .home_prefix ,
207
- self .venv_prefix ,
208
- self .proj_prefix ,
225
+ os .path .join (self .target_dir , self .mvn_resource_prefix ),
209
226
self .parsed_args .module ,
210
227
self .parsed_args .venv ,
211
228
)
212
229
213
230
os .makedirs (os .path .dirname (self .launcher_file ), exist_ok = True )
214
- shutil . copy ( self .java_launcher_template , self .launcher_file )
231
+ self .create_launcher_file ( get_file ( JAVA_BINDING_LAUNCHER_TEMPLATE_PATH ) , self .launcher_file )
215
232
216
- virtual_filesystem_java_file = os .path .join (self .target_dir , self .code_prefix , VIRTUAL_FILESYSTEM_TEMPLATE_FILE )
233
+ virtual_filesystem_java_file = os .path .join (self .target_dir , self .mvn_code_prefix , VFS_JAVA_FILE )
217
234
self .create_virtual_filesystem_file (virtual_filesystem_java_file )
218
235
219
- shutil .copy (self . get_file (NATIVE_IMAGE_RESOURCES_PATH ), os .path .join (self .target_dir , NATIVE_IMAGE_RESOURCES_FILE ))
236
+ shutil .copy (get_file (NATIVE_IMAGE_RESOURCES_PATH ), os .path .join (self .target_dir , NATIVE_IMAGE_RESOURCES_FILE ))
220
237
221
- def bundle_python_resources (self , target_dir , vfs_prefix , home_prefix , venv_prefix , proj_prefix , project , venv = None ):
238
+ def bundle_python_resources (self , target_dir , project , venv = None ):
222
239
"""
223
240
Copy the Python core, stdlib, venv, and module into one folder.
224
241
"""
@@ -228,28 +245,28 @@ def bundle_python_resources(self, target_dir, vfs_prefix, home_prefix, venv_pref
228
245
self .copy_folder_to_target (
229
246
target_dir ,
230
247
__graalpython__ .capi_home ,
231
- f"{ vfs_prefix } / { home_prefix } /lib-graalpython" ,
248
+ f"{ VFS_HOME_PREFIX } /lib-graalpython" ,
232
249
path_filter = lambda file = None , dir = None : file and file .endswith (".py" ),
233
250
)
234
251
235
252
self .copy_folder_to_target (
236
253
target_dir ,
237
254
__graalpython__ .stdlib_home ,
238
- f"{ vfs_prefix } / { home_prefix } /lib-python/3" ,
255
+ f"{ VFS_HOME_PREFIX } /lib-python/3" ,
239
256
path_filter = lambda file = None , dir = None : dir
240
257
and dir in ["idlelib" , "ensurepip" , "tkinter" , "turtledemo" ],
241
258
)
242
259
243
- if venv :
244
- self .copy_folder_to_target (target_dir , venv , f" { vfs_prefix } / { venv_prefix } " )
260
+ if venv :
261
+ self .copy_folder_to_target (target_dir , venv , VFS_VENV_PREFIX )
245
262
246
263
if project and os .path .isdir (project ):
247
- self .copy_folder_to_target (target_dir , project , f" { vfs_prefix } / { proj_prefix } " )
264
+ self .copy_folder_to_target (target_dir , project , VFS_PROJ_PREFIX )
248
265
else :
249
266
with tempfile .TemporaryDirectory () as tmpdir :
250
267
name = os .path .join (tmpdir , "__main__.py" )
251
268
shutil .copy (project , name )
252
- self .copy_folder_to_target (target_dir , tmpdir , f" { vfs_prefix } / { proj_prefix } " )
269
+ self .copy_folder_to_target (target_dir , tmpdir , VFS_PROJ_PREFIX )
253
270
os .unlink (name )
254
271
255
272
def copy_folder_to_target (self , resource_root , folder , prefix , path_filter = lambda file = None , dir = None : False ):
@@ -294,32 +311,32 @@ def __init__(self, parsed_args):
294
311
super ().__init__ (parsed_args )
295
312
296
313
self .target_dir = parsed_args .output_directory
297
- self .code_prefix = MVN_CODE_PREFIX
298
- self .resource_prefix = MVN_RESOURCE_PREFIX
299
- self .launcher_file = os .path .join (self .target_dir , self .code_prefix , JAVA_LAUNCHER_FILE )
314
+ self .mvn_code_prefix = MVN_CODE_PREFIX
315
+ self .mvn_resource_prefix = MVN_RESOURCE_PREFIX
316
+ self .launcher_file = os .path .join (self .target_dir , self .mvn_code_prefix , JAVA_BINDING_LAUNCHER_FILE )
300
317
301
318
def create (self ):
302
319
self .check_output_directory ()
303
320
304
321
os .makedirs (self .target_dir , exist_ok = True )
305
322
self .create_target_directory ()
306
- shutil . copy ( os .path .join (os . path . dirname ( __file__ ), "launcher" , "pom.xml" ), self . target_dir )
323
+ self . create_pom_file ( get_file ( JAVA_BINDING_POM_TEMPLATE_PATH ), os .path .join (self . target_dir , MVN_POM_FILE ) )
307
324
308
325
class NativeExecutable (Standalone ):
309
326
310
327
def __init__ (self , parsed_args ):
311
328
super ().__init__ (parsed_args )
312
329
313
330
self .target_dir = tempfile .mkdtemp ()
314
- self .code_prefix = ""
315
- self .resource_prefix = ""
316
- self .launcher_file = os .path .join (self .target_dir , self . code_prefix , JAVA_LAUNCHER_FILE )
331
+ self .mvn_code_prefix = ""
332
+ self .mvn_resource_prefix = ""
333
+ self .launcher_file = os .path .join (self .target_dir , JAVA_BINDING_LAUNCHER_FILE )
317
334
318
335
def create (self ):
319
336
try :
320
337
self .create_target_directory ()
321
- files_list_path = os .path .join (self .target_dir , self . vfs_fileslist_path )
322
- dir_to_list = os .path .join (self .target_dir , self . vfs_prefix )
338
+ files_list_path = os .path .join (self .target_dir , FILES_LIST_PATH )
339
+ dir_to_list = os .path .join (self .target_dir , VFS_PREFIX )
323
340
__graalpython__ .list_files (dir_to_list , files_list_path )
324
341
self .build_binary ()
325
342
finally :
@@ -390,12 +407,13 @@ def build_binary(self):
390
407
"-Dpolyglot.engine.WarnInterpreterOnly=false" ,
391
408
]
392
409
cmd += [
410
+ "--no-fallback" ,
393
411
"--language:python" ,
394
412
"-H:-CopyLanguageResources" ,
395
413
"-H:ResourceConfigurationFiles=native-image-resources.json" ,
396
414
"-o" ,
397
415
output ,
398
- JAVA_LAUNCHER ,
416
+ NATIVE_EXEC_LAUNCHER ,
399
417
]
400
418
if self .parsed_args .verbose :
401
419
print (f"Building Python standalone binary: { ' ' .join (cmd )} " )
0 commit comments