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-Name: %pluginName
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-Vendor: %providerName
Bundle-Localization: plugin
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.templates;x-internal:=true,
org.eclipse.cdt.managedbuilder.gnu.ui
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.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)"
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-17

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<?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
are made available under the terms of the Eclipse Public License 2.0
which accompanies this distribution, and is available at
@ -15,6 +15,7 @@ Contributors:
John Dallaway - extend optimization options (#828)
John Dallaway - add archiver other objects option (#653)
John Dallaway - extend language standard options (#944)
John Dallaway - use macOS environment variable supplier (#1175)
-->
<plugin>
<!-- Managed Make Builder Tool Specifications -->
@ -2270,6 +2271,7 @@ Contributors:
</toolChain>
<toolChain
archList="all"
configurationEnvironmentSupplier="org.eclipse.cdt.managedbuilder.gnu.macos.MacosEnvironmentVariableSupplier"
id="cdt.managedbuild.toolchain.gnu.macosx.base"
languageSettingsProviders="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser;org.eclipse.cdt.managedbuilder.core.GCCBuiltinSpecsDetector"
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.cdt.managedbuilder.core;bundle-version="[9.7.100,10)",
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-ActivationPolicy: lazy
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.List;
import org.eclipse.cdt.internal.core.Homebrew;
import org.eclipse.cdt.internal.core.MinGW;
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.gnu.cygwin.GnuCygwinConfigurationEnvironmentSupplier;
import org.eclipse.cdt.managedbuilder.gnu.macos.MacosEnvironmentVariableSupplier;
import org.eclipse.cdt.managedbuilder.gnu.mingw.MingwEnvironmentVariableSupplier;
import org.eclipse.cdt.managedbuilder.llvm.ui.preferences.LlvmPreferenceStore;
import org.eclipse.cdt.managedbuilder.llvm.util.Separators;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
/**
* Contains LLVM environment variables.
@ -42,7 +45,7 @@ public class LlvmEnvironmentVariableSupplier implements IConfigurationEnvironmen
// toggle for preference changes
private static boolean preferencesChanged = true;
// 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
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$
@ -52,10 +55,12 @@ public class LlvmEnvironmentVariableSupplier implements IConfigurationEnvironmen
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 boolean isInitialized = false;
/**
* 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
String binPath = getBinPath();
// 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
IBuildEnvironmentVariable envPath = llvmEnvironmentVariables.get(ENV_VAR_NAME_PATH);
IBuildEnvironmentVariable mingwPath = null, cygwinPath = null;
// if path is empty
if (envPath == null) {
// try to find mingw path from MingwEnvironmentVariableSupplier
IConfigurationEnvironmentVariableSupplier mingwEnvironmentVariables = new MingwEnvironmentVariableSupplier();
mingwPath = mingwEnvironmentVariables.getVariable(ENV_VAR_NAME_PATH, null, null);
// try to find cygwin path from GnuCygwinConfigurationEnvironmentSupplier
IConfigurationEnvironmentVariableSupplier cygwinEnvironmentVariables = new GnuCygwinConfigurationEnvironmentSupplier();
cygwinPath = cygwinEnvironmentVariables.getVariable(ENV_VAR_NAME_PATH, null, null);
}
// try to find mingw path from MingwEnvironmentVariableSupplier
IConfigurationEnvironmentVariableSupplier mingwEnvironmentVariables = new MingwEnvironmentVariableSupplier();
mingwPath = mingwEnvironmentVariables.getVariable(ENV_VAR_NAME_PATH, null, null);
// try to find cygwin path from GnuCygwinConfigurationEnvironmentSupplier
IConfigurationEnvironmentVariableSupplier cygwinEnvironmentVariables = new GnuCygwinConfigurationEnvironmentSupplier();
cygwinPath = cygwinEnvironmentVariables.getVariable(ENV_VAR_NAME_PATH, null, null);
// if mingw found
if (mingwPath != null) {
//form full path
@ -93,6 +94,14 @@ public class LlvmEnvironmentVariableSupplier implements IConfigurationEnvironmen
//TODO: Emit proper error message and enter it to Eclipse error log.
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
setLlvmEnvironmentVariable(ENV_VAR_NAME_PATH, pathStr);
@ -440,15 +449,24 @@ public class LlvmEnvironmentVariableSupplier implements IConfigurationEnvironmen
return ""; //$NON-NLS-1$
}
private static synchronized void init() {
if (!isInitialized) {
initializePaths();
isInitialized = true;
}
}
@Override
public IBuildEnvironmentVariable getVariable(String variableName, IConfiguration configuration,
IEnvironmentVariableProvider provider) {
init();
return llvmEnvironmentVariables.get(variableName);
}
@Override
public IBuildEnvironmentVariable[] getVariables(IConfiguration configuration,
IEnvironmentVariableProvider provider) {
init();
return llvmEnvironmentVariables.values().toArray(new IBuildEnvironmentVariable[0]);
}
}