Skip to content

Commit

Permalink
Build and use native-image image only in gate runs
Browse files Browse the repository at this point in the history
or when needed in the vm-suite.
  • Loading branch information
olpaw committed May 25, 2018
1 parent a025497 commit c825246
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 71 deletions.
15 changes: 5 additions & 10 deletions substratevm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ mx build

echo "public class HelloWorld { public static void main(String[] args) { System.out.println(\"Hello World\"); } }" > HelloWorld.java
$JAVA_HOME/bin/javac HelloWorld.java
./native-image HelloWorld
mx native-image HelloWorld
./helloworld
./native-image --server-shutdown
```

To speed up successive image-build requests, native-image launches background image-build servers. The last command ensures that all image-build servers are shut down. (If you build images only with `--no-server`, this step can be omitted.)
Expand All @@ -41,23 +40,19 @@ In the main directory, invoke `mx help` to see the list of commands. Most of the

## Building images

After running `mx build` you will find the following symlink to the `native-image` tool in your `substratevm` directory:
After running `mx build` you can use `mx native-image` to build native images. You can specify the main entry point, i.e., the application you want to create the image for. For more information run `mx native-image --help`.

native-image -> svmbuild/native-image-root/linux-amd64/bin/native-image

Use this tool to build native images. You can specify the main entry point, i.e., the application you want to create the image for. For more information run `./native-image --help`.

Native image generation is performed by a Java program that runs on JDK 8 with JVMCI. You can debug it with a regular Java debugger. Use `./native-image --debug-attach` to start native image generation so that it waits for a Java debugger to attach first (by default, at port 8000). In Eclipse, use the debugging configuration "substratevm-localhost-8000" to attach to it. This debugging configuration is automatically generated by `mx ideinit`.
Native image generation is performed by a Java program that runs on JDK 8 with JVMCI. You can debug it with a regular Java debugger. Use `mx native-image --debug-attach` to start native image generation so that it waits for a Java debugger to attach first (by default, at port 8000). In Eclipse, use the debugging configuration "substratevm-localhost-8000" to attach to it. This debugging configuration is automatically generated by `mx ideinit`.

If you find yourself having to debug into the Graal level of SubstrateVM, you should read the Graal [debugging](../compiler/docs/Debugging.md) page. You can use Ideal Graph Visualizer to view individual compilation steps:
```bash
mx igv &>/dev/null &
./native-image --no-server HelloWorld -H:Dump= -H:MethodFilter=HelloWorld.*
mx native-image HelloWorld -H:Dump= -H:MethodFilter=HelloWorld.*
```

## Images and Entry Points

An SVM image can be built as a standalone executable, which is the default, or as a shared library by passing `-shared` to `native-image`. For an image to be useful, it needs to have at least one entry point method.
An SVM image can be built as a standalone executable, which is the default, or as a shared library by passing `--shared` to `native-image`. For an image to be useful, it needs to have at least one entry point method.

For executables, SVM supports Java main methods with a signature that takes the command-line arguments as an array of strings:

Expand Down
81 changes: 20 additions & 61 deletions substratevm/mx.substratevm/mx_substratevm.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,16 @@
suite = mx.suite('substratevm')
svmSuites = [suite]

orig_command_gate = mx.command_function('gate')
orig_command_build = mx.command_function('build')

allow_native_image_build = True
native_image_build_veto = None
gate_run = False

def gate(args):
global gate_run
gate_run = True
orig_command_gate(args)

def build(args, vm=None):
if any([opt in args for opt in ['-h', '--help']]):
Expand All @@ -80,12 +87,15 @@ def build(args, vm=None):
if not _host_os_supported():
mx.abort('build: SubstrateVM can be built only on Darwin, Linux and Windows platforms')

global allow_native_image_build
if '--warning-as-error' in args and '--force-javac' not in args:
# --warning-as-error with ecj is buggy (GR-3969)
allow_native_image_build = False
global native_image_build_veto
if svm_suite().primary and not gate_run:
native_image_build_veto = 'No SVM gate-run'
elif mx.get_os() == 'windows':
native_image_build_veto = mx.get_os() + ' currently not supported'
elif '--warning-as-error' in args and '--force-javac' not in args:
native_image_build_veto = 'Building with ejc + --warning-as-error (see GR-3969)'
else:
allow_native_image_build = True
native_image_build_veto = None

orig_command_build(args, vm)

Expand Down Expand Up @@ -289,23 +299,13 @@ def native_image_extract_dependencies(args):
deps += [language_suite_name + ':' + dep for dep in language_native_deps]
return deps

def native_image_symlink_path(native_image_root, platform_specific=True):
symlink_path = join(svm_suite().dir, basename(native_image_path(native_image_root)))
if platform_specific:
symlink_path += '-' + platform_subdir()
return symlink_path

def native_image_on_jvm(args):
driver_cp = [join(suite_native_image_root(), 'lib', subdir, '*.jar') for subdir in ['boot', 'jvmci', 'graalvm']]
driver_cp += [join(suite_native_image_root(), 'lib', 'svm', tail) for tail in ['*.jar', join('builder', '*.jar')]]
driver_cp = list(itertools.chain.from_iterable(glob.glob(cp) for cp in driver_cp))
run_java(['-Dnative-image.root=' + suite_native_image_root(), '-cp', ":".join(driver_cp), mx.dependency('substratevm:SVM_DRIVER').mainClass] + args)

def bootstrap_native_image(native_image_root, svmDistribution, graalDistribution, librarySupportDistribution):
if not allow_native_image_build:
mx.logv('Detected building with ejc + --warning-as-error -> suppress bootstrap_native_image')
return

bootstrap_command = list(GRAAL_COMPILER_FLAGS)
bootstrap_command += locale_US_args()
bootstrap_command += substratevm_version_args()
Expand All @@ -331,8 +331,8 @@ def bootstrap_native_image(native_image_root, svmDistribution, graalDistribution
if mx._opts.strip_jars:
bootstrap_command += ['-H:-VerifyNamingConventions']

if mx.get_os() == 'windows':
mx.log('Skip building native-image executable on ' + mx.get_os())
if native_image_build_veto:
mx.log('Skip building native-image executable: ' + native_image_build_veto)
else:
run_java(bootstrap_command)
mx.logv('Built ' + native_image_path(native_image_root))
Expand Down Expand Up @@ -375,13 +375,6 @@ def native_image_extract_dists(subdir, dist_names):
for clibrary_path in clibrary_paths():
copy_tree(clibrary_path, join(native_image_root, join(svm_subdir, 'clibraries')))

# Create platform-specific symlink to native-image in svm_suite().dir
symlink_path = remove_existing_symlink(native_image_symlink_path(native_image_root))
relsymlink(native_image_path(native_image_root), symlink_path)
# Finally create default symlink to native-image in svm_suite().dir
symlink_path = remove_existing_symlink(native_image_symlink_path(native_image_root, platform_specific=False))
relsymlink(native_image_path(native_image_root), symlink_path)

class BootstrapNativeImage(mx.Project):
def __init__(self, suite, name, deps, workingSets, theLicense=None, **kwargs):
super(BootstrapNativeImage, self).__init__(suite, name, "", [], deps, workingSets, suite.dir, theLicense)
Expand All @@ -407,39 +400,10 @@ def __init__(self, args, project):
super(NativeImageBootstrapTask, self).__init__(args, min(8, mx.cpu_count()), project)
self._newestOutput = None

def _allow_bootstrapping(self):
return self.subject.suite == svm_suite()

def __str__(self):
prefix = "Bootstrapping " if self._allow_bootstrapping() else "Skip bootstrapping "
return prefix + self.subject.name

def _shouldRebuildNativeImage(self):
# Only bootstrap native-image for the most-specific svm_suite
if not self._allow_bootstrapping():
return False, 'Skip bootstrapping'

supress = mx.get_env("SUPPRESS_NATIVE_IMAGE_REBUILD", 'false')
if supress.lower() in ('false', '0', 'no', ''):
supress = False
elif supress.lower() in ('true', '1', 'yes'):
supress = True
else:
mx.abort("Could not understand SUPPRESS_NATIVE_IMAGE_REBUILD=" + supress)
if supress:
# Only bootstrap if it doesn't already exist
symlink_path = native_image_symlink_path(self.subject.native_image_root)
if exists(symlink_path):
mx.log('Suppressed rebuilding native-image (delete ' + symlink_path + ' to allow rebuilding).')
return False, 'Already bootstrapped'

return True, ''
return "Bootstrapping " + self.subject.name

def build(self):
shouldRebuild = self._shouldRebuildNativeImage()[0]
if not shouldRebuild:
return

bootstrap_native_image(
native_image_root=self.subject.native_image_root,
svmDistribution=self.subject.svmDistribution,
Expand All @@ -454,14 +418,8 @@ def clean(self, forBuild=False):
native_image_root = self.subject.native_image_root
if exists(native_image_root):
remove_tree(native_image_root)
remove_existing_symlink(native_image_symlink_path(native_image_root))
remove_existing_symlink(native_image_symlink_path(native_image_root, platform_specific=False))

def needsBuild(self, newestInput):
shouldRebuild, reason = self._shouldRebuildNativeImage()
if not shouldRebuild:
return False, reason

witness = self.newestOutput()
if not self._newestOutput or witness.isNewerThan(self._newestOutput):
self._newestOutput = witness
Expand Down Expand Up @@ -932,6 +890,7 @@ def fetch_languages(args, early_exit=True):
))

mx.update_commands(suite, {
'gate': [gate, '[options]'],
'build': [build, ''],
'helloworld' : [lambda args: native_image_context_run(helloworld, args), ''],
'cinterfacetutorial' : [lambda args: native_image_context_run(cinterfacetutorial, args), ''],
Expand Down

0 comments on commit c825246

Please sign in to comment.