summaryrefslogblamecommitdiffstats
path: root/org.rtems.cdt/src/org/rtems/cdt/Storage.java
blob: 6827c8d9b477b59297a697f9c14e678542d51691 (plain) (tree)







































                                                                                  
                                          
                                           
                                            


















                                                             

                                                                                  

         
                                                                                
                                    
                
                     
                                                                                          






                                            

                                                                        
        
                                    

                                                                                    
                                

                                                                 





                             
                                                                                    
                     
                                                                                         




                                            

                                                                                                



                                                                           
                                                                                               




                            

                                                                                                

                                                                            
                                                                                            



                           
                                                                      
                                                       





                                                                      

                                                                                 

                                       
                                                                      
 
                                                                      




                            

                                                                                                 

                                       
                                                                      
 
                                                                      




                            

                                                                            

         

                                                                           

         

                                                            

                                                                                
                                                                       

                                                                                    
                                                       



                          

                                                                                 







                                                                  
                                                  


                                       


                                                                                                  
                                

                                                                                                 

                         

                                                                                       

                               
                                                  

         


                                                                              
                                                                
                                      

                                              





                                                                                     

                                               
                                                                           
                
                                              


                                                                         
                                                   
                                                                                                                

                                 
                                                                  





                                                                    
                                                                                    


                                                           



                                                                               
 
                                                                                                

                                                                               

                                              
                                                

                                                                                     
                                

                                                             
                                                     


                                              







                                                                                                                              


                                   
                                                                                                                

                                          
                                    






                                                            
                                                                                          


                                                    



                                                           

                                                                                         





                                                                              

                                                                                         

                                                                              
                                                                                                        






                                                                                                         
                                                                                                        


                                                           
                                                                                           



                                                                   
                                                                                          



                                                     
                                                                           

                                         
                                     




                                                                            
                           







                                                                          


                                 

                                    
                                                      
                                     


                                                                   
                                                                                                                                              

                          



                                                                                                                      
                                                   
                 

         
                                                                                                                


                                                                        
                                                                                                                           
                                                       

                                                                                                                                   








                                                                          

                                                              

                                                       
                                                        

                                                              

                                                                  




                                                                                                      
                                                                             
                 

                                 
                                                 

                                 

                                                                                                 

         

                                                                                                         
 
                                                            
         
 

                                                                                                
         
        

                                                                                      
         
        
                                                                                                                
                     



                                                                               





                                            
                                                                       
                     
                                                                                                                 

                                                           
                                                                                                                                 








                                                           




                             
/*
 * Copyright (c) 2008 Embedded Brains GmbH and others.
 *
 *   Embedded Brains GmbH
 *   Obere Lagerstr. 30
 *   D-82178 Puchheim
 *   Germany
 *   rtems@embedded-brains.de
 *
 * All rights reserved.  This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License Version 1.0 ("EPL")
 * which accompanies this distribution and is available at
 *
 *   http://www.eclipse.org/legal/epl-v10.html
 *
 * For purposes of the EPL, "Program" will mean the Content.
 *
 * Contributors:
 *
 *   Sebastian Huber (Embedded Brains GmbH) - Initial API and implementation.
 */

package org.rtems.cdt;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.eclipse.cdt.build.core.scannerconfig.CfgInfoContext;
import org.eclipse.cdt.build.internal.core.scannerconfig.CfgDiscoveredPathManager;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.managedbuilder.core.IConfiguration;
import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.QualifiedName;

public class Storage {
	private static final String OPTION_SEPARATOR = "\0";

	private static final String VALUE_START_TOKEN = "\t";

	private static final int EXPECT_OPTION = 0;

	private static final int EXPECT_COMMAND = 1;

	private static final int EXPECT_KEY = 2;

	private static final int TOOL_COMPLETE = 3;

	public static String getPreference(String key) {
		return Activator.getDefault().getPreferenceStore().getString(key);
	}

