8346719: Add relaunchers to the static JDK image for missing executables

Reviewed-by: alanb, erikj
This commit is contained in:
Magnus Ihse Bursie
2025-11-05 13:57:18 +00:00
parent c9a98169cb
commit 2dd15cf5bf
14 changed files with 678 additions and 190 deletions

View File

@@ -461,9 +461,9 @@ $(eval $(call SetupTarget, symbols-image, \
TARGET := symbols, \
))
$(eval $(call SetupTarget, static-launcher, \
$(eval $(call SetupTarget, static-launchers, \
MAKEFILE := StaticLibs, \
TARGET := static-launcher, \
TARGET := static-launchers, \
DEPS := hotspot-static-libs static-libs, \
))
@@ -1290,7 +1290,7 @@ ifeq ($(call isTargetOs, macosx), true)
legacy-images: mac-legacy-jre-bundle
endif
static-exploded-image: static-launcher exploded-image
static-exploded-image: static-launchers exploded-image
# These targets build the various documentation images
docs-jdk-image: docs-jdk

View File

@@ -48,8 +48,8 @@ ifneq ($(word 2, $(wildcard $(HOTSPOT_STATIC_LIB_PATH))), )
endif
# Find all modules with static libraries
STATIC_LIB_MODULES := $(patsubst $(SUPPORT_OUTPUTDIR)/modules_static-libs/%, \
%, $(wildcard $(SUPPORT_OUTPUTDIR)/modules_static-libs/*))
STATIC_LIB_MODULES := $(sort $(patsubst $(SUPPORT_OUTPUTDIR)/modules_static-libs/%, \
%, $(wildcard $(SUPPORT_OUTPUTDIR)/modules_static-libs/*)))
# Filter out known broken libraries. This is a temporary measure until
# proper support for these libraries can be provided.
@@ -123,13 +123,18 @@ else
$(error Unsupported platform)
endif
################################################################################
# Build the java static launcher
################################################################################
$(eval $(call SetupBuildLauncher, java, \
ENABLE_ARG_FILES := true, \
EXPAND_CLASSPATH_WILDCARDS := true, \
EXTRA_RCFLAGS := $(JAVA_RCFLAGS), \
VERSION_INFO_RESOURCE := $(JAVA_VERSION_INFO_RESOURCE), \
OPTIMIZATION := HIGH, \
MACOSX_PRIVILEGED := true, \
STATIC_LAUNCHER := true, \
CFLAGS := -DSTATIC_BUILD, \
LDFLAGS := $(LDFLAGS_STATIC_JDK), \
LIBS := $(STATIC_LIBS) $(EXTERNAL_LIBS), \
LINK_TYPE := C++, \
@@ -146,7 +151,53 @@ TARGETS += $(java)
JAVA_LAUNCHER := $(BUILD_LAUNCHER_java_TARGET)
static-launcher: $(java)
static-launchers: $(java)
################################################################################
# Build relaunchers (thin wrappers calling the java binary) for all other
# JDK launchers.
################################################################################
RELAUNCHER_SRC := $(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/launcher
# $1: The module name
# $2: The launcher name
define SetupRelauncher
$1_$2_LAUNCHER_ARGS_LINE := $$(call ReadFile, $$(SUPPORT_OUTPUTDIR)/static-native/relaunchers/$1/$2-relauncher-arguments.txt)
# Restore |||| with space
$1_$2_LAUNCHER_ARGS := '{ $$(subst ||||,$(SPACE),$$(strip $$(foreach a, $$($1_$2_LAUNCHER_ARGS_LINE), "-J$$a"$$(COMMA) )) ) }'
$$(eval $$(call SetupJdkExecutable, BUILD_relauncher_$2, \
NAME := $2, \
EXTRA_FILES := $$(RELAUNCHER_SRC)/relauncher.c, \
CFLAGS := -DLAUNCHER_ARGS=$$($1_$2_LAUNCHER_ARGS), \
LIBS_windows := shlwapi.lib, \
OUTPUT_DIR := $$(STATIC_LAUNCHER_OUTPUT_DIR), \
OBJECT_DIR := $$(STATIC_LAUNCHER_OUTPUT_DIR)/relaunchers/$2, \
))
TARGETS += $$(BUILD_relauncher_$2)
RELAUNCHERS += $$(BUILD_relauncher_$2_TARGET)
static-launchers: $$(BUILD_relauncher_$2)
endef
# Find all modules with launchers
LAUNCHER_MODULES := $(sort $(patsubst $(SUPPORT_OUTPUTDIR)/modules_static-launchers/%, \
%, $(wildcard $(SUPPORT_OUTPUTDIR)/modules_static-launchers/*)))
# Find launchers for each module
$(foreach module, $(LAUNCHER_MODULES), \
$(eval LAUNCHERS_$(module) := $(if $(wildcard \
$(SUPPORT_OUTPUTDIR)/modules_static-launchers/$(module)/module-included-launchers.txt), \
$(shell cat \
$(SUPPORT_OUTPUTDIR)/modules_static-launchers/$(module)/module-included-launchers.txt))) \
)
# For all launchers (except java and javaw), setup a relauncher build
$(foreach module, $(LAUNCHER_MODULES), \
$(foreach launcher, $(filter-out java javaw, $(LAUNCHERS_$(module))), \
$(eval $(call SetupRelauncher,$(module),$(launcher)))))
################################################################################
#
@@ -188,26 +239,72 @@ TARGETS += $(copy-from-jdk-image)
$(copy-from-jdk-image): | static-jdk-info
$(eval $(call SetupCopyFiles, copy-static-launcher, \
FILES := $(JAVA_LAUNCHER), \
$(eval $(call SetupCopyFiles, copy-static-launchers, \
FILES := $(JAVA_LAUNCHER) $(RELAUNCHERS), \
DEST := $(STATIC_JDK_IMAGE_DIR)/bin, \
))
TARGETS += $(copy-static-launcher)
TARGETS += $(copy-static-launchers)
$(eval $(call SetupCopyFiles, copy-static-launcher-debuginfo, \
$(eval $(call SetupCopyFiles, copy-static-launchers-debuginfo, \
SRC := $(STATIC_LAUNCHER_OUTPUT_DIR), \
DEST := $(STATIC_JDK_IMAGE_DIR)/bin, \
FILES := $(call FindDebuginfoFiles, $(STATIC_LAUNCHER_OUTPUT_DIR)), \
))
TARGETS += $(copy-static-launcher-debuginfo)
TARGETS += $(copy-static-launchers-debuginfo)
static-jdk-image: $(copy-from-jdk-image) $(copy-static-launcher) $(copy-static-launcher-debuginfo)
# Copy the microsoft runtime libraries on windows
ifeq ($(call isTargetOs, windows), true)
# Chmod to avoid permission issues if bundles are unpacked on unix platforms.
# Use separate macro calls in case the source files are not in the same
# directory.
$(eval $(call SetupCopyFiles, copy-windows-msvcr, \
DEST := $(STATIC_JDK_IMAGE_DIR)/bin, \
FILES := $(MSVCR_DLL), \
MACRO := copy-and-chmod-executable, \
))
TARGETS += $(copy-windows-msvcr)
$(eval $(call SetupCopyFiles, copy-windows-vcruntime, \
DEST := $(STATIC_JDK_IMAGE_DIR)/bin, \
FILES := $(VCRUNTIME_1_DLL), \
MACRO := copy-and-chmod-executable, \
))
TARGETS += $(copy-windows-vcruntime)
$(eval $(call SetupCopyFiles, copy-windows-msvcp, \
DEST := $(STATIC_JDK_IMAGE_DIR)/bin, \
FILES := $(MSVCP_DLL), \
MACRO := copy-and-chmod-executable, \
))
TARGETS += $(copy-windows-msvcp)
copy-windows-libs := $(copy-windows-msvcr) $(copy-windows-vcruntime) $(copy-windows-msvcp)
ifneq ($(UCRT_DLL_DIR), )
$(eval $(call SetupCopyFiles, copy-windows-ucrt, \
DEST := $(STATIC_JDK_IMAGE_DIR)/bin, \
SRC := $(UCRT_DLL_DIR), \
FILES := $(wildcard $(UCRT_DLL_DIR)/*.dll), \
MACRO := copy-and-chmod-executable, \
))
TARGETS += $(copy-windows-ucrt)
copy-windows-libs += $(copy-windows-ucrt)
endif
endif
static-jdk-image: $(copy-from-jdk-image) $(copy-static-launchers) \
$(copy-static-launchers-debuginfo) $(copy-windows-libs)
TARGETS += static-jdk-image
.PHONY: static-launcher static-jdk-image
.PHONY: static-launchers static-jdk-image
################################################################################

View File

@@ -43,6 +43,9 @@ LAUNCHER_CFLAGS += -I$(TOPDIR)/src/java.base/share/native/launcher \
MACOSX_PLIST_DIR := $(TOPDIR)/src/java.base/macosx/native/launcher
JAVA_MANIFEST := $(TOPDIR)/src/java.base/windows/native/launcher/java.manifest
INCLUDED_LAUNCHERS_FILE := $(SUPPORT_OUTPUTDIR)/modules_static-launchers/$(MODULE)/module-included-launchers.txt
INCLUDED_LAUNCHERS :=
################################################################################
# Build standard launcher.
@@ -74,19 +77,30 @@ define SetupBuildLauncherBody
$1_MAIN_MODULE := $(MODULE)
$1_RELAUNCHER_ARGUMENTS :=
ifneq ($$($1_MAIN_CLASS), )
$1_JAVA_ARGS += -Xms8m
$1_LAUNCHER_CLASS := -m $$($1_MAIN_MODULE)/$$($1_MAIN_CLASS)
endif
ifeq ($$($1_EXPAND_CLASSPATH_WILDCARDS), true)
$1_CFLAGS += -DEXPAND_CLASSPATH_WILDCARDS
ifeq ($$($1_ENABLE_ARG_FILES), true)
$1_CFLAGS += -DDISABLE_ARGFILE=JNI_FALSE
else
$1_CFLAGS += -DDISABLE_ARGFILE=JNI_TRUE
# This must be the first argument given, if it should be present
$1_RELAUNCHER_ARGUMENTS += -DjavaLauncherArgFiles=false
endif
ifeq ($$($1_ENABLE_ARG_FILES), true)
$1_CFLAGS += -DENABLE_ARG_FILES
ifeq ($$($1_EXPAND_CLASSPATH_WILDCARDS), true)
$1_CFLAGS += -DCLASSPATH_WILDCARDS=JNI_TRUE
else
$1_CFLAGS += -DCLASSPATH_WILDCARDS=JNI_FALSE
$1_RELAUNCHER_ARGUMENTS += -DjavaLauncherWildcards=false
endif
$1_RELAUNCHER_ARGUMENTS += -DjavaLauncherProgname=$1
ifeq ($(call isTargetOs, windows), true)
ifeq ($$($1_WINDOWS_JAVAW), true)
$1_CFLAGS += -DJAVAW
@@ -94,9 +108,14 @@ define SetupBuildLauncherBody
endif
ifneq ($$($1_JAVA_ARGS), )
$1_JAVA_ARGS_STR := '{ $$(strip $$(foreach a, \
$$(addprefix -J, $$($1_JAVA_ARGS)) $$($1_LAUNCHER_CLASS), "$$a"$(COMMA) )) }'
$1_PREFIXED_JAVA_ARGS := $$(addprefix -J, $$($1_JAVA_ARGS)) \
$$($1_LAUNCHER_CLASS)
$1_JAVA_ARGS_STR := '{ $$(strip $$(foreach a, $$($1_PREFIXED_JAVA_ARGS), \
"$$a"$(COMMA) )) }'
$1_CFLAGS += -DJAVA_ARGS=$$($1_JAVA_ARGS_STR)
# To preserve spaces, substitute them with a hopefully unique pattern
$1_RELAUNCHER_ARGUMENTS += \
-DjavaLauncherArgs=$$(subst $$(SPACE),||||,$$($1_PREFIXED_JAVA_ARGS))
endif
ifeq ($(call isTargetOs, macosx), true)
@@ -172,8 +191,28 @@ define SetupBuildLauncherBody
))
$1 += $$(BUILD_LAUNCHER_$1)
$1_RELAUNCHER_ARGUMENTS_FILE := \
$$(SUPPORT_OUTPUTDIR)/static-native/relaunchers/$$(MODULE)/$1-relauncher-arguments.txt
$1_VARDEPS := $$($1_RELAUNCHER_ARGUMENTS)
$1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, \
$$($1_RELAUNCHER_ARGUMENTS_FILE).vardeps)
$$($1_RELAUNCHER_ARGUMENTS_FILE):
$$(call MakeDir, $$(@D))
$$(ECHO) '$$($1_RELAUNCHER_ARGUMENTS)' > $$@
$1 += $$($1_RELAUNCHER_ARGUMENTS_FILE)
TARGETS += $$($1)
# Record the fact that this launcher is part of the current module.
INCLUDED_LAUNCHERS += $1
# Add a dependency from this launcher to the launcher list
$$(INCLUDED_LAUNCHERS_FILE): $$($1)
$$(BUILD_LAUNCHER_$1): $$(BUILD_PLIST_$1)
ifeq ($(call isTargetOs, macosx), true)
@@ -242,5 +281,14 @@ endif
################################################################################
# We need to keep track of which launchers are created by this module. This
# information is required for static builds, to know which relaunchers to
# create. The file module-included-launchers.txt is then read in StaticLibs.gmk.
$(INCLUDED_LAUNCHERS_FILE):
$(call MakeDir, $(@D))
$(ECHO) $(INCLUDED_LAUNCHERS) > $@
TARGETS += $(INCLUDED_LAUNCHERS_FILE)
endif # include guard
include MakeIncludeEnd.gmk

View File

@@ -73,7 +73,7 @@ ifeq ($(call isTargetOs, linux), true)
$(eval $(call SetupJdkExecutable, BUILD_JEXEC, \
NAME := jexec, \
SRC := $(TOPDIR)/src/$(MODULE)/unix/native/launcher, \
EXTRA_FILES := $(TOPDIR)/src/$(MODULE)/unix/native/launcher/jexec.c, \
OPTIMIZATION := LOW, \
EXTRA_HEADER_DIRS := libjli, \
CFLAGS_linux := -fPIC, \

View File

@@ -25,7 +25,6 @@
################################################################################
include LauncherCommon.gmk
include LibCommon.gmk
JPACKAGE_OUTPUT_DIR := \

View File

@@ -1,75 +0,0 @@
/*
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef _DEFINES_H
#define _DEFINES_H
#include "java.h"
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
/*
* This file contains commonly defined constants used only by main.c
* and should not be included by another file.
*/
#ifndef VERSION_STRING
/* make sure the compilation fails */
#error "VERSION_STRING must be defined"
#endif
/* Unused, but retained for JLI_Launch compatibility*/
#define DOT_VERSION "0.0"
#ifdef JAVA_ARGS
#ifdef PROGNAME
static const char* const_progname = PROGNAME;
#else
static char* const_progname = NULL;
#endif
static const char* const_jargs[] = JAVA_ARGS;
#else /* !JAVA_ARGS */
static const char* const_progname = "java";
static const char** const_jargs = NULL;
#endif /* JAVA_ARGS */
#ifdef LAUNCHER_NAME
static const char* const_launcher = LAUNCHER_NAME;
#else /* LAUNCHER_NAME */
static char* const_launcher = NULL;
#endif /* LAUNCHER_NAME */
#ifdef EXPAND_CLASSPATH_WILDCARDS
static const jboolean const_cpwildcard = JNI_TRUE;
#else
static const jboolean const_cpwildcard = JNI_FALSE;
#endif /* EXPAND_CLASSPATH_WILDCARDS */
#ifdef ENABLE_ARG_FILES
static const jboolean const_disable_argfile = JNI_FALSE;
#else
static const jboolean const_disable_argfile = JNI_TRUE;
#endif
#endif /*_DEFINES_H */

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,10 +30,60 @@
* tools. The rest of the files will be linked in.
*/
#include "defines.h"
#include "java.h"
#include "jli_util.h"
#include "jni.h"
// Unused, but retained for JLI_Launch compatibility
#define DOT_VERSION "0.0"
// This is reported when requesting a full version
static char* launcher = LAUNCHER_NAME;
// This is used as the name of the executable in the help message
static char* progname = PROGNAME;
#ifdef JAVA_ARGS
static const char* jargs[] = JAVA_ARGS;
#else
static const char** jargs = NULL;
#endif
static int jargc;
static jboolean cpwildcard = CLASSPATH_WILDCARDS;
static jboolean disable_argfile = DISABLE_ARGFILE;
#ifdef STATIC_BUILD
static void check_relauncher_argument(char* arg) {
if (strcmp(arg, "-J-DjavaLauncherWildcards=false") == 0) {
cpwildcard = JNI_FALSE;
}
const char *progname_prefix = "-J-DjavaLauncherProgname=";
size_t progname_prefix_len = strlen(progname_prefix);
if (strncmp(arg, progname_prefix, progname_prefix_len) == 0) {
progname = arg + progname_prefix_len;
}
const char *args_prefix = "-J-DjavaLauncherArgs=";
size_t args_prefix_len = strlen(args_prefix);
if (strncmp(arg, args_prefix, args_prefix_len) == 0) {
char* java_args_ptr = arg + args_prefix_len;
size_t java_args_len = strlen(arg) - args_prefix_len;
JLI_List java_args = JLI_List_new(java_args_len);
char* next_space;
while ((next_space = strchr(java_args_ptr, ' ')) != NULL) {
size_t next_arg_len = next_space - java_args_ptr;
JLI_List_addSubstring(java_args, java_args_ptr, next_arg_len);
java_args_ptr = next_space + 1;
}
JLI_List_add(java_args, java_args_ptr);
jargc = (int) java_args->size;
jargs = (const char**) java_args->elements;
}
}
#endif
/*
* Entry point.
*/
@@ -44,7 +94,7 @@ char **__initenv;
int WINAPI
WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow)
{
const jboolean const_javaw = JNI_TRUE;
const jboolean javaw = JNI_TRUE;
__initenv = _environ;
@@ -52,19 +102,25 @@ WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow)
JNIEXPORT int
main(int argc, char **argv)
{
const jboolean const_javaw = JNI_FALSE;
const jboolean javaw = JNI_FALSE;
#endif /* JAVAW */
int margc;
char** margv;
int jargc;
const char** jargv = const_jargs;
jargc = (sizeof(const_jargs) / sizeof(char *)) > 1
? sizeof(const_jargs) / sizeof(char *)
jargc = (sizeof(jargs) / sizeof(char *)) > 1
? sizeof(jargs) / sizeof(char *)
: 0; // ignore the null terminator index
JLI_InitArgProcessing(jargc > 0, const_disable_argfile);
#ifdef STATIC_BUILD
// Relaunchers always give -J-DjavaLauncherArgFiles as the first argument, if present
// We must check disable_argfile before calling JLI_InitArgProcessing.
if (argc > 1 && strcmp(argv[1], "-J-DjavaLauncherArgFiles=false") == 0) {
disable_argfile = JNI_TRUE;
}
#endif
JLI_InitArgProcessing(jargc > 0, disable_argfile);
#ifdef _WIN32
{
@@ -103,6 +159,9 @@ main(int argc, char **argv)
StdArg *stdargs = JLI_GetStdArgs();
for (i = 0 ; i < margc ; i++) {
margv[i] = stdargs[i].arg;
#ifdef STATIC_BUILD
check_relauncher_argument(margv[i]);
#endif
}
margv[i] = NULL;
}
@@ -127,6 +186,9 @@ main(int argc, char **argv)
}
// Iterate the rest of command line
for (i = 1; i < argc; i++) {
#ifdef STATIC_BUILD
check_relauncher_argument(argv[i]);
#endif
JLI_List argsInFile = JLI_PreprocessArg(argv[i], JNI_TRUE);
if (NULL == argsInFile) {
JLI_List_add(args, JLI_StringDup(argv[i]));
@@ -148,12 +210,12 @@ main(int argc, char **argv)
}
#endif /* WIN32 */
return JLI_Launch(margc, margv,
jargc, jargv,
jargc, jargs,
0, NULL,
VERSION_STRING,
DOT_VERSION,
(const_progname != NULL) ? const_progname : *margv,
(const_launcher != NULL) ? const_launcher : *margv,
progname,
launcher,
jargc > 0,
const_cpwildcard, const_javaw, 0);
cpwildcard, javaw, 0);
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define JAVA_EXECUTABLE_NAME "java"
#ifndef LAUNCHER_ARGS
#error LAUNCHER_ARGS must be defined
#endif
static char *launcher_args[] = LAUNCHER_ARGS;
int main(int argc, char *argv[]) {
////////////////////////////////////////////////////////////////////////////
// Create a fully qualified path to the java executable in the same
// directory as this file resides in.
char *our_full_path = realpath(argv[0], NULL);
if (our_full_path == NULL) {
perror("failed to get the full path of the executable");
return 1;
}
char *last_slash_pos = strrchr(our_full_path, '/');
if (last_slash_pos == NULL) {
fprintf(stderr, "no '/' found in the full path of the executable\n");
return 1;
}
size_t base_length = last_slash_pos - our_full_path + 1;
size_t java_path_length = base_length + strlen(JAVA_EXECUTABLE_NAME) + 1;
char *java_path = malloc(java_path_length);
if (java_path == NULL) {
perror("malloc failed");
return 1;
}
memcpy(java_path, our_full_path, base_length);
strcpy(java_path + base_length, JAVA_EXECUTABLE_NAME);
////////////////////////////////////////////////////////////////////////////
// Build the argument list: our executable name + launcher args + users args
int launcher_argsc = sizeof(launcher_args) / sizeof(char *);
char **java_args = malloc((launcher_argsc + argc + 1) * sizeof(char *));
if (java_args == NULL) {
perror("malloc failed");
return 1;
}
// Our executable name
java_args[0] = argv[0];
// Launcher arguments
for (int i = 0; i < launcher_argsc; i++) {
java_args[i + 1] = launcher_args[i];
}
// User arguments
for (int i = 1; i < argc; i++) {
java_args[launcher_argsc + i] = argv[i];
}
java_args[launcher_argsc + argc] = NULL;
////////////////////////////////////////////////////////////////////////////
// Finally execute the real java process with the constructed arguments
if (getenv("_JAVA_LAUNCHER_DEBUG")) {
char *program_name = basename(argv[0]);
fprintf(stderr, "%s: executing: '%s'", program_name, java_path);
for (int i = 0; java_args[i] != NULL; i++) {
fprintf(stderr, " '%s' ", java_args[i]);
}
fprintf(stderr, "\n");
}
execv(java_path, java_args);
// Should not reach here, unless something went wrong
perror("execv failed");
return 1;
}

View File

@@ -276,6 +276,9 @@ CreateExecutionEnvironment(int *pargc, char ***pargv,
char jdkroot[], jint so_jdkroot,
char jvmpath[], jint so_jvmpath,
char jvmcfg[], jint so_jvmcfg) {
/* Compute/set the name of the executable */
SetExecname(*pargv);
if (JLI_IsStaticallyLinked()) {
// With static builds, all JDK and VM natives are statically linked
// with the launcher executable. No need to manipulate LD_LIBRARY_PATH
@@ -297,9 +300,6 @@ CreateExecutionEnvironment(int *pargc, char ***pargv,
size_t new_runpath_size;
#endif /* SETENV_REQUIRED */
/* Compute/set the name of the executable */
SetExecname(*pargv);
/* Check to see if the jvmpath exists */
/* Find out where the JDK is that we will be using. */
if (!GetJDKInstallRoot(jdkroot, so_jdkroot, JNI_FALSE)) {

View File

@@ -0,0 +1,246 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <shlwapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#define JAVA_EXECUTABLE_NAME "java.exe"
#ifndef LAUNCHER_ARGS
#error LAUNCHER_ARGS must be defined
#endif
static char* launcher_args[] = LAUNCHER_ARGS;
char* quote_argument(char* arg) {
// See https://learn.microsoft.com/en-us/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way
// for an explanation of how to properly quote command lines for CreateProcess
size_t arg_length = strlen(arg);
if (strcspn(arg, " \t\n\v\"") == arg_length) {
// No quoting is needed
return arg;
}
// Worst-case buffer size: all characters need a backslash, and starting + end quotes
size_t buffer_size = arg_length * 2 + 3;
char* buffer = malloc(buffer_size);
if (buffer == NULL) {
return NULL;
}
int backslashes = 0;
char* write_pos = buffer;
char* read_pos = arg;
// Start with a quote character
*write_pos++ = '"';
while (*read_pos) {
while (*read_pos == '\\') {
read_pos++;
backslashes++;
}
if (*read_pos == '"') {
// Any potential backslashes before a quote needs to be doubled,
// and the quote needs to be escaped with an additional backslash
for (int i = 0; i < backslashes * 2 + 1; i++) {
*write_pos++ = '\\';
}
*write_pos++ = *read_pos++;
backslashes = 0;
} else {
// Backslashes not preceeding a quote are copied without escaping
for (int i = 0; i < backslashes; i++) {
*write_pos++ = '\\';
}
if (*read_pos) {
*write_pos++ = *read_pos++;
backslashes = 0;
}
}
}
// If the string ended with backslashes, they need to be doubled before
// the final quote character
for (int i = 0; i < backslashes; i++) {
*write_pos++ = '\\';
}
*write_pos++ = '"';
*write_pos = '\0';
return buffer;
}
int main(int argc, char* argv[]) {
////////////////////////////////////////////////////////////////////////////
// Create a fully qualified path to the java executable in the same
// directory as this file resides in.
// Calculate path length first
DWORD our_full_path_len = GetFullPathName(argv[0], 0, NULL, NULL);
if (our_full_path_len == 0) {
fprintf(stderr, "failed to get the full path of the executable: %lu\n", GetLastError());
return 1;
}
char* our_full_path = malloc(our_full_path_len + 1);
if (our_full_path == NULL) {
perror("malloc failed");
return 1;
}
if (GetFullPathName(argv[0], our_full_path_len + 1, our_full_path, NULL) == 0) {
fprintf(stderr, "failed to get the full path of the executable: %lu\n", GetLastError());
return 1;
}
char *last_slash_pos = strrchr(our_full_path, '\\');
if (last_slash_pos == NULL) {
fprintf(stderr, "no '\\' found in the full path of the executable\n");
return 1;
}
size_t base_length = last_slash_pos - our_full_path + 1;
size_t java_path_length = base_length + strlen(JAVA_EXECUTABLE_NAME) + 1;
char *java_path = malloc(java_path_length);
if (java_path == NULL) {
perror("malloc failed");
return 1;
}
memcpy(java_path, our_full_path, base_length);
strcpy(java_path + base_length, JAVA_EXECUTABLE_NAME);
////////////////////////////////////////////////////////////////////////////
// Build the argument list: our executable name + launcher args + users args
int launcher_argsc = sizeof(launcher_args) / sizeof(char *);
char **java_args = malloc((launcher_argsc + argc + 1) * sizeof(char *));
if (java_args == NULL) {
perror("malloc failed");
return 1;
}
// Our executable name
java_args[0] = quote_argument(argv[0]);
if (java_args[0] == NULL) {
perror("malloc failed");
return 1;
}
// Launcher arguments
for (int i = 0; i < launcher_argsc; i++) {
char* quoted = quote_argument(launcher_args[i]);
if (quoted == NULL) {
perror("malloc failed");
return 1;
}
java_args[i + 1] = quoted;
}
// User arguments
for (int i = 1; i < argc; i++) {
char* quoted = quote_argument(argv[i]);
if (quoted == NULL) {
perror("malloc failed");
return 1;
}
java_args[launcher_argsc + i] = quoted;
}
java_args[launcher_argsc + argc] = NULL;
// Windows needs the command line as a single string, not as an array of char*
size_t total_length = 0;
for (int i = 0; java_args[i] != NULL; i++) {
char* arg = java_args[i];
total_length += strlen(java_args[i]) + 1;
}
char* command_line = malloc(total_length);
if (command_line == NULL) {
perror("malloc failed");
return 1;
}
// Concatenate the quoted arguments with a space between them
char* write_pos = command_line;
for (int i = 0; java_args[i] != NULL; i++) {
size_t arg_len = strlen(java_args[i]);
memcpy(write_pos, java_args[i], arg_len);
write_pos += arg_len;
// Append a space
*write_pos++ = ' ';
}
// Replace the last space with a null terminator
write_pos--;
*write_pos = '\0';
////////////////////////////////////////////////////////////////////////////
// Finally execute the real java process with the constructed arguments
if (GetEnvironmentVariable("_JAVA_LAUNCHER_DEBUG", NULL, 0)) {
char *program_name = PathFindFileName(argv[0]);
fprintf(stderr, "%s: executing: '%s' '%s'\n", program_name, java_path, command_line);
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
// Windows has no equivalent of exec, so start the process and wait for it
// to finish, to be able to return the same exit code
if (!CreateProcess(java_path, command_line, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
fprintf(stderr, "CreateProcess failed: %lu\n", GetLastError());
return 1;
}
if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED) {
fprintf(stderr, "WaitForSingleObject failed: %lu\n", GetLastError());
return 1;
}
DWORD exit_code;
if (!GetExitCodeProcess(pi.hProcess, &exit_code)) {
fprintf(stderr, "GetExitCodeProcess failed: %lu\n", GetLastError());
return 1;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return exit_code;
}

View File

@@ -1,38 +1,3 @@
# Require javac
runtime/HiddenClasses/DefineHiddenClass.java 8346719 generic-all
# Require jstack
runtime/Thread/TestThreadDumpClassInitMonitor.java 8346719 generic-all
runtime/Thread/TestThreadDumpSMRInfo.java 8346719 generic-all
serviceability/tmtools/jstack/DaemonThreadTest.java 8346719 generic-all
serviceability/tmtools/jstack/JstackThreadTest.java 8346719 generic-all
serviceability/tmtools/jstack/SpreadLockTest.java 8346719 generic-all
serviceability/tmtools/jstack/ThreadNamesTest.java 8346719 generic-all
serviceability/tmtools/jstack/TraveledLockTest.java 8346719 generic-all
serviceability/tmtools/jstack/WaitNotifyThreadTest.java 8346719 generic-all
serviceability/tmtools/jstat/GcCapacityTest.java 8346719 generic-all
serviceability/tmtools/jstat/GcCauseTest01.java 8346719 generic-all
serviceability/tmtools/jstat/GcCauseTest02.java 8346719 generic-all
serviceability/tmtools/jstat/GcCauseTest03.java 8346719 generic-all
serviceability/tmtools/jstat/GcNewTest.java 8346719 generic-all
serviceability/tmtools/jstat/GcTest01.java 8346719 generic-all
serviceability/tmtools/jstat/GcTest02.java 8346719 generic-all
# Require jcmd
serviceability/HeapDump/DuplicateArrayClassesTest.java 8346719 generic-all
serviceability/HeapDump/FieldsInInstanceTest.java 8346719 generic-all
serviceability/attach/ConcAttachTest.java 8346719 generic-all
serviceability/attach/RemovingUnixDomainSocketTest.java 8346719 generic-all
serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java#default 8346719 generic-all
serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java#no-vmcontinuations 8346719 generic-all
# Require jhsdb
serviceability/sa/ClhsdbCDSCore.java 8346719 generic-all
serviceability/sa/ClhsdbFindPC.java#no-xcomp-core 8346719 generic-all
serviceability/sa/ClhsdbFindPC.java#xcomp-core 8346719 generic-all
serviceability/sa/ClhsdbPmap.java#core 8346719 generic-all
serviceability/sa/ClhsdbPstack.java#core 8346719 generic-all
# Dynamically link with JDK/VM native libraries
gtest/GTestWrapper.java 8356201 generic-all
gtest/LargePageGtests.java#use-large-pages 8356201 generic-all

View File

@@ -1,14 +1,26 @@
# Require jarsigner
java/lang/System/LoggerFinder/SignedLoggerFinderTest/SignedLoggerFinderTest.java 8346719 generic-all
java/util/jar/JarFile/jarVerification/MultiProviderTest.java 8346719 generic-all
###########################################################################
#
# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
###########################################################################
# Require jar
java/lang/System/MacEncoding/TestFileEncoding.java 8346719 generic-all
java/util/ResourceBundle/modules/basic/BasicTest.java 8346719 generic-all
# Require javac
java/util/ResourceBundle/modules/layer/LayerTest.java 8346719 generic-all
java/util/ResourceBundle/modules/unnamed/UnNamedTest.java 8346719 generic-all
# Require jps
java/util/concurrent/locks/Lock/TimedAcquireLeak.java 8346719 generic-all
# Currently empty

View File

@@ -1,29 +1,26 @@
# Requires javadoc
jdk/javadoc/tool/6964914/TestStdDoclet.java 8346719 generic-all
jdk/javadoc/tool/6964914/TestUserDoclet.java 8346719 generic-all
jdk/javadoc/tool/AddOpensTest.java 8346719 generic-all
jdk/javadoc/tool/EncodingTest.java 8346719 generic-all
jdk/javadoc/tool/EnsureNewOldDoclet.java 8346719 generic-all
jdk/javadoc/tool/QuietOption.java 8346719 generic-all
jdk/javadoc/tool/testLocaleOption/TestLocaleOption.java 8346719 generic-all
###########################################################################
#
# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
###########################################################################
# Requires javac
tools/javac/ClassPathTest/ClassPathTest.java 8346719 generic-all
tools/javac/Paths/ClassPath.java 8346719 generic-all
tools/javac/Paths/WildcardMineField.java 8346719 generic-all
tools/javac/T8132562/ClassPathWithDoubleQuotesTest.java 8346719 generic-all
tools/javac/file/MultiReleaseJar/MultiReleaseJarTest.java 8346719 generic-all
tools/javac/modules/AllDefaultTest.java 8346719 generic-all
tools/javac/modules/EnvVarTest.java 8346719 generic-all
tools/javac/modules/InheritRuntimeEnvironmentTest.java 8346719 generic-all
tools/javac/modules/NPEEmptyFileTest.java 8346719 generic-all
tools/javac/newlines/NewLineTest.java 8346719 generic-all
tools/javac/options/smokeTests/OptionSmokeTest.java 8346719 generic-all
tools/javac/platform/PlatformProviderTest.java 8346719 generic-all
tools/javac/processing/options/testPrintProcessorInfo/TestWithXstdout.java 8346719 generic-all
# Requires jar
tools/jdeps/MultiReleaseJar.java 8346719 generic-all
# Requires jimage
tools/javac/Paths/MineField.java 8346719 generic-all
# Currently empty

View File

@@ -1,2 +1,26 @@
# Requires jcmd
jdk/test/lib/hprof/HprofTest.java 8346719 generic-all
###########################################################################
#
# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
###########################################################################
# Currently empty