com.github.maven_nar.cpptasks.compiler.AbstractCompiler.java Source code

Java tutorial

Introduction

Here is the source code for com.github.maven_nar.cpptasks.compiler.AbstractCompiler.java

Source

/*
 * #%L
 * Native ARchive plugin for Maven
 * %%
 * Copyright (C) 2002 - 2014 NAR Maven Plugin developers.
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package com.github.maven_nar.cpptasks.compiler;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Vector;

import org.apache.commons.io.FilenameUtils;

import com.github.maven_nar.cpptasks.CCTask;
import com.github.maven_nar.cpptasks.CUtil;
import com.github.maven_nar.cpptasks.CompilerDef;
import com.github.maven_nar.cpptasks.DependencyInfo;
import com.github.maven_nar.cpptasks.ProcessorDef;
import com.github.maven_nar.cpptasks.TargetDef;
import com.github.maven_nar.cpptasks.VersionInfo;
import com.github.maven_nar.cpptasks.parser.Parser;

/**
 * An abstract compiler implementation.
 *
 * @author Adam Murdoch
 * @author Curt Arnold
 */
public abstract class AbstractCompiler extends AbstractProcessor implements Compiler {
    private static final String[] emptyIncludeArray = new String[0];
    private final String outputSuffix;
    protected File workDir;
    protected File objDir;

    protected AbstractCompiler(final String[] sourceExtensions, final String[] headerExtensions,
            final String outputSuffix) {
        super(sourceExtensions, headerExtensions);
        this.outputSuffix = outputSuffix;
    }

    /**
     * Checks file name to see if parse should be attempted
     *
     * Default implementation returns false for files with extensions '.dll',
     * 'tlb', '.res'
     *
     */
    protected boolean canParse(final File sourceFile) {
        final String sourceName = sourceFile.toString();
        final int lastPeriod = sourceName.lastIndexOf('.');
        if (lastPeriod >= 0 && lastPeriod == sourceName.length() - 4) {
            final String ext = sourceName.substring(lastPeriod).toUpperCase();
            if (ext.equals(".DLL") || ext.equals(".TLB") || ext.equals(".RES")) {
                return false;
            }
        }
        return true;
    }

    abstract protected CompilerConfiguration createConfiguration(CCTask task, LinkType linkType,
            ProcessorDef[] baseConfigs, CompilerDef specificConfig, TargetDef targetPlatform,
            VersionInfo versionInfo);

    @Override
    public ProcessorConfiguration createConfiguration(final CCTask task, final LinkType linkType,
            final ProcessorDef[] baseConfigs, final ProcessorDef specificConfig, final TargetDef targetPlatform,
            final VersionInfo versionInfo) {
        if (specificConfig == null) {
            throw new NullPointerException("specificConfig");
        }
        return createConfiguration(task, linkType, baseConfigs, (CompilerDef) specificConfig, targetPlatform,
                versionInfo);
    }

    abstract protected Parser createParser(File sourceFile);

    protected String getBaseOutputName(final String inputFile) {
        return FilenameUtils.getBaseName(inputFile);
    }

    @Override
    public String[] getOutputFileNames(final String inputFile, final VersionInfo versionInfo) {
        //
        // if a recognized input file
        //
        if (bid(inputFile) > 1) {
            final String baseName = getBaseOutputName(inputFile);
            return new String[] { baseName + this.outputSuffix };
        }
        return new String[0];
    }

    /**
     * Returns dependency info for the specified source file
     *
     * @param task
     *          task for any diagnostic output
     * @param source
     *          file to be parsed
     * @param includePath
     *          include path to be used to resolve included files
     *
     * @param sysIncludePath
     *          sysinclude path from build file, files resolved using
     *          sysInclude path will not participate in dependency analysis
     *
     * @param envIncludePath
     *          include path from environment variable, files resolved with
     *          envIncludePath will not participate in dependency analysis
     *
     * @param baseDir
     *          used to produce relative paths in DependencyInfo
     * @param includePathIdentifier
     *          used to distinguish DependencyInfo's from different include
     *          path settings
     *
     */
    public final DependencyInfo parseIncludes(final CCTask task, final File source, final File[] includePath,
            final File[] sysIncludePath, final File[] envIncludePath, final File baseDir,
            final String includePathIdentifier) {
        //
        // if any of the include files can not be identified
        // change the sourceLastModified to Long.MAX_VALUE to
        // force recompilation of anything that depends on it
        long sourceLastModified = source.lastModified();
        final File[] sourcePath = new File[1];
        sourcePath[0] = new File(source.getParent());
        final Vector onIncludePath = new Vector();
        final Vector onSysIncludePath = new Vector();
        String baseDirPath;
        try {
            baseDirPath = baseDir.getCanonicalPath();
        } catch (final IOException ex) {
            baseDirPath = baseDir.toString();
        }
        final String relativeSource = CUtil.getRelativePath(baseDirPath, source);
        String[] includes = emptyIncludeArray;
        if (canParse(source)) {
            final Parser parser = createParser(source);
            try {
                final Reader reader = new BufferedReader(new FileReader(source));
                parser.parse(reader);
                includes = parser.getIncludes();
            } catch (final IOException ex) {
                task.log("Error parsing " + source.toString() + ":" + ex.toString());
                includes = new String[0];
            }
        }
        for (final String include : includes) {
            if (!resolveInclude(include, sourcePath, onIncludePath)) {
                if (!resolveInclude(include, includePath, onIncludePath)) {
                    if (!resolveInclude(include, sysIncludePath, onSysIncludePath)) {
                        if (!resolveInclude(include, envIncludePath, onSysIncludePath)) {
                            //
                            // this should be enough to require us to reparse
                            // the file with the missing include for dependency
                            // information without forcing a rebuild
                            sourceLastModified += 2 * CUtil.FILETIME_EPSILON;
                        }
                    }
                }
            }
        }
        for (int i = 0; i < onIncludePath.size(); i++) {
            final String relativeInclude = CUtil.getRelativePath(baseDirPath, (File) onIncludePath.elementAt(i));
            onIncludePath.setElementAt(relativeInclude, i);
        }
        for (int i = 0; i < onSysIncludePath.size(); i++) {
            final String relativeInclude = CUtil.getRelativePath(baseDirPath, (File) onSysIncludePath.elementAt(i));
            onSysIncludePath.setElementAt(relativeInclude, i);
        }
        return new DependencyInfo(includePathIdentifier, relativeSource, sourceLastModified, onIncludePath,
                onSysIncludePath);
    }

    protected boolean resolveInclude(final String includeName, final File[] includePath, final Vector onThisPath) {
        for (final File element : includePath) {
            final File includeFile = new File(element, includeName);
            if (includeFile.exists()) {
                onThisPath.addElement(includeFile);
                return true;
            }
        }
        return false;
    }

    public final String getOutputSuffix() {
        return this.outputSuffix;
    }

    public void setWorkDir(final File workDir) {
        this.workDir = workDir;
    }

    public void setObjDir(final File objDir) {
        this.objDir = objDir;
    }
}