	public static String getPristineProperty(IProject project, String key) {
		String value = null;
		
		try {
			value = project.getPersistentProperty(new QualifiedName("", key));
		} catch (CoreException e) {
			e.printStackTrace();
		}

		return value;
	}

	public static String getProperty(IProject project, String key) {
		String value = getPristineProperty(project, key);
	
		if (value == null) {
			if (key.startsWith(Constants.TOOL_KEY_PREFIX)) {
				changePlatform(project, Constants.PLATFORM_DEFAULT);
			} else {
				value = getPreference(key);
				setProperty(project, key, value);
			}
		}

		return value;
	}

	public static void setProperty(IProject project, String key, String value) {
		try {
			project.setPersistentProperty(new QualifiedName("", key), value);
		} catch (CoreException e) {
			e.printStackTrace();
		}
	}

	public static IConfiguration [] getConfigurations(IProject project) {
		ICProjectDescription pd = CoreModel.getDefault().getProjectDescription(project);

		ICConfigurationDescription cds [] = pd.getConfigurations();
		IConfiguration cfgs [] = new IConfiguration [cds.length];
		for (int i = 0; i < cds.length; ++i) {
			cfgs [i] = ManagedBuildManager.getConfigurationForDescription(cds [i]);
		}

		return cfgs;
	}

	public static IConfiguration getActiveConfiguration(IProject project) {
		ICProjectDescription pd = CoreModel.getDefault().getProjectDescription(project);

		ICConfigurationDescription cd = pd.getActiveConfiguration();
		IConfiguration cfg = ManagedBuildManager.getConfigurationForDescription(cd);

		return cfg;
	}

	public static String prependToPath(String path, String part) {
		if (path == null || path.length()==0) {
			return part;
		} else {
			return part + Constants.PATH_SEPARATOR + path;
		}
	}

	public static String prependToPathByPreference(String path, String key) {
		String basePath = getPreference(key);

		if (basePath != null) {
			IPath part = new Path(basePath).append("bin");

			return prependToPath(path, part.toOSString());
		}

		return path;
	}

	public static String prependToPathByProperty(IProject project, String path, String key) {
		String basePath = getProperty(project, key);

		if (basePath != null) {
			IPath part = new Path(basePath).append("bin");

			return prependToPath(path, part.toOSString());
		}

		return path;
	}

	public static String getPlatform(IProject project) {
		return getPristineProperty(project, Constants.PLATFORM_KEY);
	}
	
	public static void setPlatform(IProject project, String platform) {
		setProperty(project, Constants.PLATFORM_KEY, platform);
	}

	public static void clearPlatform(IProject project) {
		setPlatform(project, null);

		// Delete discovered paths for all configurations of the project
		for (IConfiguration cfg : getConfigurations(project)) {
			CfgDiscoveredPathManager.getInstance().removeDiscoveredInfo(
				project,
				new CfgInfoContext(cfg)
			);
		}
	}

	public static void changePlatform(IProject project, String newPlatform) {
		String platform = getPlatform(project);

		// Check if we have already the requested platform
		if (platform != null && platform == newPlatform) {
			// Nothing to do
			return;
		}

		// Set new platform
		setPlatform(project, newPlatform);

		// Update path prepends
		String path = null;
		if (Platform.getOS().equals(Platform.OS_WIN32)) {
			if (newPlatform.equals(Constants.PLATFORM_CYGWIN)) {
				path = prependToPathByPreference(path, Constants.CYGWIN_PATH_KEY);
			} else {
				path = prependToPathByPreference(path, Constants.MINGW_PATH_KEY);
				path = prependToPathByPreference(path, Constants.MSYS_PATH_KEY);
			}
		}
		path = prependToPathByProperty(project, path, Constants.BASE_PATH_KEY);
		setProperty(project, Constants.PATH_PREPEND_KEY, path);

		// Update tools
		updateTools(project, newPlatform);
	}

