1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-01 22:25:25 +02:00

Detect Homebrew installations on macOS hosts

We provide immediate access to tools installed using the Homebrew
package manager as for the MSYS2 package manager.
This commit is contained in:
John Dallaway 2025-06-27 16:04:00 +01:00
parent e112fc24b9
commit cf74c35e5b
6 changed files with 199 additions and 16 deletions

View file

@ -2,17 +2,18 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2 Bundle-ManifestVersion: 2
Bundle-Name: %pluginName Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.cdt.managedbuilder.gnu.ui; singleton:=true Bundle-SymbolicName: org.eclipse.cdt.managedbuilder.gnu.ui; singleton:=true
Bundle-Version: 8.7.300.qualifier Bundle-Version: 8.7.400.qualifier
Bundle-Activator: org.eclipse.cdt.managedbuilder.gnu.ui.GnuUIPlugin Bundle-Activator: org.eclipse.cdt.managedbuilder.gnu.ui.GnuUIPlugin
Bundle-Vendor: %providerName Bundle-Vendor: %providerName
Bundle-Localization: plugin Bundle-Localization: plugin
Export-Package: org.eclipse.cdt.managedbuilder.gnu.cygwin, Export-Package: org.eclipse.cdt.managedbuilder.gnu.cygwin,
org.eclipse.cdt.managedbuilder.gnu.macos;x-internal:=true,
org.eclipse.cdt.managedbuilder.gnu.mingw;x-internal:=true, org.eclipse.cdt.managedbuilder.gnu.mingw;x-internal:=true,
org.eclipse.cdt.managedbuilder.gnu.templates;x-internal:=true, org.eclipse.cdt.managedbuilder.gnu.templates;x-internal:=true,
org.eclipse.cdt.managedbuilder.gnu.ui org.eclipse.cdt.managedbuilder.gnu.ui
Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.33.0,4.0.0)", Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.33.0,4.0.0)",
org.eclipse.cdt.managedbuilder.core;bundle-version="[9.7.100,10.0.0)", org.eclipse.cdt.managedbuilder.core;bundle-version="[9.7.100,10.0.0)",
org.eclipse.cdt.core;bundle-version="[9.1.0,10.0.0)", org.eclipse.cdt.core;bundle-version="[9.2.0,10.0.0)",
org.eclipse.core.resources;bundle-version="[3.22.200,4)" org.eclipse.core.resources;bundle-version="[3.22.200,4)"
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-RequiredExecutionEnvironment: JavaSE-17

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?> <?eclipse version="3.0"?>
<!-- <!--
Copyright (c) 2005, 2024 Intel Corporation and others Copyright (c) 2005, 2025 Intel Corporation and others
This program and the accompanying materials This program and the accompanying materials
are made available under the terms of the Eclipse Public License 2.0 are made available under the terms of the Eclipse Public License 2.0
which accompanies this distribution, and is available at which accompanies this distribution, and is available at
@ -15,6 +15,7 @@ Contributors:
John Dallaway - extend optimization options (#828) John Dallaway - extend optimization options (#828)
John Dallaway - add archiver other objects option (#653) John Dallaway - add archiver other objects option (#653)
John Dallaway - extend language standard options (#944) John Dallaway - extend language standard options (#944)
John Dallaway - use macOS environment variable supplier (#1175)
--> -->
<plugin> <plugin>
<!-- Managed Make Builder Tool Specifications --> <!-- Managed Make Builder Tool Specifications -->
@ -2270,6 +2271,7 @@ Contributors:
</toolChain> </toolChain>
<toolChain <toolChain
archList="all" archList="all"
configurationEnvironmentSupplier="org.eclipse.cdt.managedbuilder.gnu.macos.MacosEnvironmentVariableSupplier"
id="cdt.managedbuild.toolchain.gnu.macosx.base" id="cdt.managedbuild.toolchain.gnu.macosx.base"
languageSettingsProviders="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser;org.eclipse.cdt.managedbuilder.core.GCCBuiltinSpecsDetector" languageSettingsProviders="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser;org.eclipse.cdt.managedbuilder.core.GCCBuiltinSpecsDetector"
name="%ToolChainName.Macosx" name="%ToolChainName.Macosx"

View file

@ -0,0 +1,64 @@
/*******************************************************************************
* Copyright (c) 2025 John Dallaway and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* John Dallaway - Initial implementation (#1175)
*******************************************************************************/
package org.eclipse.cdt.managedbuilder.gnu.macos;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.internal.core.Homebrew;
import org.eclipse.cdt.managedbuilder.core.IConfiguration;
import org.eclipse.cdt.managedbuilder.envvar.IBuildEnvironmentVariable;
import org.eclipse.cdt.managedbuilder.envvar.IConfigurationEnvironmentVariableSupplier;
import org.eclipse.cdt.managedbuilder.envvar.IEnvironmentVariableProvider;
import org.eclipse.cdt.managedbuilder.internal.envvar.BuildEnvVar;
import org.eclipse.core.runtime.Path;
/**
* Provides environment variables to support MBS builds using MacOS toolchains
*
* @noextend This class is not intended to be subclassed by clients.
*/
public class MacosEnvironmentVariableSupplier implements IConfigurationEnvironmentVariableSupplier {
private static final String ENV_PATH = "PATH"; //$NON-NLS-1$
@Override
public IBuildEnvironmentVariable getVariable(String variableName, IConfiguration configuration,
IEnvironmentVariableProvider provider) {
if (Homebrew.ENV_HOMEBREW_HOME.equals(variableName)) {
IEnvironmentVariable homebrewHomeVar = CCorePlugin.getDefault().getBuildEnvironmentManager()
.getVariable(Homebrew.ENV_HOMEBREW_HOME, (ICConfigurationDescription) null, false);
if (homebrewHomeVar == null) { // if HOMEBREW_HOME not already defined
String homebrewHome = Homebrew.getHomebrewHome();
if (homebrewHome == null) { // if Homebrew not installed
homebrewHome = ""; //$NON-NLS-1$
}
return new BuildEnvVar(Homebrew.ENV_HOMEBREW_HOME, new Path(homebrewHome).toOSString(),
IBuildEnvironmentVariable.ENVVAR_REPLACE);
}
} else if (variableName.equals(ENV_PATH)) {
String path = "${" + Homebrew.ENV_HOMEBREW_HOME + "}/bin"; //$NON-NLS-1$ //$NON-NLS-2$
return new BuildEnvVar(ENV_PATH, path, IBuildEnvironmentVariable.ENVVAR_PREPEND);
}
return null;
}
@Override
public IBuildEnvironmentVariable[] getVariables(IConfiguration configuration,
IEnvironmentVariableProvider provider) {
return new IBuildEnvironmentVariable[] { getVariable(Homebrew.ENV_HOMEBREW_HOME, configuration, provider),
getVariable(ENV_PATH, configuration, provider) };
}
}

View file

@ -0,0 +1,98 @@
/*******************************************************************************
* Copyright (c) 2012, 2025 Andrew Gvozdev and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Andrew Gvozdev - Original MinGW API and implementation
* John Dallaway - Initial Homebrew implementation (#1175)
*******************************************************************************/
package org.eclipse.cdt.internal.core;
import java.util.Objects;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
/**
* A collection of Homebrew-related utility methods.
*/
public class Homebrew {
public static final String ENV_HOMEBREW_HOME = "HOMEBREW_HOME"; //$NON-NLS-1$
private static final String ENV_PATH = "PATH"; //$NON-NLS-1$
private static String envPathValueCached = null;
private static String envHomebrewHomeValueCached = null;
private static String homebrewLocation = null;
private static boolean isHomebrewLocationCached = false;
private static String findHomebrewRoot(String envPathValue, String envHomebrewHomeValue) {
// Check $HOMEBREW_HOME which overrides default locations
if (envHomebrewHomeValue != null && !envHomebrewHomeValue.isEmpty()) {
String homebrewPath = envHomebrewHomeValue;
if (installationExists(homebrewPath)) {
return homebrewPath;
}
}
String defaultHomebrewPath = getDefaultHomebrewPath();
if (installationExists(defaultHomebrewPath)) {
return defaultHomebrewPath;
}
return null;
}
private static boolean installationExists(String homebrewHomeDir) {
return new Path(homebrewHomeDir).append("bin").toFile().isDirectory(); //$NON-NLS-1$
}
private static String getDefaultHomebrewPath() {
final String os = Platform.getOS();
final String arch = Platform.getOSArch();
if (Platform.OS_MACOSX.equals(os)) {
if (Platform.ARCH_AARCH64.equals(arch)) {
return "/opt/homebrew"; //$NON-NLS-1$
} else if (Platform.ARCH_X86_64.equals(arch)) {
return "/usr/local"; //$NON-NLS-1$
}
} else if (Platform.OS_LINUX.equals(os) && Platform.ARCH_X86_64.equals(arch)) {
return "/home/linuxbrew/.linuxbrew"; //$NON-NLS-1$
}
return null;
}
/**
* Find location where Homebrew is installed. Do not cache returned value.
*
* @return Homebrew installation path.
*/
public static String getHomebrewHome() {
IEnvironmentVariable varPath = CCorePlugin.getDefault().getBuildEnvironmentManager().getVariable(ENV_PATH,
(ICConfigurationDescription) null, true);
String envPathValue = varPath != null ? varPath.getValue() : null;
IEnvironmentVariable varHomebrewHome = CCorePlugin.getDefault().getBuildEnvironmentManager()
.getVariable(ENV_HOMEBREW_HOME, (ICConfigurationDescription) null, true);
String envHomebrewHomeValue = varHomebrewHome != null ? varHomebrewHome.getValue() : null;
if (isHomebrewLocationCached && Objects.equals(envPathValue, envPathValueCached)
&& Objects.equals(envHomebrewHomeValue, envHomebrewHomeValueCached)) {
return homebrewLocation;
}
homebrewLocation = findHomebrewRoot(envPathValue, envHomebrewHomeValue);
envPathValueCached = envPathValue;
envHomebrewHomeValueCached = envHomebrewHomeValue;
isHomebrewLocationCached = true;
return homebrewLocation;
}
}

View file

@ -11,7 +11,7 @@ Require-Bundle: org.eclipse.ui;bundle-version="[3.207.200,4)",
org.eclipse.core.resources;bundle-version="[3.22.200,4)", org.eclipse.core.resources;bundle-version="[3.22.200,4)",
org.eclipse.cdt.managedbuilder.core;bundle-version="[9.7.100,10)", org.eclipse.cdt.managedbuilder.core;bundle-version="[9.7.100,10)",
org.eclipse.cdt.managedbuilder.gnu.ui;bundle-version="[8.7.200,9)", org.eclipse.cdt.managedbuilder.gnu.ui;bundle-version="[8.7.200,9)",
org.eclipse.cdt.core;bundle-version="[9.1.0,10)" org.eclipse.cdt.core;bundle-version="[9.2.0,10)"
Bundle-RequiredExecutionEnvironment: JavaSE-17 Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-ActivationPolicy: lazy Bundle-ActivationPolicy: lazy
Export-Package: org.eclipse.cdt.managedbuilder.llvm.makegen; Export-Package: org.eclipse.cdt.managedbuilder.llvm.makegen;

View file

@ -21,17 +21,20 @@ import java.io.File;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import org.eclipse.cdt.internal.core.Homebrew;
import org.eclipse.cdt.internal.core.MinGW; import org.eclipse.cdt.internal.core.MinGW;
import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IConfiguration;
import org.eclipse.cdt.managedbuilder.envvar.IBuildEnvironmentVariable; import org.eclipse.cdt.managedbuilder.envvar.IBuildEnvironmentVariable;
import org.eclipse.cdt.managedbuilder.envvar.IConfigurationEnvironmentVariableSupplier; import org.eclipse.cdt.managedbuilder.envvar.IConfigurationEnvironmentVariableSupplier;
import org.eclipse.cdt.managedbuilder.envvar.IEnvironmentVariableProvider; import org.eclipse.cdt.managedbuilder.envvar.IEnvironmentVariableProvider;
import org.eclipse.cdt.managedbuilder.gnu.cygwin.GnuCygwinConfigurationEnvironmentSupplier; import org.eclipse.cdt.managedbuilder.gnu.cygwin.GnuCygwinConfigurationEnvironmentSupplier;
import org.eclipse.cdt.managedbuilder.gnu.macos.MacosEnvironmentVariableSupplier;
import org.eclipse.cdt.managedbuilder.gnu.mingw.MingwEnvironmentVariableSupplier; import org.eclipse.cdt.managedbuilder.gnu.mingw.MingwEnvironmentVariableSupplier;
import org.eclipse.cdt.managedbuilder.llvm.ui.preferences.LlvmPreferenceStore; import org.eclipse.cdt.managedbuilder.llvm.ui.preferences.LlvmPreferenceStore;
import org.eclipse.cdt.managedbuilder.llvm.util.Separators; import org.eclipse.cdt.managedbuilder.llvm.util.Separators;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
/** /**
* Contains LLVM environment variables. * Contains LLVM environment variables.
@ -42,7 +45,7 @@ public class LlvmEnvironmentVariableSupplier implements IConfigurationEnvironmen
// toggle for preference changes // toggle for preference changes
private static boolean preferencesChanged = true; private static boolean preferencesChanged = true;
// LLVM environment variable data structure // LLVM environment variable data structure
private static HashMap<String, LlvmBuildEnvironmentVariable> llvmEnvironmentVariables = new HashMap<>(6); private static HashMap<String, LlvmBuildEnvironmentVariable> llvmEnvironmentVariables = new HashMap<>(7);
// Environment variables for HashMap usage // Environment variables for HashMap usage
private static final String ENV_VAR_NAME_LLVM_BIN = "LLVM_BIN_PATH"; //$NON-NLS-1$ private static final String ENV_VAR_NAME_LLVM_BIN = "LLVM_BIN_PATH"; //$NON-NLS-1$
private static final String ENV_VAR_NAME_LLVMINTERP = "LLVMINTERP"; //$NON-NLS-1$ private static final String ENV_VAR_NAME_LLVMINTERP = "LLVMINTERP"; //$NON-NLS-1$
@ -52,10 +55,12 @@ public class LlvmEnvironmentVariableSupplier implements IConfigurationEnvironmen
private static final String ENV_VAR_NAME_LIBRARIES = "LIBRARIES"; //$NON-NLS-1$ private static final String ENV_VAR_NAME_LIBRARIES = "LIBRARIES"; //$NON-NLS-1$
private static final List<String> LLVM_BIN_SELECTION_TOOLS = List.of("llvm-ar", "clang"); //$NON-NLS-1$ //$NON-NLS-2$ private static final List<String> LLVM_BIN_SELECTION_TOOLS = List.of("llvm-ar", "clang"); //$NON-NLS-1$ //$NON-NLS-2$
private static boolean isInitialized = false;
/** /**
* Initializes llvm environment variable paths from the system environment variables. * Initializes llvm environment variable paths from the system environment variables.
*/ */
public static void initializePaths() { //TODO: Is this actually called anywhere? public static void initializePaths() {
// get bin path // get bin path
String binPath = getBinPath(); String binPath = getBinPath();
// set LLVM bin path environment variable // set LLVM bin path environment variable
@ -69,16 +74,12 @@ public class LlvmEnvironmentVariableSupplier implements IConfigurationEnvironmen
// try to find mingw or cygwin path from PATH environment variable // try to find mingw or cygwin path from PATH environment variable
IBuildEnvironmentVariable envPath = llvmEnvironmentVariables.get(ENV_VAR_NAME_PATH); IBuildEnvironmentVariable envPath = llvmEnvironmentVariables.get(ENV_VAR_NAME_PATH);
IBuildEnvironmentVariable mingwPath = null, cygwinPath = null; IBuildEnvironmentVariable mingwPath = null, cygwinPath = null;
// if path is empty // try to find mingw path from MingwEnvironmentVariableSupplier
if (envPath == null) { IConfigurationEnvironmentVariableSupplier mingwEnvironmentVariables = new MingwEnvironmentVariableSupplier();
// try to find mingw path from MingwEnvironmentVariableSupplier mingwPath = mingwEnvironmentVariables.getVariable(ENV_VAR_NAME_PATH, null, null);
IConfigurationEnvironmentVariableSupplier mingwEnvironmentVariables = new MingwEnvironmentVariableSupplier(); // try to find cygwin path from GnuCygwinConfigurationEnvironmentSupplier
mingwPath = mingwEnvironmentVariables.getVariable(ENV_VAR_NAME_PATH, null, null); IConfigurationEnvironmentVariableSupplier cygwinEnvironmentVariables = new GnuCygwinConfigurationEnvironmentSupplier();
// try to find cygwin path from GnuCygwinConfigurationEnvironmentSupplier cygwinPath = cygwinEnvironmentVariables.getVariable(ENV_VAR_NAME_PATH, null, null);
IConfigurationEnvironmentVariableSupplier cygwinEnvironmentVariables = new GnuCygwinConfigurationEnvironmentSupplier();
cygwinPath = cygwinEnvironmentVariables.getVariable(ENV_VAR_NAME_PATH, null, null);
}
// if mingw found // if mingw found
if (mingwPath != null) { if (mingwPath != null) {
//form full path //form full path
@ -93,6 +94,14 @@ public class LlvmEnvironmentVariableSupplier implements IConfigurationEnvironmen
//TODO: Emit proper error message and enter it to Eclipse error log. //TODO: Emit proper error message and enter it to Eclipse error log.
e.printStackTrace(); e.printStackTrace();
} }
} else if (Platform.OS_MACOSX.equals(Platform.getOS())) {
// use MacosEnvironmentVariableSupplier to find PATH
IBuildEnvironmentVariable macosPath = new MacosEnvironmentVariableSupplier()
.getVariable(ENV_VAR_NAME_PATH, null, null);
if (macosPath != null) {
setLlvmEnvironmentVariable(Homebrew.ENV_HOMEBREW_HOME, Homebrew.getHomebrewHome());
pathStr += File.pathSeparator + macosPath.getValue();
}
} }
//initialize environment variable cache values //initialize environment variable cache values
setLlvmEnvironmentVariable(ENV_VAR_NAME_PATH, pathStr); setLlvmEnvironmentVariable(ENV_VAR_NAME_PATH, pathStr);
@ -440,15 +449,24 @@ public class LlvmEnvironmentVariableSupplier implements IConfigurationEnvironmen
return ""; //$NON-NLS-1$ return ""; //$NON-NLS-1$
} }
private static synchronized void init() {
if (!isInitialized) {
initializePaths();
isInitialized = true;
}
}
@Override @Override
public IBuildEnvironmentVariable getVariable(String variableName, IConfiguration configuration, public IBuildEnvironmentVariable getVariable(String variableName, IConfiguration configuration,
IEnvironmentVariableProvider provider) { IEnvironmentVariableProvider provider) {
init();
return llvmEnvironmentVariables.get(variableName); return llvmEnvironmentVariables.get(variableName);
} }
@Override @Override
public IBuildEnvironmentVariable[] getVariables(IConfiguration configuration, public IBuildEnvironmentVariable[] getVariables(IConfiguration configuration,
IEnvironmentVariableProvider provider) { IEnvironmentVariableProvider provider) {
init();
return llvmEnvironmentVariables.values().toArray(new IBuildEnvironmentVariable[0]); return llvmEnvironmentVariables.values().toArray(new IBuildEnvironmentVariable[0]);
} }
} }