From 01c6df1e8ca367de095fb98e0eb1438bb0d04678 Mon Sep 17 00:00:00 2001
From: Eran Ifrah <eran@codelite.org>
Date: Sun, 12 Jan 2025 18:54:16 +0200
Subject: [PATCH] CodeLite doesn't detect existing mingw-w64 installations

Added new compiler locator (MSW only) that checks for gcc/clang
using the PATH env variable.

fixes: https://github.com/eranif/codelite/issues/3326

Signed-off-by: Eran Ifrah <eran@codelite.org>
---
 .../CompilerLocator/CompilerLocatorMSYS2.cpp  | 52 ++++++++++---------
 .../CompilerLocator/CompilerLocatorMSYS2.hpp  | 18 +++++--
 Plugin/CompilersDetectorManager.cpp           | 50 +++++++++---------
 Plugin/compiler.cpp                           |  2 +-
 Plugin/globals.cpp                            |  2 +-
 5 files changed, 69 insertions(+), 55 deletions(-)

diff --git a/Plugin/CompilerLocator/CompilerLocatorMSYS2.cpp b/Plugin/CompilerLocator/CompilerLocatorMSYS2.cpp
index a427e38394..8e4539c716 100644
--- a/Plugin/CompilerLocator/CompilerLocatorMSYS2.cpp
+++ b/Plugin/CompilerLocator/CompilerLocatorMSYS2.cpp
@@ -1,11 +1,10 @@
 #include "CompilerLocatorMSYS2.hpp"
 
-#include "GCCMetadata.hpp"
-#include "Platform/Platform.hpp"
 #include "compiler.h"
 #include "file_logger.h"
 
 #include <wx/filename.h>
+#include <wx/tokenzr.h>
 
 // --------------------------------------------------
 // --------------------------------------------------
@@ -36,27 +35,39 @@ std::vector<std::unordered_map<wxString, wxString>> TOOLCHAINS = {
 };
 }
 
-CompilerLocatorMSYS2Usr::CompilerLocatorMSYS2Usr()
-{
-    m_repository = "";
-    m_msys2.SetChroot("\\usr");
-}
+CompilerLocatorMSYS2Usr::CompilerLocatorMSYS2Usr() { m_msys2.SetChroot("\\usr"); }
 CompilerLocatorMSYS2Usr::~CompilerLocatorMSYS2Usr() {}
 
-CompilerLocatorMSYS2Mingw64::CompilerLocatorMSYS2Mingw64()
-{
-    m_repository = "mingw64";
-    m_msys2.SetChroot("\\mingw64");
-}
+CompilerLocatorMSYS2Mingw64::CompilerLocatorMSYS2Mingw64() { m_msys2.SetChroot("\\mingw64"); }
 
 CompilerLocatorMSYS2Mingw64::~CompilerLocatorMSYS2Mingw64() {}
 
-CompilerLocatorMSYS2Clang64::CompilerLocatorMSYS2Clang64()
+CompilerLocatorMSYS2Clang64::CompilerLocatorMSYS2Clang64() { m_msys2.SetChroot("\\clang64"); }
+CompilerLocatorMSYS2Clang64::~CompilerLocatorMSYS2Clang64() {}
+
+CompilerLocatorMSYS2Env::CompilerLocatorMSYS2Env() {}
+CompilerLocatorMSYS2Env::~CompilerLocatorMSYS2Env() {}
+
+bool CompilerLocatorMSYS2Env::Locate()
 {
-    m_repository = "clang64";
-    m_msys2.SetChroot("\\clang64");
+    clDEBUG() << "Locating compiler based on PATH environment variable" << endl;
+    m_compilers.clear();
+    wxString path_env;
+    if (!::wxGetEnv("PATH", &path_env)) {
+        return false;
+    }
+
+    wxArrayString paths_to_try = ::wxStringTokenize(path_env, ";", wxTOKEN_STRTOK);
+    for (const auto& path : paths_to_try) {
+        clDEBUG() << "Tyring to locate compiler at:" << path << endl;
+        auto cmp = CompilerLocatorMSYS2::Locate(path);
+        if (cmp) {
+            clDEBUG() << "Found compiler:" << cmp->GetName() << endl;
+            m_compilers.push_back(cmp);
+        }
+    }
+    return !m_compilers.empty();
 }
