Skip to content

Commit 9ea64be

Browse files
committed
[GR-9653] Fix running Python from shared library without core available
PullRequest: graalpython-open/45
2 parents 2b46d8f + 1ddae77 commit 9ea64be

File tree

6 files changed

+206
-13
lines changed

6 files changed

+206
-13
lines changed

graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public static void main(String[] args) {
6565
private String commandString = null;
6666
private String inputFile = null;
6767
private boolean inspectFlag = false;
68+
private boolean verboseFlag = false;
6869
private boolean runCC = false;
6970
private boolean runLD = false;
7071
private VersionAction versionAction = VersionAction.None;
@@ -81,6 +82,9 @@ protected List<String> preprocessArguments(List<String> arguments, Map<String, S
8182
case "-B":
8283
System.out.println("Warning: " + arg + " does nothing on GraalPython.");
8384
break;
85+
case "-v":
86+
verboseFlag = true;
87+
break;
8488
case "-V":
8589
case "--version":
8690
versionAction = VersionAction.PrintAndExit;
@@ -160,7 +164,10 @@ protected void launch(Builder contextBuilder) {
160164
// to print Python exceptions
161165
contextBuilder.option("python.AlwaysRunExcepthook", "true");
162166
if (inspectFlag) {
163-
contextBuilder.option("python.PythonInspectFlag", "true");
167+
contextBuilder.option("python.InspectFlag", "true");
168+
}
169+
if (verboseFlag) {
170+
contextBuilder.option("python.VerboseFlag", "true");
164171
}
165172

166173
ConsoleHandler consoleHandler = createConsoleHandler(System.in, System.out);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
package com.oracle.graal.python;
2727

2828
import java.io.IOException;
29+
import java.text.MessageFormat;
2930
import java.util.ArrayList;
3031

3132
import org.graalvm.options.OptionDescriptors;
@@ -117,7 +118,13 @@ private static boolean optionsAllowPreInitializedContext(PythonContext context,
117118
// Verify that the option for using a shared core is the same as
118119
// at image building time
119120
final boolean useSharedCore = newEnv.getOptions().get(PythonOptions.SharedCore);
120-
return context.getCore().hasSingletonContext() == !useSharedCore;
121+
boolean canUsePreinitializedContext = context.getCore().hasSingletonContext() == !useSharedCore;
122+
if (canUsePreinitializedContext) {
123+
PythonCore.writeInfo(newEnv, "Using preinitialized context.");
124+
} else {
125+
PythonCore.writeInfo(newEnv, "Not using preinitialized context.");
126+
}
127+
return canUsePreinitializedContext;
121128
}
122129

123130
@Override
@@ -137,6 +144,12 @@ private void ensureHomeInOptions(Env env) {
137144
String coreHome = env.getOptions().get(PythonOptions.CoreHome);
138145
String stdLibHome = env.getOptions().get(PythonOptions.StdLibHome);
139146

147+
PythonCore.writeInfo(env, (MessageFormat.format("Initial locations:" +
148+
"\n\tLanguage home: {0}" +
149+
"\n\tSysPrefix: {1}" +
150+
"\n\tCoreHome: {2}" +
151+
"\n\tStdLibHome: {3}", languageHome, sysPrefix, coreHome, stdLibHome)));
152+
140153
TruffleFile home = null;
141154
if (languageHome != null) {
142155
home = env.getTruffleFile(languageHome);
@@ -187,6 +200,12 @@ private void ensureHomeInOptions(Env env) {
187200
}
188201
env.getOptions().set(PythonOptions.StdLibHome, stdLibHome);
189202
}
203+
204+
PythonCore.writeInfo(env, (MessageFormat.format("Updated locations:" +
205+
"\n\tLanguage home: {0}" +
206+
"\n\tSysPrefix: {1}" +
207+
"\n\tCoreHome: {2}" +
208+
"\n\tStdLibHome: {3}", home.getPath(), sysPrefix, coreHome, stdLibHome)));
190209
}
191210
}
192211

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/control/TopLevelExceptionHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ private void printExc(PException e) {
154154
}
155155

156156
private void handleSystemExit(PException e) {
157-
if (PythonOptions.getOption(context, PythonOptions.PythonInspectFlag) && !getSourceSection().getSource().isInteractive()) {
157+
if (PythonOptions.getOption(context, PythonOptions.InspectFlag) && !getSourceSection().getSource().isInteractive()) {
158158
// Don't exit if -i flag was given and we're not yet running interactively
159159
return;
160160
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonCore.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,23 @@ public interface PythonCore {
124124
public PythonContext getContext();
125125

126126
static void writeWarning(TruffleLanguage.Env env, String warning) {
127-
if (!LIBPOLYGLOT) {
128-
try {
129-
env.err().write("[python] WARNING: ".getBytes());
130-
env.err().write(warning.getBytes());
131-
env.err().write('\n');
132-
} catch (IOException e) {
133-
}
127+
if (!LIBPOLYGLOT || env.getOptions().get(PythonOptions.VerboseFlag)) {
128+
write(env, "WARNING: " + warning);
129+
}
130+
}
131+
132+
static void writeInfo(TruffleLanguage.Env env, String warning) {
133+
if (env.getOptions().get(PythonOptions.VerboseFlag)) {
134+
write(env, warning);
135+
}
136+
}
137+
138+
static void write(TruffleLanguage.Env env, String warning) {
139+
try {
140+
env.err().write("[python] ".getBytes());
141+
env.err().write(warning.getBytes());
142+
env.err().write('\n');
143+
} catch (IOException e) {
134144
}
135145
}
136146

@@ -155,7 +165,7 @@ public static String getSysPrefix(TruffleLanguage.Env env) {
155165
String sysPrefix = env.getOptions().get(PythonOptions.SysPrefix);
156166
if (sysPrefix.isEmpty()) {
157167
writeWarning(env, NO_PREFIX_WARNING);
158-
env.getOptions().set(PythonOptions.CoreHome, PREFIX);
168+
env.getOptions().set(PythonOptions.SysPrefix, PREFIX);
159169
return LIB_GRAALPYTHON;
160170
}
161171
return sysPrefix;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonOptions.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,14 @@ private PythonOptions() {
9898
public static final OptionKey<Boolean> AlwaysRunExcepthook = new OptionKey<>(false);
9999

100100
@Option(category = OptionCategory.USER, help = "") //
101-
public static final OptionKey<Boolean> PythonInspectFlag = new OptionKey<>(false);
101+
public static final OptionKey<Boolean> InspectFlag = new OptionKey<>(false);
102102

103103
@Option(category = OptionCategory.USER, help = "Remove assert statements and any code conditional on the value of __debug__.") public static final OptionKey<Boolean> PythonOptimizeFlag = new OptionKey<>(
104104
false);
105105

106+
@Option(category = OptionCategory.DEBUG, help = "Turn on verbose mode") //
107+
public static final OptionKey<Boolean> VerboseFlag = new OptionKey<>(false);
108+
106109
public static OptionDescriptors createDescriptors() {
107110
return new PythonOptionsOptionDescriptors();
108111
}

mx.graalpython/mx_graalpython.py

Lines changed: 155 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,10 @@ def graalpython_gate_runner(args, tasks):
360360
if task:
361361
python_checkcopyrights([])
362362

363+
with Task('GraalPython GraalVM shared-library build', tasks, tags=[GraalPythonTags.downstream, GraalPythonTags.graalvm]) as task:
364+
if task:
365+
run_shared_lib_test()
366+
363367
with Task('GraalPython GraalVM build', tasks, tags=[GraalPythonTags.downstream, GraalPythonTags.graalvm]) as task:
364368
if task:
365369
mx.run_mx(
@@ -393,6 +397,155 @@ def graalpython_gate_runner(args, tasks):
393397
mx_gate.add_gate_runner(_suite, graalpython_gate_runner)
394398

395399

400+
def run_shared_lib_test(args=None):
401+
mx.run_mx(
402+
["--dynamicimports", "/substratevm,/vm",
403+
"build", "--force-deprecation-as-warning", "--dependencies",
404+
"GRAAL_MANAGEMENT,POLYGLOT_NATIVE_API_HEADERS,libpolyglot.so.image"],
405+
nonZeroIsFatal=True
406+
)
407+
vmdir = os.path.join(mx.suite("truffle").dir, "..", "vm")
408+
svm_lib_path = os.path.join(vmdir, "mxbuild", "-".join([mx.get_os(), mx.get_arch()]), "libpolyglot.so.image")
409+
fd = name = progname = None
410+
try:
411+
fd, name = tempfile.mkstemp(suffix='.c')
412+
os.write(fd, """
413+
#include "stdio.h"
414+
#include "polyglot_api.h"
415+
416+
#define assert_ok(msg, f) { if (!(f)) { \\
417+
const poly_extended_error_info* error_info; \\
418+
poly_get_last_error_info(isolate_thread, &error_info); \\
419+
fprintf(stderr, "%s\\n", error_info->error_message); \\
420+
return fprintf(stderr, "%s\\n", msg); } } while (0)
421+
422+
poly_isolate global_isolate;
423+
poly_thread isolate_thread;
424+
poly_engine engine;
425+
poly_context context;
426+
427+
static poly_status create_context() {
428+
poly_status status;
429+
430+
if (poly_attach_thread(global_isolate, &isolate_thread)) {
431+
return poly_generic_failure;
432+
}
433+
434+
poly_engine_builder engine_builder;
435+
status = poly_create_engine_builder(isolate_thread, &engine_builder);
436+
if (status != poly_ok) {
437+
return status;
438+
}
439+
status = poly_engine_builder_build(isolate_thread, engine_builder, &engine);
440+
if (status != poly_ok) {
441+
return status;
442+
}
443+
poly_context_builder builder;
444+
status = poly_create_context_builder(isolate_thread, NULL, 0, &builder);
445+
if (status != poly_ok) {
446+
return status;
447+
}
448+
status = poly_context_builder_engine(isolate_thread, builder, engine);
449+
if (status != poly_ok) {
450+
return status;
451+
}
452+
status = poly_context_builder_option(isolate_thread, builder, "python.VerboseFlag", "true");
453+
if (status != poly_ok) {
454+
return status;
455+
}
456+
status = poly_context_builder_build(isolate_thread, builder, &context);
457+
if (status != poly_ok) {
458+
return status;
459+
}
460+
461+
poly_destroy_handle(isolate_thread, engine_builder);
462+
poly_destroy_handle(isolate_thread, builder);
463+
464+
return poly_ok;
465+
}
466+
467+
static poly_status tear_down_context() {
468+
poly_status status = poly_context_close(isolate_thread, context, true);
469+
if (status != poly_ok) {
470+
return status;
471+
}
472+
473+
status = poly_destroy_handle(isolate_thread, context);
474+
if (status != poly_ok) {
475+
return status;
476+
}
477+
478+
status = poly_engine_close(isolate_thread, engine, true);
479+
if (status != poly_ok) {
480+
return status;
481+
}
482+
483+
status = poly_destroy_handle(isolate_thread, engine);
484+
if (status != poly_ok) {
485+
return status;
486+
}
487+
488+
if (poly_detach_thread(isolate_thread)) {
489+
return poly_ok;
490+
}
491+
492+
return poly_ok;
493+
}
494+
495+
static int test_basic_python_function() {
496+
assert_ok("Context creation failed.", create_context() == poly_ok);
497+
498+
poly_value func;
499+
assert_ok("function eval failed", poly_context_eval(isolate_thread, context, "python", "test_func", "def test_func(x):\\n return x * x\\ntest_func", &func) == poly_ok);
500+
int32_t arg_value = 42;
501+
poly_value primitive_object;
502+
assert_ok("create argument failed", poly_create_int32(isolate_thread, context, arg_value, &primitive_object) == poly_ok);
503+
poly_value arg[1] = {primitive_object};
504+
poly_value value;
505+
assert_ok("invocation was unsuccessful", poly_value_execute(isolate_thread, func, arg, 1, &value) == poly_ok);
506+
507+
int32_t result_value;
508+
poly_value_as_int32(isolate_thread, value, &result_value);
509+
510+
assert_ok("primitive free failed", poly_destroy_handle(isolate_thread, primitive_object) == poly_ok);
511+
assert_ok("value free failed", poly_destroy_handle(isolate_thread, value) == poly_ok);
512+
assert_ok("value computation was incorrect", result_value == 42 * 42);
513+
assert_ok("func free failed", poly_destroy_handle(isolate_thread, func) == poly_ok);
514+
assert_ok("Context tear down failed.", tear_down_context() == poly_ok);
515+
return 0;
516+
}
517+
518+
int32_t main(int32_t argc, char **argv) {
519+
poly_isolate_params isolate_params = {};
520+
if (poly_create_isolate(&isolate_params, &global_isolate)) {
521+
return 1;
522+
}
523+
return test_basic_python_function();
524+
}
525+
""")
526+
os.close(fd)
527+
progname = os.path.join(_suite.dir, "graalpython-embedded-tool")
528+
mx.log("".join(["Running ", "'clang", "-I%s" % svm_lib_path, "-L%s" % svm_lib_path, name, "-o", progname, "-lpolyglot"]))
529+
mx.run(["clang", "-I%s" % svm_lib_path, "-L%s" % svm_lib_path, name, "-o%s" % progname, "-lpolyglot"], nonZeroIsFatal=True)
530+
mx.log("Running " + progname + " with LD_LIBRARY_PATH " + svm_lib_path)
531+
mx.run(["ls", "-l", progname])
532+
mx.run(["ls", "-l", svm_lib_path])
533+
mx.run([progname], env={"LD_LIBRARY_PATH": svm_lib_path})
534+
finally:
535+
try:
536+
os.unlink(progname)
537+
except:
538+
pass
539+
try:
540+
os.close(fd)
541+
except:
542+
pass
543+
try:
544+
os.unlink(name)
545+
except:
546+
pass
547+
548+
396549
class ArchiveProject(mx.ArchivableProject):
397550
def __init__(self, suite, name, deps, workingSets, theLicense, **args):
398551
super(ArchiveProject, self).__init__(suite, name, deps, workingSets, theLicense)
@@ -595,5 +748,6 @@ def python_checkcopyrights(args):
595748
'delete-graalpython-if-testdownstream': [delete_self_if_testdownstream, ''],
596749
'python-checkcopyrights': [python_checkcopyrights, 'Make sure code files have copyright notices'],
597750
'punittest': [punittest, ''],
598-
'nativebuild': [nativebuild, '']
751+
'nativebuild': [nativebuild, ''],
752+
'python-so-test': [run_shared_lib_test, ''],
599753
})

0 commit comments

Comments
 (0)