	private static void updateTools(IProject project, String platform) {
		String bspPath = getProperty(project, Constants.BSP_PATH_KEY);
		IPath make = new Path("make");
		List<String> options = new LinkedList<String>();
		boolean error = false;
		
		// Set tools to default values
		updateTool(project, Constants.TOOL_ARCHIVER_KEY, "ar", options);
		updateTool(project, Constants.TOOL_ASSEMBLER_KEY, "as", options);
		updateTool(project, Constants.TOOL_COMPILER_CPP_KEY, "g++", options);
		updateTool(project, Constants.TOOL_COMPILER_C_KEY, "gcc", options);
		updateTool(project, Constants.TOOL_LINKER_CPP_KEY, "g++", options);
		updateTool(project, Constants.TOOL_LINKER_C_KEY, "gcc", options);
		
		// Delete markers for this unit
		deleteMarkers(project, Constants.MARKER_ID_TOOL_DISCOVERY);
		
		// Translate path if necessary
		if (Platform.getOS().equals(Platform.OS_WIN32)) {
			if (platform.equals(Constants.PLATFORM_CYGWIN)) {
				String s [] = bspPath.split(":");
				if (s.length > 0) {
					bspPath = bspPath.replaceFirst("^" + s [0] + ":", "/cygdrive/" + s [0]);
				}
			}
			bspPath = bspPath.replaceAll("\\\\", "/");
		}

		// Create make process builder
		ProcessBuilder pb = new ProcessBuilder();

		// Change working directory to the Makefile location
		pb.directory(Activator.getDefault().getMakefileLocation().toFile());

		// Update path environment variable
		Map<String, String> env = pb.environment();
		String path = env.get(Constants.PATH_VARIABLE_NAME);
		String part = getProperty(project, Constants.PATH_PREPEND_KEY);
		path = Storage.prependToPath(path, part);
		env.put(Constants.PATH_VARIABLE_NAME, path);

		// On Windows we have to search for the make program in the new path environment
		if (Platform.getOS().equals(Platform.OS_WIN32)) {
			String parts [] = path.split(Constants.PATH_SEPARATOR);
			boolean found = false;
			
			for (String p : parts) {
				IPath makeCandidate = new Path(p).append("make.exe");
				File file = new File(makeCandidate.toOSString());
				
				if (file.exists()) {
					make = makeCandidate;
					found = true;
					break;
				}
			}
			
			if (!found) {
				createMarker(
					project,
					Constants.MARKER_ID_TOOL_DISCOVERY,
					"make program not found, check your Cygwin or MinGW settings in the RTEMS preferences"
				);
			}
		}

		// Set command line
		String makeArgument = Constants.BSP_PATH_MAKE_VARIABLE + "=" + bspPath.replaceAll(" ", "\\\\ ");
		pb.command(
			make.toOSString(),
			makeArgument
		);

		// Start make process and parse its output
		Process p = null;
		try {
			p = pb.start();
			InputStream is = p.getInputStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(is));
			String line = br.readLine();
			String key = null;
			String command = null;
			int state = EXPECT_KEY;
			while (line != null) {
				switch (state) {
					case EXPECT_OPTION:
						if (line.startsWith(VALUE_START_TOKEN)) {
							options.add(line.substring(1));
						} else {
							state = TOOL_COMPLETE;
							continue;
						}
						break;
					case EXPECT_COMMAND:
						if (line.startsWith(VALUE_START_TOKEN)) {
							command = line.substring(1);
							state = EXPECT_OPTION;
						} else {
							throw new IOException("unexpected line format");
						}
						break;
					case EXPECT_KEY:
						if (line.length() > Constants.TOOL_KEY_PREFIX.length()) {
							key = line;
							state = EXPECT_COMMAND;
						} else {
							throw new IOException("unexpected line format");
						}
						break;
					case TOOL_COMPLETE:
						updateTool(project, key, command, options);
						options.clear();
						state = EXPECT_KEY;
						continue;
					default:
						throw new IOException("unexpected state");
				}
				line = br.readLine();
			}
			if (state == EXPECT_OPTION) {
				updateTool(project, key, command, options);
			}
		} catch (IOException e) {
			error = true;
			createMarker(
				project,
				Constants.MARKER_ID_TOOL_DISCOVERY,
				"make output parse error: " + e.getMessage()
			);
		} finally {
			if (p != null) {
				while (true) {
					try {
						p.waitFor();
						break;
					} catch (InterruptedException e) {
						continue;
					}
				}
			}
		}
		
