All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.maven_nar.NarVcprojMojo Maven / Gradle / Ivy

Go to download

This plugin compiles native code and publishes native artifacts in the form of nar files.

There is a newer version: 3.10.1
Show newest version
/*
 * #%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;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.Profile;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;

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.LinkerDef;
import com.github.maven_nar.cpptasks.OutputTypeEnum;
import com.github.maven_nar.cpptasks.RuntimeType;
import com.github.maven_nar.cpptasks.SubsystemEnum;
import com.github.maven_nar.cpptasks.ide.ProjectDef;
import com.github.maven_nar.cpptasks.ide.ProjectWriterEnum;
import com.github.maven_nar.cpptasks.types.DefineArgument;
import com.github.maven_nar.cpptasks.types.DefineSet;
import com.github.maven_nar.cpptasks.types.LibrarySet;
import com.github.maven_nar.cpptasks.types.LinkerArgument;
import com.github.maven_nar.cpptasks.types.SystemLibrarySet;

/**
 * Generates a Visual Studio 2005 project file (vcproj) Heavily inspired by
 * NarCompileMojo.
 *
 * @author Darren Sargent
 *
 */
@Mojo(name = "nar-vcproj", defaultPhase = LifecyclePhase.GENERATE_RESOURCES,
  requiresDependencyResolution = ResolutionScope.COMPILE)
public class NarVcprojMojo extends AbstractCompileMojo {

  // FIXME: code duplication with NarCompileMojo
  private void createVcProjFile(final Project antProject, final Library library)
      throws MojoExecutionException, MojoFailureException {

    // configure task
    final CCTask task = new CCTask();
    task.setProject(antProject);
    task.setDebug(true);

    // subsystem (console)
    final SubsystemEnum subSystem = new SubsystemEnum();
    subSystem.setValue(library.getSubSystem());
    task.setSubsystem(subSystem);

    // outtype
    final OutputTypeEnum outTypeEnum = new OutputTypeEnum();
    final String type = library.getType();
    outTypeEnum.setValue(type);
    task.setOuttype(outTypeEnum);

    // stdc++
    task.setLinkCPP(library.linkCPP());

    // TODO: this should match the standard NAR location defined by layout
    // similar to Nar Compile
    // outDir
    File outDir = new File(getTargetDirectory(), "bin");
    outDir = new File(outDir, getAOL().toString());
    outDir.mkdirs();

    // outFile
    final File outFile = new File(outDir, getOutput(getAOL(), type));

    getLog().debug("NAR - output: '" + outFile + "'");
    task.setOutfile(outFile);

    // object directory
    File objDir = new File(getTargetDirectory(), "obj");
    objDir = new File(objDir, getAOL().toString());
    objDir.mkdirs();
    task.setObjdir(objDir);

    // failOnError, libtool
    task.setFailonerror(failOnError(getAOL()));
    task.setLibtool(useLibtool(getAOL()));

    // runtime
    final RuntimeType runtimeType = new RuntimeType();
    runtimeType.setValue(getRuntime(getAOL()));
    task.setRuntime(runtimeType);

    // add C++ compiler
    final CompilerDef cpp = getCpp().getCompiler(Compiler.MAIN, null);
    if (cpp != null) {
      task.addConfiguredCompiler(cpp);
    }

    // add VCPROJ_MOJO def (see UnitTestDriverImpl.cpp generated by Krusoe
    // plugin)
    final DefineSet defineSet = new DefineSet();
    final DefineArgument defineArgument = new DefineArgument();
    defineArgument.setName("VCPROJ_MOJO");
    defineSet.addDefine(defineArgument);
    cpp.addConfiguredDefineset(defineSet);

    // add javah include path
    final File jniDirectory = getJavah().getJniDirectory();
    if (jniDirectory.exists()) {
      task.createIncludePath().setPath(jniDirectory.getPath());
    }

    // add java include paths
    getJava().addIncludePaths(task, Library.EXECUTABLE);

    getMsvc().configureCCTask(task);

    final List dependencies = getNarArtifacts();
    // add dependency include paths
    for (final Object element : dependencies) {
      // FIXME, handle multiple includes from one NAR
      final NarArtifact narDependency = (NarArtifact) element;
      final String binding = narDependency.getNarInfo().getBinding(getAOL(), Library.STATIC);
      getLog().debug("Looking for " + narDependency + " found binding " + binding);
      if (!binding.equals(Library.JNI)) {
        final File unpackDirectory = getUnpackDirectory();
        final File include = getLayout().getIncludeDirectory(unpackDirectory, narDependency.getArtifactId(),
            narDependency.getBaseVersion());
        getLog().debug("Looking for directory: " + include);
        if (include.exists()) {
          task.createIncludePath().setPath(include.getPath());
        } else {
          getLog().warn(String.format("Unable to locate %1$s lib include path '%2$s'", binding, include));
        }
      }
    }

    // add linker
    final LinkerDef linkerDefinition = getLinker().getLinker(this, task, getOS(), getAOL().getKey() + ".linker.",
        type, null);
    task.addConfiguredLinker(linkerDefinition);

    // add dependency libraries
    // FIXME: what about PLUGIN and STATIC, depending on STATIC, should we
    // not add all libraries, see NARPLUGIN-96
    if (type.equals(Library.SHARED) || type.equals(Library.JNI) || type.equals(Library.EXECUTABLE)) {

      final List depLibOrder = getDependencyLibOrder();
      List depLibs = dependencies;

      // reorder the libraries that come from the nar dependencies
      // to comply with the order specified by the user
      if (depLibOrder != null && !depLibOrder.isEmpty()) {

        final List tmp = new LinkedList();

        for (final Object aDepLibOrder : depLibOrder) {

          final String depToOrderName = (String) aDepLibOrder;

          for (final Iterator j = depLibs.iterator(); j.hasNext(); ) {

            final NarArtifact dep = (NarArtifact) j.next();
            final String depName = dep.getGroupId() + ":" + dep.getArtifactId();

            if (depName.equals(depToOrderName)) {

              tmp.add(dep);
              j.remove();
            }
          }
        }

        tmp.addAll(depLibs);
        depLibs = tmp;
      }

      for (final Object depLib : depLibs) {

        final NarArtifact dependency = (NarArtifact) depLib;

        // FIXME no handling of "local"

        // FIXME, no way to override this at this stage
        final String binding = dependency.getNarInfo().getBinding(getAOL(), Library.STATIC);
        getLog().debug("Using Binding: " + binding);
        AOL aol = getAOL();
        aol = dependency.getNarInfo().getAOL(getAOL());
        getLog().debug("Using Library AOL: " + aol.toString());

        if (!binding.equals(Library.JNI) && !binding.equals(Library.NONE) && !binding.equals(Library.EXECUTABLE)) {
          final File unpackDirectory = getUnpackDirectory();
          final File dir = getLayout()
              .getLibDirectory(unpackDirectory, dependency.getArtifactId(), dependency.getBaseVersion(), aol.toString(),
                  binding);
          getLog().debug("Looking for Library Directory: " + dir);
          if (dir.exists()) {
            final LibrarySet libSet = new LibrarySet();
            libSet.setProject(antProject);

            // FIXME, no way to override
            final String libs = dependency.getNarInfo().getLibs(getAOL());
            if (libs != null && !libs.equals("")) {
              getLog().debug("Using LIBS = " + libs);
              libSet.setLibs(new CUtil.StringArrayBuilder(libs));
              libSet.setDir(dir);
              task.addLibset(libSet);
            }
          } else {
            getLog().debug("Library Directory " + dir + " does NOT exist.");
          }

          // FIXME, look again at this, for multiple dependencies we
          // may need to remove duplicates
          final String options = dependency.getNarInfo().getOptions(getAOL());
          if (options != null && !options.equals("")) {
            getLog().debug("Using OPTIONS = " + options);
            final LinkerArgument arg = new LinkerArgument();
            arg.setValue(options);
            linkerDefinition.addConfiguredLinkerArg(arg);
          }

          final String sysLibs = dependency.getNarInfo().getSysLibs(getAOL());

          if (sysLibs != null && !sysLibs.equals("")) {
            getLog().debug("Using SYSLIBS = " + sysLibs);
            final SystemLibrarySet sysLibSet = new SystemLibrarySet();
            sysLibSet.setProject(antProject);

            sysLibSet.setLibs(new CUtil.StringArrayBuilder(sysLibs));

            task.addSyslibset(sysLibSet);
          }
        }
      }

      // Add JVM to linker
      getJava().addRuntime(task, getJavaHome(getAOL()), getOS(), getAOL().getKey() + "java.");

      // DS: generate project file
      getLog().debug("NAR: Writing project file...");
      final ProjectWriterEnum projectWriterEnum = new ProjectWriterEnum();
      projectWriterEnum.setValue("msvc8");
      final ProjectDef projectDef = new ProjectDef();
      projectDef.setType(projectWriterEnum);
      String filename = null;
      try {
        final File outputDir = new File(getTargetDirectory(), "vcproj");
        if (!outputDir.exists()) {
          final boolean succeeded = outputDir.mkdir();
          if (!succeeded) {
            throw new MojoExecutionException("Unable to create directory: " + outputDir);
          }
        }
        filename = outputDir + "/" + getMavenProject().getArtifactId();
        final File projFile = new File(filename);
        projectDef.setOutfile(projFile.getCanonicalFile());
      } catch (final IOException e) {
        throw new MojoExecutionException("Unable to create file: " + filename, e);
      }
      task.addProject(projectDef);
      task.setProjectsOnly(true);

      // we always want an EXE for debugging
      task.setOuttype(new OutputTypeEnum());

      // execute
      try {
        task.execute();
        getLog().info("Wrote project file: " + filename + ".vcproj");
      } catch (final BuildException e) {
        throw new MojoExecutionException("NAR: Compile failed", e);
      }
    }
  }

