@@ -238,6 +238,64 @@ private boolean commandExists(String... cmd) {
238238 // ── Windows ────────────────────────────────────────────────────────────
239239
240240 /** Pure detection, no dialog — used by run() before showing anything. */
241+ private static final String WINLIBS_URL =
242+ "https://github.com/brechtsanders/winlibs_mingw/releases/download/" +
243+ "14.2.0posix-19.1.1-12.0.0-ucrt-r2/" +
244+ "winlibs-x86_64-posix-seh-gcc-14.2.0-mingw-w64ucrt-12.0.0-r2.zip" ;
245+
246+ public static File getPortableGccDir () {
247+ return new File (System .getenv ("APPDATA" ) + "\\ CppMode\\ gcc\\ mingw64\\ bin" );
248+ }
249+
250+ public static File getPortableGpp () {
251+ return new File (getPortableGccDir (), "g++.exe" );
252+ }
253+
254+ private boolean installPortableGcc () {
255+ File gccDir = new File (System .getenv ("APPDATA" ) + "\\ CppMode\\ gcc" );
256+ gccDir .mkdirs ();
257+ File zipFile = new File (gccDir , "winlibs-gcc.zip" );
258+ try {
259+ setStep ("Downloading portable g++ (WinLibs GCC 14.2)..." );
260+ appendLog ("Source: " + WINLIBS_URL );
261+ appendLog ("Destination: " + gccDir .getAbsolutePath ());
262+ appendLog ("Size: ~130 MB — please wait..." );
263+ try (java .io .InputStream in = new java .net .URI (WINLIBS_URL ).toURL ().openStream ();
264+ java .io .OutputStream out = new java .io .FileOutputStream (zipFile )) {
265+ byte [] buf = new byte [64 * 1024 ];
266+ long total = 0 ; int n ;
267+ while ((n = in .read (buf )) != -1 ) {
268+ if (cancelled .get ()) return false ;
269+ out .write (buf , 0 , n );
270+ total += n ;
271+ if (total % (5 * 1024 * 1024 ) < buf .length )
272+ appendLog ("Downloaded " + (total / (1024 * 1024 )) + " MB..." );
273+ }
274+ }
275+ setStep ("Extracting gcc..." );
276+ appendLog ("Extracting to " + gccDir .getAbsolutePath ());
277+ // Use PowerShell Expand-Archive (available on all modern Windows)
278+ Process extract = new ProcessBuilder (
279+ "powershell" , "-NoProfile" , "-Command" ,
280+ "Expand-Archive -Force -Path '" + zipFile .getAbsolutePath () +
281+ "' -DestinationPath '" + gccDir .getAbsolutePath () + "'" )
282+ .redirectErrorStream (true ).start ();
283+ streamToLog (extract );
284+ int code = extract .waitFor ();
285+ zipFile .delete (); // clean up zip after extraction
286+ if (code != 0 ) { appendLog ("Extraction failed." ); return false ; }
287+ if (!getPortableGpp ().exists ()) {
288+ appendLog ("g++.exe not found after extraction -- unexpected zip structure." );
289+ return false ;
290+ }
291+ appendLog ("Portable g++ installed: " + getPortableGpp ().getAbsolutePath ());
292+ return true ;
293+ } catch (Exception e ) {
294+ appendLog ("Error: " + e .getMessage ());
295+ return false ;
296+ }
297+ }
298+
241299 private java .util .List <String > detectWindowsMissing () {
242300 String pacman = findWindowsPacman ();
243301 boolean haveGpp = pacman != null ? false : commandExists ("g++" , "--version" );
@@ -321,6 +379,13 @@ private boolean[] windowsLibsPresentDetailed() {
321379 */
322380 private boolean installWindowsToolchain (String existingPacman ) {
323381 try {
382+ // Prefer portable gcc (no MSYS2 needed) unless MSYS2 already installed.
383+ if (existingPacman == null && !getPortableGpp ().exists ()) {
384+ if (!installPortableGcc ()) return false ;
385+ if (cancelled .get ()) return false ;
386+ // Portable gcc bundles everything -- no pacman step needed.
387+ return true ;
388+ }
324389 String pacman = existingPacman ;
325390 if (pacman == null ) {
326391 File installer = File .createTempFile ("msys2-installer" , ".exe" );
0 commit comments