| /******************************************************************************* |
| * Copyright (c) 2010, 2016 Nokia Siemens Networks Oyj, Finland. |
| * |
| * 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: |
| * Nokia Siemens Networks - initial implementation |
| * Leo Hippelainen - Initial implementation |
| * Petri Tuononen - Initial implementation |
| * Marc-Andre Laperle (Ericsson) |
| *******************************************************************************/ |
| package org.eclipse.cdt.managedbuilder.llvm.ui; |
| |
| import java.io.File; |
| import java.util.HashMap; |
| |
| 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.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; |
| |
| /** |
| * Contains LLVM environment variables. |
| * |
| * @noextend This class is not intended to be subclassed by clients. |
| */ |
| public class LlvmEnvironmentVariableSupplier implements IConfigurationEnvironmentVariableSupplier { |
| // toggle for preference changes |
| private static boolean preferencesChanged = true; |
| // LLVM environment variable data structure |
| private static HashMap<String, LlvmBuildEnvironmentVariable> llvmEnvironmentVariables = new HashMap<>(6); |
| // 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$ |
| private static final String ENV_VAR_NAME_PATH = "PATH"; //$NON-NLS-1$ |
| private static final String ENV_VAR_NAME_INCLUDE_PATH = "INCLUDE_PATH"; //$NON-NLS-1$ |
| private static final String ENV_VAR_NAME_LIBRARY_PATH = "LLVM_LIB_SEARCH_PATH"; //$NON-NLS-1$ |
| private static final String ENV_VAR_NAME_LIBRARIES = "LIBRARIES"; //$NON-NLS-1$ |
| |
| /** |
| * Initializes llvm environment variable paths from the system environment variables. |
| */ |
| public static void initializePaths() { //TODO: Is this actually called anywhere? |
| // get bin path |
| String binPath = getBinPath(); |
| // set LLVM bin path environment variable |
| setLlvmEnvironmentVariableReplace(ENV_VAR_NAME_LLVM_BIN, binPath); |
| // if bin path exists |
| if (binPath != null && binPath.length() != 0) { |
| String pathStr = binPath; |
| // if OS is Windows (Windows specific settings) |
| if (System.getProperty("os.name").toLowerCase().indexOf("win") >= 0) { //$NON-NLS-1$ //$NON-NLS-2$ |
| try { |
| // 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); |
| |
| } |
| // if mingw found |
| if (mingwPath != null) { |
| //form full path |
| pathStr = pathStr + System.getProperty("path.separator") + mingwPath.getValue(); //$NON-NLS-1$ |
| } |
| // if cygwin found |
| if (cygwinPath != null) { |
| //form full path |
| pathStr = pathStr + System.getProperty("path.separator") + cygwinPath.getValue(); //$NON-NLS-1$ |
| } |
| } catch (Exception e) { |
| //TODO: Emit proper error message and enter it to Eclipse error log. |
| e.printStackTrace(); |
| } |
| } |
| //initialize environment variable cache values |
| setLlvmEnvironmentVariable(ENV_VAR_NAME_PATH, pathStr); |
| setLlvmEnvironmentVariable(ENV_VAR_NAME_LLVMINTERP, binPath + Separators.getFileSeparator() + "lli"); //$NON-NLS-1$ |
| setLlvmEnvironmentVariable(ENV_VAR_NAME_INCLUDE_PATH, getSysEnvPath(ENV_VAR_NAME_INCLUDE_PATH)); |
| setLlvmEnvironmentVariable(ENV_VAR_NAME_LIBRARY_PATH, getSysEnvPath(ENV_VAR_NAME_LIBRARY_PATH)); |
| setLlvmEnvironmentVariable(ENV_VAR_NAME_LIBRARIES, getSysEnvPath(ENV_VAR_NAME_LIBRARIES)); |
| preferencesChanged = false; |
| } |
| } |
| |
| /** |
| * Returns LLVM bin path |
| * |
| * @return LLVM bin path |
| */ |
| public static String getBinPath() { |
| return findBinDir(ENV_VAR_NAME_LLVM_BIN, "bin"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Returns LLVM include paths |
| * |
| * @return LLVM include paths |
| */ |
| public static String getIncludePath() { |
| return getLlvmEnvironmentVariable(ENV_VAR_NAME_INCLUDE_PATH).getValue(); |
| } |
| |
| /** |
| * Returns LLVM library paths |
| * |
| * @return LLVM library paths |
| */ |
| public static String getLibraryPath() { |
| return getLlvmEnvironmentVariable(ENV_VAR_NAME_LIBRARY_PATH).getValue(); |
| } |
| |
| /** |
| * Returns LLVM libraries |
| * |
| * @return LLVM libraries |
| */ |
| public static String getLibraries() { |
| return getLlvmEnvironmentVariable(ENV_VAR_NAME_LIBRARIES).getValue(); |
| } |
| |
| /** |
| * Sets path to LLVM bin. |
| * |
| * @param path Path to LLVM bin location. |
| */ |
| public static void setBinPath(String path) { |
| setLlvmEnvironmentVariableReplace(ENV_VAR_NAME_LLVM_BIN, path); |
| } |
| |
| /** |
| * Appends a new include path. |
| * |
| * @param path Include path |
| */ |
| public static void addIncludePath(String path) { |
| String existingIncPaths = getIncludePath(); |
| //add the include path only if it doesn't already exists |
| if (!existingIncPaths.contains(path)) { |
| appendLlvmEnvironmentVariable(ENV_VAR_NAME_INCLUDE_PATH, existingIncPaths, path); |
| } |
| } |
| |
| /** |
| * Appends a new library path. |
| * |
| * @param path Library path |
| */ |
| public static void addLibraryPath(String path) { |
| String existingLibPaths = getLibraryPath(); |
| //add the library path only if it doesn't already exists |
| if (!existingLibPaths.contains(path)) { |
| appendLlvmEnvironmentVariable(ENV_VAR_NAME_LIBRARY_PATH, existingLibPaths, path); |
| } |
| } |
| |
| /** |
| * Appends a new library. |
| * |
| * @param lib Library file |
| */ |
| public static void addLibrary(String lib) { |
| String existingLibs = getLibraries(); |
| //add the library only if it doesn't already exists |
| if (!existingLibs.contains(lib)) { |
| appendLlvmEnvironmentVariable(ENV_VAR_NAME_LIBRARIES, existingLibs, lib); |
| } |
| } |
| |
| /** |
| * This is to be called if some of the preference paths have changed. |
| */ |
| public static void notifyPreferenceChange() { //TODO: Change |
| preferencesChanged = true; |
| } |
| |
| /** |
| * Returns a specific path for given parameters. |
| * |
| * @param pathKey Path for specific location |
| * @param subDirName Additional sub-path |
| * @return bin path |
| */ |
| private static String findBinDir(String pathKey, String subDirName) { |
| String resultPath = null; |
| // If preferences haven't been changed, try to find the bin path from the LLVM environment |
| // variable map. |
| if (!preferencesChanged) { //TODO: Change |
| //get current path |
| LlvmBuildEnvironmentVariable earlierValue = llvmEnvironmentVariables.get(pathKey); |
| //if earlier LlvmBuildEnvironmentVariable exists |
| if (null != earlierValue) { |
| //return current path |
| return earlierValue.getValue(); |
| } |
| } else { |
| // Try if the path is set in the LLVM plug-in preferences |
| String preferenceLocation = LlvmPreferenceStore.getBinPath(); |
| // if preference exists |
| if (null != preferenceLocation) { |
| // remove white spaces from preference location |
| preferenceLocation = preferenceLocation.trim(); |
| // if preference location is not empty |
| if (preferenceLocation.length() != 0) { |
| // get path for LLVM executable |
| resultPath = getDirIfLlvmFound(preferenceLocation, null); |
| // if LLVM executable path doesn't exist |
| if (null == resultPath) { |
| // If no luck check next with sub directory name appended |
| resultPath = getDirIfLlvmFound(preferenceLocation, subDirName); |
| } |
| } |
| } |
| if (null == resultPath) { |
| // If still no luck try all folders listed in PATH |
| String pathVariable = System.getenv(ENV_VAR_NAME_PATH); |
| // split paths to String array |
| String[] paths = pathVariable.split(Separators.getPathSeparator()); |
| // check every path if LLVM executable is found |
| for (String pathStr : paths) { |
| resultPath = getDirIfLlvmFound(pathStr, null); |
| // stop loop if LLVM executable path is found |
| if (null != resultPath) { |
| break; |
| } |
| } |
| } |
| // return found path |
| return resultPath; |
| } |
| return null; |
| } |
| |
| /** |
| * Returns LLVM executable path. |
| * |
| * @param candidatePath Suggestion for LLVM executable path |
| * @param subPath Additional sub-path for LLVM executable path |
| * @return Full path for LLVM executable if valid, otherwise null |
| */ |
| private static String getDirIfLlvmFound(String candidatePath, String subPath) { |
| String llvmPath = candidatePath; |
| // If there is a trailing / or \, remove it |
| if (llvmPath.endsWith(Separators.getFileSeparator()) && llvmPath.length() > 1) { |
| llvmPath = llvmPath.substring(0, candidatePath.length() - 1); |
| } |
| // If subPath exists and is not empty -> append it to candidatePath. |
| if (null != subPath && !subPath.isEmpty()) { |
| // Form full path. |
| llvmPath = llvmPath + Separators.getFileSeparator() + subPath; |
| } |
| // Return a full path for LLVM executable if it's valid, otherwise null. |
| return getBinDirIfLlvm_ar(llvmPath); |
| } |
| |
| /** |
| * Returns the full path for llvm executable if the bin path given |
| * as a parameter is found and executable exists in that path. |
| * |
| * @param binPathTemp User provided bin directory path |
| * @return bin path where llvm-ar is located if executable exists |
| */ |
| private static String getBinDirIfLlvm_ar(String binPathTemp) { |
| //if given directory is found |
| if (new Path(binPathTemp).toFile().isDirectory()) { |
| String llvm_executable = "llvm-ar"; //$NON-NLS-1$ |
| File arFileFullPath = null; |
| // If OS is Windows -> add .exe to the executable name. |
| if (System.getProperty("os.name").toLowerCase().indexOf("win") >= 0) { //$NON-NLS-1$//$NON-NLS-2$ |
| llvm_executable = llvm_executable + ".exe"; //$NON-NLS-1$ |
| } |
| // Form full executable path |
| arFileFullPath = new File(binPathTemp, llvm_executable); |
| // Check if file exists -> proper LLVM installation exists. |
| if (arFileFullPath.isFile()) { |
| // Return path where llvm-ar exists. |
| return binPathTemp; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * @return location of $MINGW_HOME/bin folder on the file-system. |
| * @deprecated. Deprecated as of CDT 8.2. Note that MinGW root path in general may depend on configuration. |
| * |
| * If you use this do not cache results to ensure user preferences are accounted for. |
| * Please rely on internal caching. |
| */ |
| @Deprecated |
| private static IPath getBinDir() { |
| IPath binDir = null; |
| String minGWHome = MinGW.getMinGWHome(); |
| if (minGWHome != null) { |
| binDir = new Path(minGWHome).append("bin"); //$NON-NLS-1$ |
| } |
| return binDir; |
| } |
| |
| /** |
| * Returns stdc++ library path located in MinGW installation. |
| * |
| * @return stdc++ library path for MinGW |
| */ |
| public static String getMinGWStdLib() { |
| // get mingw bin path |
| IPath mingwBinPath = getBinDir(); |
| if (mingwBinPath != null) { |
| StringBuilder sB = new StringBuilder(mingwBinPath.toOSString()); |
| // drop bin |
| if (sB.length() >= 3) { |
| sB.delete(sB.length() - 3, sB.length()); |
| // append mingw lib subdir |
| sB.append("lib\\gcc\\mingw32\\"); //$NON-NLS-1$ |
| // get all files in the directory |
| File f = new File(sB.toString()); |
| if (f.isDirectory()) { |
| String[] list = f.list(); |
| if (list.length > 0) { |
| // append the first dir |
| sB.append(list[0]); |
| return sB.toString(); |
| } |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * |
| * Returns LLVM environment variable. |
| * |
| * @param envName Name of the environment variable |
| */ |
| public static LlvmBuildEnvironmentVariable getLlvmEnvironmentVariable(String envName) { |
| return llvmEnvironmentVariables.get(envName); |
| } |
| |
| /** |
| * Sets LLVM environment variable. |
| * |
| * @param name Name for the environment variable |
| * @param path Path for the environment variable |
| */ |
| private static void setLlvmEnvironmentVariable(String name, String path) { |
| // append a new path in front of the the old path in HashMap that contains |
| // the specific LLVM environment variable |
| llvmEnvironmentVariables.put(name, |
| new LlvmBuildEnvironmentVariable(name, path, IBuildEnvironmentVariable.ENVVAR_APPEND)); |
| } |
| |
| /** |
| * Sets LLVM environment variable by replacing the existing paths. |
| * |
| * @param name Name for the environment variable |
| * @param path Path for the environment variable |
| */ |
| public static void setLlvmEnvironmentVariableReplace(String name, String path) { |
| // replace the old path in HashMap that contains the specific LLVM environment variable |
| llvmEnvironmentVariables.put(name, |
| new LlvmBuildEnvironmentVariable(name, path, IBuildEnvironmentVariable.ENVVAR_REPLACE)); |
| } |
| |
| /** |
| * Appends a new LLVM environment variable to existing list. |
| * |
| * @param name Name of the preference |
| * @param oldPath Old paths/preference values |
| * @param path New path to be added to the environment variable |
| */ |
| public static void appendLlvmEnvironmentVariable(String name, String oldPath, String path) { |
| String newPath = null; |
| boolean ok = false; |
| // if oldPath exists |
| if (oldPath != null) { |
| //if the oldPath isn't empty |
| if (!oldPath.trim().isEmpty()) { |
| StringBuilder sB = new StringBuilder(); |
| // append old path |
| sB.append(oldPath); |
| // append a path separator |
| sB.append(Separators.getPathSeparator()); |
| // append the new path |
| sB.append(path); |
| // construct a new full path |
| newPath = sB.toString(); |
| ok = true; |
| } |
| } |
| if (!ok) { |
| newPath = path; |
| } |
| // Set new path to the HashMap that contains the specific LLVM environment variable |
| // if newPath exists. |
| if (newPath != null) { |
| // if the newPath isn't empty |
| if (!newPath.trim().isEmpty()) { |
| // add new values to the LLVM environment variable |
| llvmEnvironmentVariables.put(name, |
| new LlvmBuildEnvironmentVariable(name, newPath, IBuildEnvironmentVariable.ENVVAR_APPEND)); |
| } |
| } |
| } |
| |
| /** |
| * Returns a system environment variable path |
| * |
| * @param envName Environment variable name |
| * @return system environment variable path |
| */ |
| private static String getSysEnvPath(String envName) { |
| String path = System.getenv(envName); |
| if (path != null) { |
| return path; |
| } |
| return ""; //$NON-NLS-1$ |
| } |
| |
| @Override |
| public IBuildEnvironmentVariable getVariable(String variableName, IConfiguration configuration, |
| IEnvironmentVariableProvider provider) { |
| return llvmEnvironmentVariables.get(variableName); |
| } |
| |
| @Override |
| public IBuildEnvironmentVariable[] getVariables(IConfiguration configuration, |
| IEnvironmentVariableProvider provider) { |
| return llvmEnvironmentVariables.values().toArray(new IBuildEnvironmentVariable[0]); |
| } |
| } |