  /**
   * List the dependencies needed for compilation, those dependencies are used
   * to get the include paths needed for
   * compilation and to get the libraries paths and names needed for linking.
   */
  @Override
  protected ScopeFilter getArtifactScopeFilter() {
    return new ScopeFilter( Artifact.SCOPE_COMPILE, null );
  }

  @Override
  public void narExecute() throws MojoExecutionException, MojoFailureException {

    // Only do this if MSVC++ compiler is being used.
    if (!getOS().equals(OS.WINDOWS)) {
      getLog().debug("Skipping -- not running on Windows");
      return;
    }

    // need to run with profile "windows-debug". No other profiles are valid
    // for vcproj generation.
    boolean debug = false;

    final List profiles = NarUtil.collectActiveProfiles(getMavenProject());
    for (final Object profile1 : profiles) {
      final Profile profile = (Profile) profile1;
      if (profile.getId().equalsIgnoreCase("windows-debug")) {
        debug = true;
        break;
      }
    }

    if (!debug) {
      getLog().info("NAR: Skipping vcproj generation.  Run with -P windows-debug to enable this step.");
      return;
    }

    if (getLibraries().isEmpty()) {
      getLog().info("NAR: Skipping vcproj generation.  No libraries to be built.");
      return;
    }

    // super.narExecute();

    // arbitrarily grab the first library -- we're going to make treat it as
    // an exe anyway, whatever type it's supposed to be.
    createVcProjFile(getAntProject(), getLibraries().get(0));
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy