/*******************************************************************************
* Copyright (c) 2007, 2016 Intel Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Intel Corporation - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.managedbuilder.internal.buildmodel;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import org.eclipse.cdt.core.settings.model.util.CDataUtil;
import org.eclipse.cdt.managedbuilder.buildmodel.BuildDescriptionManager;
import org.eclipse.cdt.managedbuilder.buildmodel.IBuildCommand;
import org.eclipse.cdt.managedbuilder.buildmodel.IBuildDescription;
import org.eclipse.cdt.managedbuilder.buildmodel.IBuildResource;
import org.eclipse.cdt.managedbuilder.buildmodel.IBuildStep;
import org.eclipse.cdt.managedbuilder.buildmodel.IStepVisitor;
import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin;
import org.eclipse.cdt.managedbuilder.internal.core.ManagedMakeMessages;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
public class BuildDescriptionGnuMakefileGenerator {
private static final String OUT_STEP_RULE = "post_build"; //$NON-NLS-1$
private static final String IN_STEP_RULE = "pre_build"; //$NON-NLS-1$
private static final String ALL = "all"; //$NON-NLS-1$
private static final String TARGET_SEPARATOR = ":"; //$NON-NLS-1$
private static final String LINE_SEPARATOR = "\n"; //$NON-NLS-1$
private static final String TAB = "\t"; //$NON-NLS-1$
private static final String SPACE = " "; //$NON-NLS-1$
private static final String ENCODING = "utf-8"; //$NON-NLS-1$
private static final String VAR_SOURCES = "SOURCES"; //$NON-NLS-1$
private static final String VAR_TARGETS = "TARGETS"; //$NON-NLS-1$
private static final String EQUALS = "="; //$NON-NLS-1$
private static final String VARREF_PREFIX = "${"; //$NON-NLS-1$
private static final String VARREF_SUFFIX = "}"; //$NON-NLS-1$
private static final String DOT_DOT_SLASH = "../"; //$NON-NLS-1$
private static final String DOT_DOT_BACKSLASH = "..\\"; //$NON-NLS-1$
private IBuildDescription fDes;
private class DescriptionVisitor implements IStepVisitor {
Writer fWriter;
DescriptionVisitor(Writer writer){
fWriter = writer;
}
@Override
public int visit(IBuildStep step) throws CoreException {
if(step == fDes.getInputStep() || step == fDes.getOutputStep())
return VISIT_CONTINUE;
try {
write(fWriter, step);
} catch (IOException e) {
throw new CoreException(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.getUniqueIdentifier(), ManagedMakeMessages.getString("BuildDescriptionGnuMakefileGenerator.0"), e)); //$NON-NLS-1$
}
return VISIT_CONTINUE;
}
}
public BuildDescriptionGnuMakefileGenerator(IBuildDescription des){
fDes = des;
}
public void store(OutputStream stream) throws CoreException{
Writer writer = createWriter(stream);
try {
writer.write(VAR_SOURCES);
writer.write(EQUALS);
IBuildStep step = fDes.getInputStep();
String tmp = toString(step.getOutputResources());
writer.write(tmp);
writer.write(LINE_SEPARATOR);
writer.write(LINE_SEPARATOR);
writer.write(VAR_TARGETS);
writer.write(EQUALS);
step = fDes.getOutputStep();
tmp = toString(step.getInputResources());
writer.write(tmp);
writer.write(LINE_SEPARATOR);
writer.write(LINE_SEPARATOR);
writer.write(LINE_SEPARATOR);
writeRuleHeader(writer, ALL, IN_STEP_RULE + SPACE + OUT_STEP_RULE);
writer.write(LINE_SEPARATOR);
writer.write(LINE_SEPARATOR);
write(writer, fDes.getOutputStep());
write(writer, fDes.getInputStep());
BuildDescriptionManager.accept(new DescriptionVisitor(writer), fDes, true);
writer.flush();
} catch (IOException e) {
throw new CoreException(new Status(IStatus.ERROR, ManagedBuilderCorePlugin.getUniqueIdentifier(), ManagedMakeMessages.getString("BuildDescriptionGnuMakefileGenerator.1"), e)); //$NON-NLS-1$
}
}
protected Writer createWriter(OutputStream stream){
try {
return new OutputStreamWriter(stream, ENCODING);
} catch (UnsupportedEncodingException e1) {
ManagedBuilderCorePlugin.log(e1);
}
return new OutputStreamWriter(stream);
}
protected String createVarRef(String var){
return new StringBuilder().append(VARREF_PREFIX).append(var).append(VARREF_SUFFIX).toString();
}
protected void write(Writer writer, IBuildStep step) throws CoreException, IOException {
writer.write(LINE_SEPARATOR);
String target, deps;
if(step == fDes.getOutputStep()){
target = OUT_STEP_RULE;
deps = createVarRef(VAR_TARGETS);
} else if (step == fDes.getInputStep()){
target = IN_STEP_RULE;
deps = ""; //$NON-NLS-1$
} else {
IBuildResource[] inputs = step.getInputResources();
IBuildResource[] outputs = step.getOutputResources();
target = toString(outputs);
deps = toString(inputs);
}
writeRuleHeader(writer, target, deps);
IBuildCommand[] cmds = step.getCommands(null, null, null, true);
for(int i = 0; i < cmds.length; i++){
String cmdStr = toString(cmds[i]);
writeCommand(writer, cmdStr);
}
writer.write(LINE_SEPARATOR);
writer.write(LINE_SEPARATOR);
}
protected void writeCommand(Writer writer, String cmd) throws IOException{
writer.write(TAB);
writer.write(cmd);
writer.write(LINE_SEPARATOR);
}
protected String toString(IBuildCommand cmd){
StringBuilder buf = new StringBuilder();
buf.append(cmd.getCommand());
String argsString = CDataUtil.arrayToString(cmd.getArgs(), SPACE);
if(argsString != null && argsString.length() != 0){
buf.append(SPACE);
buf.append(argsString);
}
return removeDotDotSlashesAndBackSlashesHack(buf.toString());
}
protected void writeRuleHeader(Writer writer, String target, String deps) throws IOException{
writer.write(target);
writer.write(TARGET_SEPARATOR);
writer.write(SPACE);
writer.write(deps);
writer.write(LINE_SEPARATOR);
}
protected String toString(IBuildResource[] rcs){
StringBuilder buf = new StringBuilder();
for(int i = 0; i < rcs.length; i++){
if(i != 0)
buf.append(SPACE);
buf.append(toString(rcs[i]));
}
return buf.toString();
}
protected String toString(IBuildResource rc){
return removeDotDotSlashesAndBackSlashesHack(BuildDescriptionManager.getRelPath(fDes.getDefaultBuildDirLocation(), rc.getLocation()).toString());
}
/*
* this is a very bad hack that removes the "../" and "..\" from the string
* this is needed to overcome an assumption that the source root is ../
* the BuildDescription calculation mechanism should be fixed to remove this assumption
*/
private String removeDotDotSlashesAndBackSlashesHack(String str){
str = removeDotDotSlashes(str);
return removeDotDotBackslashes(str);
}
private String removeDotDotSlashes(String str){
int index = str.indexOf(DOT_DOT_SLASH, 0);
if(index != -1){
StringBuilder buf = new StringBuilder();
int start = 0;
for(; index != -1; index = str.indexOf(DOT_DOT_SLASH, start)){
buf.append(str.substring(start, index));
start = index + DOT_DOT_SLASH.length();
}
buf.append(str.substring(start));
return buf.toString();
}
return str;
}
private String removeDotDotBackslashes(String str){
int index = str.indexOf(DOT_DOT_BACKSLASH, 0);
if(index != -1){
StringBuilder buf = new StringBuilder();
int start = 0;
for(; index != -1; index = str.indexOf(DOT_DOT_BACKSLASH, start)){
buf.append(str.substring(start, index));
start = index + DOT_DOT_BACKSLASH.length();
}
buf.append(str.substring(start));
return buf.toString();
}
return str;
}
}