@Override
	public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch,
			IProgressMonitor monitor) throws CoreException {

		boolean isHeadless =
			configuration.getType().getIdentifier().equals(GhidraLaunchUtils.HEADLESS_LAUNCH);
		ILaunchConfigurationWorkingCopy wc = configuration.getWorkingCopy();
		
		// Get the launch properties associated with the version of Ghidra that is trying to launch
		String projectName =
			wc.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, "");
		IJavaProject javaProject = GhidraProjectUtils.getGhidraProject(projectName);
		if (javaProject == null) {
			EclipseMessageUtils.showErrorDialog("Failed to launch project \"" + projectName +
				"\".\nDoes not appear to be a Ghidra project.");
			return;
		}
		IFolder ghidraFolder =
			javaProject.getProject().getFolder(GhidraProjectUtils.GHIDRA_FOLDER_NAME);
		AppConfig appConfig;
		String ghidraInstallPath = ghidraFolder.getLocation().toOSString();
		try {
			appConfig = new AppConfig(new File(ghidraInstallPath));
		}
		catch (ParseException | IOException e) {
			EclipseMessageUtils.showErrorDialog(
				"Failed to launch project \"" + projectName + "\".\n" + e.getMessage());
			return;
		}

		// Make sure there isn't a build/ directory present...it messes up the classpath.
		// The build directory could exist if the user built an extension from the command line
		// rather than from the Eclipse wizard
		if (javaProject.getProject().getFolder("build").exists()) {
			EclipseMessageUtils.showErrorDialog("Failed to launch project \"" + projectName +
				"\".\nDelete top-level 'build' directory and try again.");
			return;
		}

		// Set program arguments
		String customProgramArgs =
			configuration.getAttribute(GhidraLaunchUtils.ATTR_PROGAM_ARGUMENTS, "").trim();
		String programArgs =
			isHeadless ? "ghidra.app.util.headless.AnalyzeHeadless" : "ghidra.GhidraRun";
		programArgs += " " + customProgramArgs;
		wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, programArgs);
		if (isHeadless && customProgramArgs.isEmpty()) {
			EclipseMessageUtils.showInfoDialog("Ghidra Run Configuration",
				"Headless launch is being performed without any command line arguments!\n\n" +
					"Edit the \"" + configuration.getName() +
					"\" run configuration's program arguments to customize headless behavior. " +
					"See support/analyzeHeadlessREADME.html for more information.");
		}

		// Set VM arguments
		String vmArgs = appConfig.getLaunchProperties().getVmArgs();
		vmArgs += " " + configuration.getAttribute(GhidraLaunchUtils.ATTR_VM_ARGUMENTS, "").trim();
		vmArgs += " -Dghidra.external.modules=\"%s%s%s\"".formatted(
			javaProject.getProject().getLocation(), File.pathSeparator,
			getProjectDependencyDirs(javaProject));
		File pyDevSrcDir = PyDevUtils.getPyDevSrcDir();
		if (pyDevSrcDir != null) {
			vmArgs += " " + "-Declipse.pysrc.dir=\"" + pyDevSrcDir + "\"";
		}
		
		//---------Legacy properties--------------
		vmArgs += " " + "-Declipse.install.dir=\"" +
			Platform.getInstallLocation().getURL().getFile() + "\"";
		vmArgs += " " + "-Declipse.workspace.dir=\"" +
			ResourcesPlugin.getWorkspace().getRoot().getLocation() + "\"";
		vmArgs += " " + "-Declipse.project.dir=\"" + javaProject.getProject().getLocation() + "\"";
		vmArgs += " " + "-Declipse.project.dependencies=\"" +
			getProjectDependencyDirs(javaProject) + "\"";
		//----------------------------------------
		
		wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, vmArgs);

		// Handle special debug mode tasks
		if (mode.equals("debug")) {
			handleDebugMode();
		}

		super.launch(wc.doSave(), mode, launch, monitor);
	}
The Ghidra Launch delegate handles the final launch of Ghidra.
We can do any extra custom launch behavior here.
GhidraBuild/EclipsePlugins/GhidraDev/GhidraDevPlugin/src/main/java/ghidradev/ghidraprojectcreator/launchers/GhidraLaunchDelegate.java