		// Check exit status
		if (p != null && p.exitValue() != 0) {
			error = true;
			createMarker(
				project,
				Constants.MARKER_ID_TOOL_DISCOVERY,
				"make invokation `" + make.toOSString() + " " + makeArgument + "' returned with error status " + p.exitValue()
			);
		}
		
		// Check error
		if (error) {
			// Clear platform to trigger an update again if someone changed a preference or property value
			setPlatform(project, null);
		}
	}

	private static void updateTool(IProject project, String toolKey, String command, List<String> options) {
		List<String> filteredOptions = new LinkedList<String>();

		// Filter options
		if (toolKey.startsWith(Constants.COMPILER_KEY_PREFIX) || toolKey.startsWith(Constants.LINKER_KEY_PREFIX)) {
			for (String option : options) {
				if (!(option.length() == 0 || option.trim().matches("^(-c|-O[0123s]|-g.*|-W[\\w-]*|[-]*pipe)$"))) {
					filteredOptions.add(option);
				}
			}
		} else {
			filteredOptions = options;
		}

		// Transform filtered option list into option string value
		String optionsValue = new String();
		if (!options.isEmpty()) {
			optionsValue = filteredOptions.get(0);
			filteredOptions.remove(0);
		}
		for (String option : filteredOptions) {
			if (option.indexOf(' ') != -1) {
				option = "\"" + option + "\"";
			}
			optionsValue += OPTION_SEPARATOR + option;
		}
		
		// FIXME: This is a workaround for tools with long filenames under Windows.
		// It is also a workaround for the internal builder since this one does not care about
		// the environment provider to fix the $PATH.
		IPath commandPath = new Path(
			Storage.getProperty(project, Constants.BASE_PATH_KEY)
		)
		.append("bin")
		.append(command);
		command = commandPath.toString();

		// Set properties
		setProperty(project, toolKey, command);
		setProperty(project, toolKey + Constants.TOOL_OPTIONS_KEY_POSTFIX, optionsValue);
	}

	public static String [] getToolOptions(IProject project, String toolKey) {
		String optionsValue = getProperty(project, toolKey + Constants.TOOL_OPTIONS_KEY_POSTFIX);

		return optionsValue.split(OPTION_SEPARATOR);
	}

	public static boolean areToolOptionsEnabled(IProject project) {
		return !getProperty(project, Constants.DISABLE_TOOL_OPTIONS_KEY).equals("true");
	}
	
	public static void createMarker(IProject project, String id, String message) {
		createMarker(project, id, message, IMarker.SEVERITY_ERROR);
	}
	
	public static void createMarker(IProject project, String id, String message, int severity) 	{	
		try {
			IMarker marker = project.createMarker(IMarker.PROBLEM);
			marker.setAttribute(IMarker.LOCATION, id);
			marker.setAttribute(IMarker.MESSAGE, message);
			marker.setAttribute(IMarker.SEVERITY, severity);
		} catch (CoreException e) {
			e.printStackTrace();
		}

	}
	
	public static void deleteMarkers(IProject project, String id) {
		try {
			IMarker[] markers = project.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE);
			if (markers != null) {
				for (IMarker m : markers) {
					if (m.getResource().equals(project) && m.getAttribute(IMarker.LOCATION, "").equals(id)) {
						m.delete();
					}
				}
			}
		} catch (CoreException e) {
			e.printStackTrace();
		}

	}

	private Storage() {
		// Do nothing
	}
}