-CompilerLocatorMSYS2Clang64::~CompilerLocatorMSYS2Clang64() {}
 
 // --------------------------------------------------
 // --------------------------------------------------
@@ -102,13 +113,6 @@ CompilerPtr CompilerLocatorMSYS2::TryToolchain(const wxString& folder,
         return nullptr;
     }
 
-    // define the toolchain name
-    wxString basename = m_repository;
-    if (!basename.empty()) {
-        basename << "/";
-    }
-    basename << "gcc";
-
     // create new compiler
     CompilerPtr compiler(new Compiler(nullptr));
     compiler->SetName(gxx.GetFullPath());
@@ -132,7 +136,7 @@ CompilerPtr CompilerLocatorMSYS2::TryToolchain(const wxString& folder,
 
 CompilerPtr CompilerLocatorMSYS2::Locate(const wxString& folder)
 {
-    // check for g++
+    // check for g++/clang++
     for (const auto& toolchain : TOOLCHAINS) {
         auto cmp = TryToolchain(folder, toolchain);
         if (cmp) {
diff --git a/Plugin/CompilerLocator/CompilerLocatorMSYS2.hpp b/Plugin/CompilerLocator/CompilerLocatorMSYS2.hpp
index 7aa43d0cd0..b784e2b444 100644
--- a/Plugin/CompilerLocator/CompilerLocatorMSYS2.hpp
+++ b/Plugin/CompilerLocator/CompilerLocatorMSYS2.hpp
@@ -1,11 +1,9 @@
-#ifndef COMPILERLOCATORMSYS2_HPP
-#define COMPILERLOCATORMSYS2_HPP
+#pragma once
 
 #include "ICompilerLocator.h"
 #include "Platform/MSYS2.hpp"
 
 #include <unordered_map>
-#include <vector>
 #include <wx/filename.h>
 
 /// Locate for GCC compilers
@@ -13,7 +11,6 @@ class WXDLLIMPEXP_SDK CompilerLocatorMSYS2 : public ICompilerLocator
 {
 protected:
     MSYS2 m_msys2;
-    wxString m_repository;
 
 protected:
     wxFileName GetFileName(const wxString& bin_dir, const wxString& fullname) const;
@@ -55,4 +52,15 @@ class WXDLLIMPEXP_SDK CompilerLocatorMSYS2Mingw64 : public CompilerLocatorMSYS2
     CompilerLocatorMSYS2Mingw64();
     virtual ~CompilerLocatorMSYS2Mingw64();
 };
-#endif // COMPILERLOCATORMSYS2_HPP
+
+class WXDLLIMPEXP_SDK CompilerLocatorMSYS2Env : public CompilerLocatorMSYS2
+{
+public:
+    CompilerLocatorMSYS2Env();
+    virtual ~CompilerLocatorMSYS2Env();
+
+    /**
+     * @brief locate all compilers based on the PATH env variable
+     */
+    bool Locate() override;
+};
diff --git a/Plugin/CompilersDetectorManager.cpp b/Plugin/CompilersDetectorManager.cpp
index f1ba294a7c..c5fce61ad3 100644
--- a/Plugin/CompilersDetectorManager.cpp
+++ b/Plugin/CompilersDetectorManager.cpp
@@ -62,6 +62,7 @@ CompilersDetectorManager::CompilersDetectorManager()
     m_detectors.push_back(ICompilerLocator::Ptr_t(new CompilerLocatorMSYS2ClangUsr()));
     m_detectors.push_back(ICompilerLocator::Ptr_t(new CompilerLocatorMSYS2ClangClang64()));
     m_detectors.push_back(ICompilerLocator::Ptr_t(new CompilerLocatorMSYS2ClangMingw64()));
+    m_detectors.push_back(ICompilerLocator::Ptr_t(new CompilerLocatorMSYS2Env()));
 
 #elif defined(__WXGTK__)
     m_detectors.push_back(ICompilerLocator::Ptr_t(new CompilerLocatorGCC()));
@@ -91,9 +92,9 @@ bool CompilersDetectorManager::Locate()
     wxStringSet_t S;
 
     clDEBUG() << "scanning for compilers..." << endl;
-    for(auto locator : m_detectors) {
-        if(locator->Locate()) {
-            for(auto compiler : locator->GetCompilers()) {
+    for (auto locator : m_detectors) {
+        if (locator->Locate()) {
+            for (auto compiler : locator->GetCompilers()) {
                 /* Resolve symlinks and detect compiler duplication, e.g.:
                  *   /usr/bin/g++ (GCC)
                  *     -> /usr/bin/g++-9 (GCC-9)
@@ -103,8 +104,8 @@ bool CompilersDetectorManager::Locate()
                  * separate environment (vcvars*.bat) and its CXX is just
                  * 'cl.exe' */
                 wxString cxxPath = GetRealCXXPath(compiler);
-                if(compiler->GetCompilerFamily() == COMPILER_FAMILY_VC ||
-                   (!cxxPath.IsEmpty() && S.count(cxxPath) == 0)) {
+                if (compiler->GetCompilerFamily() == COMPILER_FAMILY_VC ||
+                    (!cxxPath.IsEmpty() && S.count(cxxPath) == 0)) {
                     S.insert(cxxPath);
                     m_compilersFound.push_back(compiler);
                 }
@@ -112,7 +113,7 @@ bool CompilersDetectorManager::Locate()
         }
     }
 
-    for(auto compiler : m_compilersFound) {
+    for (auto compiler : m_compilersFound) {
         MSWFixClangToolChain(compiler, m_compilersFound);
     }
 
@@ -123,9 +124,9 @@ bool CompilersDetectorManager::Locate()
 CompilerPtr CompilersDetectorManager::Locate(const wxString& folder)
 {
     m_compilersFound.clear();
-    for(auto detector : m_detectors) {
+    for (auto detector : m_detectors) {
         CompilerPtr comp = detector->Locate(folder);
-        if(comp) {
+        if (comp) {
             MSWFixClangToolChain(comp);
             return comp;
         }
@@ -135,9 +136,9 @@ CompilerPtr CompilersDetectorManager::Locate(const wxString& folder)
 
 bool CompilersDetectorManager::FoundMinGWCompiler() const
 {
-    for(size_t i = 0; i < m_compilersFound.size(); ++i) {
+    for (size_t i = 0; i < m_compilersFound.size(); ++i) {
         CompilerPtr compiler = m_compilersFound.at(i);
-        if(compiler->GetCompilerFamily() == COMPILER_FAMILY_MINGW) {
+        if (compiler->GetCompilerFamily() == COMPILER_FAMILY_MINGW) {
             // we found at least one MinGW compiler
             return true;
         }
@@ -148,16 +149,17 @@ bool CompilersDetectorManager::FoundMinGWCompiler() const
 void CompilersDetectorManager::MSWSuggestToDownloadMinGW(bool prompt)
 {
 #ifdef __WXMSW__
-    if(!prompt ||
-       ::wxMessageBox(_("Could not locate any MinGW compiler installed on your machine, would you like to "
-                        "install one now?"),
-                      "CodeLite", wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxCENTER | wxICON_QUESTION) == wxYES) {
+    if (!prompt || ::wxMessageBox(_("Could not locate any MinGW compiler installed on your machine, would you like to "
+                                    "install one now?"),
+                                  "CodeLite",
+                                  wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxCENTER | wxICON_QUESTION) == wxYES) {
 
         // open the install compiler page
         ::wxLaunchDefaultBrowser("https://docs.codelite.org/build/mingw_builds/#prepare-a-working-environment");
 
         // Prompt the user on how to proceed
-        ::wxMessageBox(_("After the installation process is done\nClick the 'Scan' button"), "CodeLite",
+        ::wxMessageBox(_("After the installation process is done\nClick the 'Scan' button"),
+                       "CodeLite",
                        wxOK | wxCENTER | wxICON_INFORMATION);
     }
 #endif // __WXMSW__
@@ -169,10 +171,10 @@ void CompilersDetectorManager::MSWFixClangToolChain(CompilerPtr compiler,
 // Update the toolchain (if Windows)
 #ifdef __WXMSW__
     ICompilerLocator::CompilerVec_t compilers;
-    if(allCompilers.empty()) {
+    if (allCompilers.empty()) {
         BuildSettingsConfigCookie cookie;
         CompilerPtr cmp = BuildSettingsConfigST::Get()->GetFirstCompiler(cookie);
-        while(cmp) {
+        while (cmp) {
             compilers.push_back(cmp);
             cmp = BuildSettingsConfigST::Get()->GetNextCompiler(cookie);
         }
@@ -180,20 +182,20 @@ void CompilersDetectorManager::MSWFixClangToolChain(CompilerPtr compiler,
         compilers.insert(compilers.end(), allCompilers.begin(), allCompilers.end());
     }
 
-    if(compiler->GetCompilerFamily() == COMPILER_FAMILY_CLANG) {
-        for(size_t i = 0; i < compilers.size(); ++i) {
+    if (compiler->GetCompilerFamily() == COMPILER_FAMILY_CLANG) {
+        for (size_t i = 0; i < compilers.size(); ++i) {
             CompilerPtr mingwCmp = compilers.at(i);
-            if(mingwCmp->GetCompilerFamily() == COMPILER_FAMILY_MINGW) {
+            if (mingwCmp->GetCompilerFamily() == COMPILER_FAMILY_MINGW) {
                 // Update the make and windres tool if no effective path is set
-                if(compiler->GetTool("MAKE").StartsWith("mingw32-make.exe")) {
+                if (compiler->GetTool("MAKE").StartsWith("mingw32-make.exe")) {
                     compiler->SetTool("MAKE", mingwCmp->GetTool("MAKE"));
                 }
-                if(compiler->GetTool("ResourceCompiler") == "windres.exe") {
+                if (compiler->GetTool("ResourceCompiler") == "windres.exe") {
                     compiler->SetTool("ResourceCompiler", mingwCmp->GetTool("ResourceCompiler"));
                 }
 
                 // MSYS2 Clang comes with its own headers and libraries
-                if(!compiler->GetName().Matches("CLANG ??bit ( MSYS2* )")) {
+                if (!compiler->GetName().Matches("CLANG ??bit ( MSYS2* )")) {
                     // Update the include paths
                     GCCMetadata compiler_md("MinGW");
                     wxArrayString includePaths;
@@ -217,7 +219,7 @@ void CompilersDetectorManager::MSWFixClangToolChain(CompilerPtr compiler,
 
 wxString CompilersDetectorManager::GetRealCXXPath(const CompilerPtr compiler) const
 {
-    if(compiler->GetName() == "rustc") {
+    if (compiler->GetName() == "rustc") {
         // rustc is a dummy compiler, do not touch it
         return compiler->GetTool("CXX");
     }
diff --git a/Plugin/compiler.cpp b/Plugin/compiler.cpp
index 231f7c7558..314d1b76db 100644
--- a/Plugin/compiler.cpp
+++ b/Plugin/compiler.cpp
@@ -503,7 +503,7 @@ wxString Compiler::GetSwitch(const wxString& name) const
 
 wxString Compiler::GetTool(const wxString& name) const
 {
-    std::map<wxString, wxString>::const_iterator iter = m_tools.find(name);
+    auto iter = m_tools.find(name);
     if (iter == m_tools.end()) {
         if (name == wxT("CC")) {
             // an upgrade, return the CXX
diff --git a/Plugin/globals.cpp b/Plugin/globals.cpp
index 100970911d..0d5d01ad33 100644
--- a/Plugin/globals.cpp
+++ b/Plugin/globals.cpp
@@ -757,7 +757,7 @@ DoReadProjectTemplatesFromFolder(const wxString& folder, std::list<ProjectPtr>&
                     continue;
                 }
                 list.push_back(proj);
-                clSYSTEM() << "Found template project:" << files[i] << "." << proj->GetName() << endl;
+                clDEBUG() << "Found template project:" << files[i] << "." << proj->GetName() << endl;
                 // load template icon
                 wxFileName fn(files.Item(i));
                 fn.SetFullName("icon.png");