Ejemplo n.º 1
0
  /**
   * Returns the linked artifact resulting from a linking of the given type. Consults the feature
   * configuration to obtain an action_config that provides the artifact. If the feature
   * configuration provides no artifact, uses a default.
   *
   * <p>We cannot assume that the feature configuration contains an action_config for the link
   * action, because the linux link action depends on hardcoded values in
   * LinkCommandLine.getRawLinkArgv(), which are applied on the condition that an action_config is
   * not present. TODO(b/30393154): Assert that the given link action has an action_config.
   *
   * @throws RuleErrorException
   */
  private Artifact getLinkedArtifact(LinkTargetType linkTargetType) throws RuleErrorException {
    Artifact result = null;
    Artifact linuxDefault = CppHelper.getLinuxLinkedArtifact(ruleContext, linkTargetType);

    try {
      String templatedName =
          features.getArtifactNameForCategory(
              linkTargetType.getLinkerOutput(), ruleContext, ImmutableMap.<String, String>of());
      PathFragment artifactFragment =
          new PathFragment(ruleContext.getLabel().getName())
              .getParentDirectory()
              .getRelative(templatedName);
      result =
          ruleContext.getPackageRelativeArtifact(
              artifactFragment, ruleContext.getConfiguration().getBinDirectory());
    } catch (ExpansionException e) {
      ruleContext.throwWithRuleError(e.getMessage());
    }

    // If the linked artifact is not the linux default, then a FailAction is generated for the
    // linux default to satisfy the requirement of the implicit output.
    // TODO(b/30132703): Remove the implicit outputs of cc_library.
    if (!result.equals(linuxDefault)) {
      ruleContext.registerAction(
          new FailAction(
              ruleContext.getActionOwner(),
              ImmutableList.of(linuxDefault),
              String.format(
                  "the given toolchain supports creation of %s instead of %s",
                  linuxDefault.getExecPathString(), result.getExecPathString())));
    }

    return result;
  }
Ejemplo n.º 2
0
  /**
   * Creates an action that converts {@code jarToDex} to a dex file. The output will be stored in
   * the {@link com.google.devtools.build.lib.actions.Artifact} {@code dxJar}.
   */
  public static void createDexAction(
      RuleContext ruleContext,
      Artifact jarToDex,
      Artifact classesDex,
      List<String> dexOptions,
      boolean multidex,
      Artifact mainDexList) {
    List<String> args = new ArrayList<>();
    args.add("--dex");
    // Add --no-locals to coverage builds.  Older coverage tools don't correctly preserve local
    // variable information in stack frame maps that are required since Java 7, so to avoid runtime
    // errors we just don't add local variable info in the first place.  This may no longer be
    // necessary, however, as long as we use a coverage tool that generates stack frame maps.
    if (ruleContext.getConfiguration().isCodeCoverageEnabled()) {
      args.add("--no-locals"); // TODO(bazel-team): Is this still needed?
    }

    // Multithreaded dex does not work when using --multi-dex.
    if (!multidex) {
      // Multithreaded dex tends to run faster, but only up to about 5 threads (at which point the
      // law of diminishing returns kicks in). This was determined experimentally, with 5-thread dex
      // performing about 25% faster than 1-thread dex.
      args.add("--num-threads=5");
    }

    args.addAll(dexOptions);
    if (multidex) {
      args.add("--multi-dex");
      if (mainDexList != null) {
        args.add("--main-dex-list=" + mainDexList.getExecPathString());
      }
    }
    args.add("--output=" + classesDex.getExecPathString());
    args.add(jarToDex.getExecPathString());

    SpawnAction.Builder builder =
        new SpawnAction.Builder()
            .setExecutable(AndroidSdkProvider.fromRuleContext(ruleContext).getDx())
            .addInput(jarToDex)
            .addOutput(classesDex)
            .addArguments(args)
            .setProgressMessage("Converting " + jarToDex.getExecPathString() + " to dex format")
            .setMnemonic("AndroidDexer")
            .setResources(ResourceSet.createWithRamCpuIo(4096.0, 5.0, 0.0));
    if (mainDexList != null) {
      builder.addInput(mainDexList);
    }
    ruleContext.registerAction(builder.build(ruleContext));
  }
Ejemplo n.º 3
0
  /**
   * Returns a raw link command for the given link invocation, including both command and arguments
   * (argv). After any further usage-specific processing, this can be passed to {@link
   * #finalizeWithLinkstampCommands} to give the final command line.
   *
   * @return raw link command line.
   */
  public List<String> getRawLinkArgv() {
    List<String> argv = new ArrayList<>();

    switch (linkTargetType) {
      case EXECUTABLE:
        argv.add(cppConfiguration.getCppExecutable().getPathString());
        argv.addAll(featureConfiguration.getCommandLine(actionName, variables));
        argv.addAll(noWholeArchiveFlags);
        addToolchainFlags(argv);
        break;

      case DYNAMIC_LIBRARY:
        if (interfaceOutput != null) {
          argv.add(configuration.getShExecutable().getPathString());
          argv.add("-c");
          argv.add(
              "build_iface_so=\"$0\"; impl=\"$1\"; iface=\"$2\"; cmd=\"$3\"; shift 3; "
                  + "\"$cmd\" \"$@\" && \"$build_iface_so\" \"$impl\" \"$iface\"");
          argv.add(interfaceSoBuilder.getExecPathString());
          argv.add(output.getExecPathString());
          argv.add(interfaceOutput.getExecPathString());
        }
        argv.add(cppConfiguration.getCppExecutable().getPathString());
        argv.addAll(featureConfiguration.getCommandLine(actionName, variables));
        argv.addAll(noWholeArchiveFlags);
        addToolchainFlags(argv);
        break;

      case STATIC_LIBRARY:
      case PIC_STATIC_LIBRARY:
      case ALWAYS_LINK_STATIC_LIBRARY:
      case ALWAYS_LINK_PIC_STATIC_LIBRARY:
        // The static library link command follows this template:
        // ar <cmd> <output_archive> <input_files...>
        argv.add(cppConfiguration.getArExecutable().getPathString());
        argv.addAll(
            cppConfiguration.getArFlags(cppConfiguration.archiveType() == Link.ArchiveType.THIN));
        argv.add(output.getExecPathString());
        argv.addAll(featureConfiguration.getCommandLine(actionName, variables));
        argv.addAll(noWholeArchiveFlags);
        break;

      default:
        throw new IllegalArgumentException();
    }

    return argv;
  }
Ejemplo n.º 4
0
  private CustomCommandLine getProtobufCommandLine() {
    CustomCommandLine.Builder commandLineBuilder =
        new CustomCommandLine.Builder()
            .add(attributes.getProtoCompiler().getExecPathString())
            .add("--input-file-list")
            .add(getProtoInputListFile().getExecPathString())
            .add("--output-dir")
            .add(getWorkspaceRelativeOutputDir().getSafePathString())
            .add("--force")
            .add("--proto-root-dir")
            .add(".");

    boolean configAdded = false;
    for (Artifact portableProtoFilter : getPortableProtoFilters()) {
      String configFlag;
      if (!configAdded) {
        configFlag = "--config";
        configAdded = true;
      } else {
        configFlag = "--extra-filter-config";
      }

      commandLineBuilder.add(configFlag).add(portableProtoFilter.getExecPathString());
    }
    return commandLineBuilder.build();
  }
  @Test
  public void testCppLinkActionExtraActionInfoWithSharedLibraries() throws Exception {
    ConfiguredTarget hello = getConfiguredTarget("//hello:hello");
    Artifact sharedObject =
        FileType.filter(getFilesToBuild(hello), CppFileTypes.SHARED_LIBRARY).iterator().next();
    CppLinkAction action = (CppLinkAction) getGeneratingAction(sharedObject);

    ExtraActionInfo.Builder builder = action.getExtraActionInfo();
    ExtraActionInfo info = builder.build();
    assertEquals("CppLink", info.getMnemonic());

    CppLinkInfo cppLinkInfo = info.getExtension(CppLinkInfo.cppLinkInfo);
    assertNotNull(cppLinkInfo);

    Iterable<String> inputs =
        Artifact.asExecPaths(
            LinkerInputs.toLibraryArtifacts(action.getLinkCommandLine().getLinkerInputs()));
    assertThat(cppLinkInfo.getInputFileList()).containsExactlyElementsIn(inputs);
    assertEquals(action.getPrimaryOutput().getExecPathString(), cppLinkInfo.getOutputFile());
    Artifact interfaceOutput = action.getLinkCommandLine().getInterfaceOutput();
    assertEquals(interfaceOutput.getExecPathString(), cppLinkInfo.getInterfaceOutputFile());
    assertEquals(
        action.getLinkCommandLine().getLinkTargetType().name(), cppLinkInfo.getLinkTargetType());
    assertEquals(
        action.getLinkCommandLine().getLinkStaticness().name(), cppLinkInfo.getLinkStaticness());
    Iterable<String> linkstamps =
        Artifact.asExecPaths(action.getLinkCommandLine().getLinkstamps().values());
    assertThat(cppLinkInfo.getLinkStampList()).containsExactlyElementsIn(linkstamps);
    Iterable<String> buildInfoHeaderArtifacts =
        Artifact.asExecPaths(action.getLinkCommandLine().getBuildInfoHeaderArtifacts());
    assertThat(cppLinkInfo.getBuildInfoHeaderArtifactList())
        .containsExactlyElementsIn(buildInfoHeaderArtifacts);
    assertThat(cppLinkInfo.getLinkOptList())
        .containsExactlyElementsIn(action.getLinkCommandLine().getLinkopts());
  }
Ejemplo n.º 6
0
  /**
   * Creates a generating action for {@code outApk} that builds the APK specified.
   *
   * <p>If {@code signingKey} is not null, the apk will be signed with it using the V1 signature
   * scheme.
   */
  Action[] buildApk(RuleContext ruleContext, Artifact outApk, Artifact signingKey, String message) {
    SpawnAction.Builder actionBuilder =
        new SpawnAction.Builder()
            .setExecutable(AndroidSdkProvider.fromRuleContext(ruleContext).getApkBuilder())
            .setProgressMessage(message)
            .setMnemonic("AndroidApkBuilder")
            .addOutputArgument(outApk);

    if (javaResourceZip != null) {
      actionBuilder.addArgument("-rj").addInputArgument(javaResourceZip);
    }

    Artifact nativeSymlinks = nativeLibs.createApkBuilderSymlinks(ruleContext);
    if (nativeSymlinks != null) {
      PathFragment nativeSymlinksDir = nativeSymlinks.getExecPath().getParentDirectory();
      actionBuilder
          .addInputManifest(nativeSymlinks, nativeSymlinksDir)
          .addInput(nativeSymlinks)
          .addInputs(nativeLibs.getAllNativeLibs())
          .addArgument("-nf")
          // If the native libs are "foo/bar/x86/foo.so", we need to pass "foo/bar" here
          .addArgument(nativeSymlinksDir.getPathString());
    }

    if (nativeLibs.getName() != null) {
      actionBuilder
          .addArgument("-rf")
          .addArgument(nativeLibs.getName().getExecPath().getParentDirectory().getPathString())
          .addInput(nativeLibs.getName());
    }

    if (javaResourceFile != null) {
      actionBuilder
          .addArgument("-rf")
          .addArgument((javaResourceFile.getExecPath().getParentDirectory().getPathString()))
          .addInput(javaResourceFile);
    }

    if (signingKey == null) {
      actionBuilder.addArgument("-u");
    } else {
      actionBuilder.addArgument("-ks").addArgument(signingKey.getExecPathString());
      actionBuilder.addInput(signingKey);
    }

    actionBuilder.addArgument("-z").addInputArgument(resourceApk);

    if (classesDex != null) {
      actionBuilder
          .addArgument(classesDex.getFilename().endsWith(".dex") ? "-f" : "-z")
          .addInputArgument(classesDex);
    }

    return actionBuilder.build(ruleContext);
  }
Ejemplo n.º 7
0
 /**
  * Adds a source to {@code compilationUnitSources} if it is a compiled file type (including
  * parsed/preprocessed header) and to {@code privateHeaders} if it is a header.
  */
 private void addSource(Artifact source, Label label) {
   boolean isHeader = CppFileTypes.CPP_HEADER.matches(source.getExecPath());
   boolean isTextualInclude = CppFileTypes.CPP_TEXTUAL_INCLUDE.matches(source.getExecPath());
   boolean isCompiledSource = SOURCE_TYPES.matches(source.getExecPathString());
   if (isHeader || isTextualInclude) {
     privateHeaders.add(source);
   }
   if (isTextualInclude || !isCompiledSource || (isHeader && !shouldProcessHeaders())) {
     return;
   }
   compilationUnitSources.add(Pair.of(source, label));
 }
Ejemplo n.º 8
0
  public static CustomCommandLine.Builder defaultSingleJarCommandLine(
      Artifact outputJar,
      String javaMainClass,
      ImmutableList<String> deployManifestLines,
      Iterable<Artifact> buildInfoFiles,
      ImmutableList<Artifact> classpathResources,
      Iterable<Artifact> runtimeClasspath,
      boolean includeBuildData,
      Compression compress,
      Artifact launcher) {

    CustomCommandLine.Builder args = CustomCommandLine.builder();
    args.addExecPath("--output", outputJar);
    if (compress == Compression.COMPRESSED) {
      args.add("--compression");
    }
    args.add("--normalize");
    if (javaMainClass != null) {
      args.add("--main_class");
      args.add(javaMainClass);
    }

    if (!deployManifestLines.isEmpty()) {
      args.add("--deploy_manifest_lines");
      args.add(deployManifestLines);
    }

    if (buildInfoFiles != null) {
      for (Artifact artifact : buildInfoFiles) {
        args.addExecPath("--build_info_file", artifact);
      }
    }
    if (!includeBuildData) {
      args.add("--exclude_build_data");
    }
    if (launcher != null) {
      args.add("--java_launcher");
      args.add(launcher.getExecPathString());
    }

    args.addExecPaths("--classpath_resources", classpathResources);
    args.addExecPaths("--sources", runtimeClasspath);
    return args;
  }
Ejemplo n.º 9
0
 /**
  * Select .pcm inputs to pass on the command line depending on whether we are in pic or non-pic
  * mode.
  */
 private Collection<String> getHeaderModulePaths(CppCompileActionBuilder builder, boolean usePic) {
   Collection<String> result = new LinkedHashSet<>();
   NestedSet<Artifact> artifacts =
       featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULE_INCLUDES_DEPENDENCIES)
           ? builder.getContext().getTopLevelHeaderModules(usePic)
           : builder.getContext().getAdditionalInputs(usePic);
   for (Artifact artifact : artifacts) {
     String filename = artifact.getFilename();
     if (!filename.endsWith(".pcm")) {
       continue;
     }
     // Depending on whether this specific compile action is pic or non-pic, select the
     // corresponding header modules. Note that the compilation context might give us both
     // from targets that are built in both modes.
     if (usePic == filename.endsWith(".pic.pcm")) {
       result.add(artifact.getExecPathString());
     }
   }
   return result;
 }
  protected void createActions(
      ConfiguredTarget base,
      RuleContext ruleContext,
      Iterable<Artifact> protoSources,
      NestedSet<Artifact> transitiveProtoSources,
      Iterable<Artifact> headerMappingFiles,
      Iterable<Artifact> classMappingFiles,
      J2ObjcSource j2ObjcSource) {
    String genDir = ruleContext.getConfiguration().getGenfilesDirectory().getExecPathString();
    Artifact compiler = ruleContext.getPrerequisiteArtifact("$protoc_darwin", Mode.HOST);
    Artifact j2objcPlugin = ruleContext.getPrerequisiteArtifact("$j2objc_plugin", Mode.HOST);

    ruleContext.registerAction(
        new SpawnAction.Builder()
            .setMnemonic("TranslatingJ2ObjcProtos")
            .addInput(compiler)
            .addInput(j2objcPlugin)
            .addInputs(
                ruleContext.getPrerequisiteArtifacts("$protoc_support_darwin", Mode.HOST).list())
            .addInputs(protoSources)
            .addTransitiveInputs(transitiveProtoSources)
            .addOutputs(j2ObjcSource.getObjcSrcs())
            .addOutputs(j2ObjcSource.getObjcHdrs())
            .addOutputs(headerMappingFiles)
            .addOutputs(classMappingFiles)
            .setExecutable(new PathFragment("/usr/bin/python"))
            .setCommandLine(
                new CustomCommandLine.Builder()
                    .add(compiler.getPath().toString())
                    .add("-w")
                    .add(compiler.getRoot().getPath().toString())
                    .add("--generate-j2objc")
                    .add("--generator-param=file_dir_mapping")
                    .add("--generator-param=generate_class_mappings")
                    .add("--j2objc-plugin=" + j2objcPlugin.getExecPathString())
                    .add("--output-dir=" + genDir)
                    .addExecPaths(protoSources)
                    .build())
            .setExecutionInfo(ImmutableMap.of(ExecutionRequirements.REQUIRES_DARWIN, ""))
            .build(ruleContext));
  }
Ejemplo n.º 11
0
  /** Returns this target's Xcode build settings. */
  private Iterable<XcodeprojBuildSetting> buildSettings() {
    ImmutableList.Builder<XcodeprojBuildSetting> buildSettings = new ImmutableList.Builder<>();
    if (attributes.appIcon() != null) {
      buildSettings.add(
          XcodeprojBuildSetting.newBuilder()
              .setName("ASSETCATALOG_COMPILER_APPICON_NAME")
              .setValue(attributes.appIcon())
              .build());
    }
    if (attributes.launchImage() != null) {
      buildSettings.add(
          XcodeprojBuildSetting.newBuilder()
              .setName("ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME")
              .setValue(attributes.launchImage())
              .build());
    }

    // Convert names to a sequence containing "1" and/or "2" for iPhone and iPad, respectively.
    ImmutableSet<TargetDeviceFamily> families = bundleSupport.targetDeviceFamilies();
    Iterable<Integer> familyIndexes =
        families.isEmpty() ? ImmutableList.<Integer>of() : UI_DEVICE_FAMILY_VALUES.get(families);
    buildSettings.add(
        XcodeprojBuildSetting.newBuilder()
            .setName("TARGETED_DEVICE_FAMILY")
            .setValue(Joiner.on(',').join(familyIndexes))
            .build());

    Artifact entitlements = attributes.entitlements();
    if (entitlements != null) {
      buildSettings.add(
          XcodeprojBuildSetting.newBuilder()
              .setName("CODE_SIGN_ENTITLEMENTS")
              .setValue("$(WORKSPACE_ROOT)/" + entitlements.getExecPathString())
              .build());
    }

    return buildSettings.build();
  }
Ejemplo n.º 12
0
  private void setupCompileBuildVariables(
      CppCompileActionBuilder builder,
      boolean usePic,
      PathFragment ccRelativeName,
      PathFragment autoFdoImportPath,
      Artifact gcnoFile,
      Artifact dwoFile,
      Map<String, String> sourceSpecificBuildVariables) {
    CcToolchainFeatures.Variables.Builder buildVariables =
        new CcToolchainFeatures.Variables.Builder();

    // TODO(bazel-team): Pull out string constants for all build variables.

    CppCompilationContext builderContext = builder.getContext();
    CppModuleMap cppModuleMap = builderContext.getCppModuleMap();
    Artifact sourceFile = builder.getSourceFile();
    Artifact outputFile = builder.getOutputFile();
    String realOutputFilePath;

    buildVariables.addVariable("source_file", sourceFile.getExecPathString());
    buildVariables.addVariable("output_file", outputFile.getExecPathString());

    if (builder.getTempOutputFile() != null) {
      realOutputFilePath = builder.getTempOutputFile().getPathString();
    } else {
      realOutputFilePath = builder.getOutputFile().getExecPathString();
    }

    if (FileType.contains(outputFile, CppFileTypes.ASSEMBLER, CppFileTypes.PIC_ASSEMBLER)) {
      buildVariables.addVariable("output_assembly_file", realOutputFilePath);
    } else if (FileType.contains(
        outputFile,
        CppFileTypes.PREPROCESSED_C,
        CppFileTypes.PREPROCESSED_CPP,
        CppFileTypes.PIC_PREPROCESSED_C,
        CppFileTypes.PIC_PREPROCESSED_CPP)) {
      buildVariables.addVariable("output_preprocess_file", realOutputFilePath);
    } else {
      buildVariables.addVariable("output_object_file", realOutputFilePath);
    }

    DotdFile dotdFile =
        CppFileTypes.mustProduceDotdFile(sourceFile.getPath().toString())
            ? Preconditions.checkNotNull(builder.getDotdFile())
            : null;
    // Set dependency_file to enable <object>.d file generation.
    if (dotdFile != null) {
      buildVariables.addVariable("dependency_file", dotdFile.getSafeExecPath().getPathString());
    }

    if (featureConfiguration.isEnabled(CppRuleClasses.MODULE_MAPS) && cppModuleMap != null) {
      // If the feature is enabled and cppModuleMap is null, we are about to fail during analysis
      // in any case, but don't crash.
      buildVariables.addVariable("module_name", cppModuleMap.getName());
      buildVariables.addVariable("module_map_file", cppModuleMap.getArtifact().getExecPathString());
      CcToolchainFeatures.Variables.ValueSequence.Builder sequence =
          new CcToolchainFeatures.Variables.ValueSequence.Builder();
      for (Artifact artifact : builderContext.getDirectModuleMaps()) {
        sequence.addValue(artifact.getExecPathString());
      }
      buildVariables.addSequence("dependent_module_map_files", sequence.build());
    }
    if (featureConfiguration.isEnabled(CppRuleClasses.USE_HEADER_MODULES)) {
      buildVariables.addSequenceVariable("module_files", getHeaderModulePaths(builder, usePic));
    }
    if (featureConfiguration.isEnabled(CppRuleClasses.INCLUDE_PATHS)) {
      buildVariables.addSequenceVariable(
          "include_paths", getSafePathStrings(builderContext.getIncludeDirs()));
      buildVariables.addSequenceVariable(
          "quote_include_paths", getSafePathStrings(builderContext.getQuoteIncludeDirs()));
      buildVariables.addSequenceVariable(
          "system_include_paths", getSafePathStrings(builderContext.getSystemIncludeDirs()));
    }

    if (featureConfiguration.isEnabled(CppRuleClasses.PREPROCESSOR_DEFINES)) {
      String fdoBuildStamp = CppHelper.getFdoBuildStamp(ruleContext);
      ImmutableList<String> defines;
      if (fdoBuildStamp != null) {
        // Stamp FDO builds with FDO subtype string
        defines =
            ImmutableList.<String>builder()
                .addAll(builderContext.getDefines())
                .add(
                    CppConfiguration.FDO_STAMP_MACRO
                        + "=\""
                        + CppHelper.getFdoBuildStamp(ruleContext)
                        + "\"")
                .build();
      } else {
        defines = builderContext.getDefines();
      }

      buildVariables.addSequenceVariable("preprocessor_defines", defines);
    }

    if (usePic) {
      if (!featureConfiguration.isEnabled(CppRuleClasses.PIC)) {
        ruleContext.ruleError("PIC compilation is requested but the toolchain does not support it");
      }
      buildVariables.addVariable("pic", "");
    }

    if (ccRelativeName != null) {
      CppHelper.getFdoSupport(ruleContext)
          .configureCompilation(
              builder,
              buildVariables,
              ruleContext,
              ccRelativeName,
              autoFdoImportPath,
              usePic,
              featureConfiguration);
    }
    if (gcnoFile != null) {
      buildVariables.addVariable("gcov_gcno_file", gcnoFile.getExecPathString());
    }

    if (dwoFile != null) {
      buildVariables.addVariable("per_object_debug_info_file", dwoFile.getExecPathString());
    }

    buildVariables.addAllVariables(CppHelper.getToolchain(ruleContext).getBuildVariables());

    buildVariables.addAllVariables(sourceSpecificBuildVariables);

    for (VariablesExtension extension : variablesExtensions) {
      extension.addVariables(buildVariables);
    }

    CcToolchainFeatures.Variables variables = buildVariables.build();
    builder.setVariables(variables);
  }
Ejemplo n.º 13
0
  /**
   * Computes, for each C++ source file in {@link #getLinkstamps}, the command necessary to compile
   * that file such that the output is correctly fed into the link command.
   *
   * <p>As these options (as well as all others) are taken into account when computing the action
   * key, they do not directly contain volatile build information to avoid unnecessary relinking.
   * Instead this information is passed as an additional header generated by {@link
   * com.google.devtools.build.lib.rules.cpp.WriteBuildInfoHeaderAction}.
   *
   * @param outputPrefix prefix to add before the linkstamp outputs' exec paths
   * @return a list of shell-escaped compiler commmands, one for each entry in {@link
   *     #getLinkstamps}
   */
  public List<String> getLinkstampCompileCommands(String outputPrefix) {
    if (linkstamps.isEmpty()) {
      return ImmutableList.of();
    }

    String compilerCommand = cppConfiguration.getCppExecutable().getPathString();
    List<String> commands = Lists.newArrayListWithCapacity(linkstamps.size());

    for (Map.Entry<Artifact, Artifact> linkstamp : linkstamps.entrySet()) {
      List<String> optionList = new ArrayList<>();

      // Defines related to the build info are read from generated headers.
      for (Artifact header : buildInfoHeaderArtifacts) {
        optionList.add("-include");
        optionList.add(header.getExecPathString());
      }

      String labelReplacement =
          Matcher.quoteReplacement(
              isSharedNativeLibrary() ? output.getExecPathString() : Label.print(owner.getLabel()));
      String outputPathReplacement = Matcher.quoteReplacement(output.getExecPathString());
      for (String option : linkstampCompileOptions) {
        optionList.add(
            option
                .replaceAll(Pattern.quote("${LABEL}"), labelReplacement)
                .replaceAll(Pattern.quote("${OUTPUT_PATH}"), outputPathReplacement));
      }

      optionList.add("-DGPLATFORM=\"" + cppConfiguration + "\"");

      // Needed to find headers included from linkstamps.
      optionList.add("-I.");

      // Add sysroot.
      PathFragment sysroot = cppConfiguration.getSysroot();
      if (sysroot != null) {
        optionList.add("--sysroot=" + sysroot.getPathString());
      }

      // Add toolchain compiler options.
      optionList.addAll(cppConfiguration.getCompilerOptions(features));
      optionList.addAll(cppConfiguration.getCOptions());
      optionList.addAll(cppConfiguration.getUnfilteredCompilerOptions(features));
      if (CppFileTypes.CPP_SOURCE.matches(linkstamp.getKey().getExecPath())) {
        optionList.addAll(cppConfiguration.getCxxOptions(features));
      }

      // For dynamic libraries, produce position independent code.
      if (linkTargetType == LinkTargetType.DYNAMIC_LIBRARY
          && cppConfiguration.toolchainNeedsPic()) {
        optionList.add("-fPIC");
      }

      // Stamp FDO builds with FDO subtype string
      if (fdoBuildStamp != null) {
        optionList.add("-D" + CppConfiguration.FDO_STAMP_MACRO + "=\"" + fdoBuildStamp + "\"");
      }

      // Add the compilation target.
      optionList.add("-c");
      optionList.add(linkstamp.getKey().getExecPathString());

      // Assemble the final command, exempting outputPrefix from shell escaping.
      commands.add(
          compilerCommand
              + " "
              + ShellEscaper.escapeJoinAll(optionList)
              + " -o "
              + outputPrefix
              + ShellEscaper.escapeString(linkstamp.getValue().getExecPathString()));
    }

    return commands;
  }
Ejemplo n.º 14
0
  /**
   * {@inheritDoc}
   *
   * <p>Creates a target, including registering actions, just as {@link #create(RuleContext)} does.
   * The difference between {@link #create(RuleContext)} and this method is that this method does
   * only what is needed to support tests on the environment besides generate the Xcodeproj file and
   * build the app and test {@code .ipa}s. The {@link #create(RuleContext)} method delegates to this
   * method.
   */
  @Override
  public final ConfiguredTarget create(RuleContext ruleContext)
      throws InterruptedException, RuleErrorException {
    ProtobufSupport protoSupport =
        new ProtobufSupport(ruleContext).registerGenerationActions().registerCompilationActions();
    Optional<ObjcProvider> protosObjcProvider = protoSupport.getObjcProvider();
    Optional<XcodeProvider> protosXcodeProvider = protoSupport.getXcodeProvider();

    ObjcCommon common = common(ruleContext, protosObjcProvider);

    if (!common.getCompilationArtifacts().get().getArchive().isPresent()) {
      ruleContext.ruleError(REQUIRES_SOURCE_ERROR);
    }

    if (!ruleContext.getFragment(AppleConfiguration.class).getIosMultiCpus().isEmpty()) {
      ruleContext.ruleError(NO_MULTI_CPUS_ERROR);
    }

    XcodeProvider.Builder xcodeProviderBuilder =
        new XcodeProvider.Builder().addPropagatedDependencies(protosXcodeProvider.asSet());

    NestedSetBuilder<Artifact> filesToBuild = NestedSetBuilder.stableOrder();
    addResourceFilesToBuild(ruleContext, common.getObjcProvider(), filesToBuild);

    XcodeProductType productType = getProductType(ruleContext);
    ExtraLinkArgs extraLinkArgs;
    Iterable<Artifact> extraLinkInputs;
    String bundleFormat;
    if (!isXcTest(ruleContext)) {
      extraLinkArgs = new ExtraLinkArgs();
      extraLinkInputs = ImmutableList.of();
      bundleFormat = ReleaseBundlingSupport.APP_BUNDLE_DIR_FORMAT;
    } else {
      XcodeProvider appIpaXcodeProvider =
          ruleContext.getPrerequisite(XCTEST_APP_ATTR, Mode.TARGET, XcodeProvider.class);
      xcodeProviderBuilder.setTestHost(appIpaXcodeProvider).setProductType(productType);

      XcTestAppProvider testApp = xcTestAppProvider(ruleContext);
      Artifact bundleLoader = testApp.getBundleLoader();

      // -bundle causes this binary to be linked as a bundle and not require an entry point
      // (i.e. main())
      // -bundle_loader causes the code in this test to have access to the symbols in the test rig,
      // or more specifically, the flag causes ld to consider the given binary when checking for
      // missing symbols.
      // -rpath @loader_path/Frameworks allows test bundles to load dylibs from the app's
      // Frameworks directory.
      extraLinkArgs =
          new ExtraLinkArgs(
              "-bundle",
              "-bundle_loader",
              bundleLoader.getExecPathString(),
              "-Xlinker",
              "-rpath",
              "-Xlinker",
              "@loader_path/Frameworks");

      extraLinkInputs = ImmutableList.of(bundleLoader);
      bundleFormat = ReleaseBundlingSupport.XCTEST_BUNDLE_DIR_FORMAT;

      filesToBuild.add(testApp.getIpa());
    }

    J2ObjcMappingFileProvider j2ObjcMappingFileProvider =
        J2ObjcMappingFileProvider.union(
            ruleContext.getPrerequisites("deps", Mode.TARGET, J2ObjcMappingFileProvider.class));
    J2ObjcEntryClassProvider j2ObjcEntryClassProvider =
        new J2ObjcEntryClassProvider.Builder()
            .addTransitive(
                ruleContext.getPrerequisites("deps", Mode.TARGET, J2ObjcEntryClassProvider.class))
            .build();

    new CompilationSupport(ruleContext)
        .registerLinkActions(
            common.getObjcProvider(),
            j2ObjcMappingFileProvider,
            j2ObjcEntryClassProvider,
            extraLinkArgs,
            extraLinkInputs,
            DsymOutputType.TEST)
        .registerCompileAndArchiveActions(common)
        .registerFullyLinkAction(
            common.getObjcProvider(),
            ruleContext.getImplicitOutputArtifact(CompilationSupport.FULLY_LINKED_LIB))
        .addXcodeSettings(xcodeProviderBuilder, common)
        .validateAttributes();

    AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class);
    new ReleaseBundlingSupport(
            ruleContext,
            common.getObjcProvider(),
            LinkedBinary.LOCAL_AND_DEPENDENCIES,
            bundleFormat,
            appleConfiguration.getMinimumOsForPlatformType(PlatformType.IOS),
            appleConfiguration.getMultiArchPlatform(PlatformType.IOS))
        .registerActions(DsymOutputType.TEST)
        .addXcodeSettings(xcodeProviderBuilder)
        .addFilesToBuild(filesToBuild, Optional.of(DsymOutputType.TEST))
        .validateResources()
        .validateAttributes();

    new ResourceSupport(ruleContext).validateAttributes().addXcodeSettings(xcodeProviderBuilder);

    new XcodeSupport(ruleContext)
        .addXcodeSettings(xcodeProviderBuilder, common.getObjcProvider(), productType)
        .addDependencies(xcodeProviderBuilder, new Attribute("bundles", Mode.TARGET))
        .addDependencies(xcodeProviderBuilder, new Attribute("deps", Mode.TARGET))
        .addNonPropagatedDependencies(
            xcodeProviderBuilder, new Attribute("non_propagated_deps", Mode.TARGET))
        .addFilesToBuild(filesToBuild)
        .registerActions(xcodeProviderBuilder.build());

    XcodeProvider xcodeProvider = xcodeProviderBuilder.build();
    NestedSet<Artifact> filesToBuildSet = filesToBuild.build();

    Runfiles.Builder runfilesBuilder =
        new Runfiles.Builder(
                ruleContext.getWorkspaceName(),
                ruleContext.getConfiguration().legacyExternalRunfiles())
            .addRunfiles(ruleContext, RunfilesProvider.DEFAULT_RUNFILES);

    NestedSetBuilder<Artifact> filesToBuildBuilder =
        NestedSetBuilder.<Artifact>stableOrder().addTransitive(filesToBuildSet);

    InstrumentedFilesProvider instrumentedFilesProvider =
        new CompilationSupport(ruleContext).getInstrumentedFilesProvider(common);

    TestSupport testSupport =
        new TestSupport(ruleContext)
            .registerTestRunnerActions()
            .addRunfiles(runfilesBuilder, instrumentedFilesProvider)
            .addFilesToBuild(filesToBuildBuilder);

    Artifact executable = testSupport.generatedTestScript();

    Runfiles runfiles = runfilesBuilder.build();
    RunfilesSupport runfilesSupport =
        RunfilesSupport.withExecutable(ruleContext, runfiles, executable);

    ImmutableMap.Builder<String, String> execInfoMapBuilder = new ImmutableMap.Builder<>();
    execInfoMapBuilder.put(ExecutionRequirements.REQUIRES_DARWIN, "");
    if (ruleContext.getFragment(ObjcConfiguration.class).runMemleaks()) {
      execInfoMapBuilder.put("nosandbox", "");
    }

    return new RuleConfiguredTargetBuilder(ruleContext)
        .setFilesToBuild(filesToBuildBuilder.build())
        .addProvider(xcodeProvider)
        .addProvider(RunfilesProvider.simple(runfiles))
        .addProvider(new ExecutionInfoProvider(execInfoMapBuilder.build()))
        .addProvider(InstrumentedFilesProvider.class, instrumentedFilesProvider)
        .addProviders(testSupport.getExtraProviders())
        .setRunfilesSupport(runfilesSupport, executable)
        .build();
  }
Ejemplo n.º 15
0
 private String extractPlistCommand(Artifact provisioningProfile) {
   return "security cms -D -i " + ShellUtils.shellEscape(provisioningProfile.getExecPathString());
 }
Ejemplo n.º 16
0
  private TargetControl targetControl() {
    String buildFilePath = label.getPackageFragment().getSafePathString() + "/BUILD";
    NestedSet<String> userHeaderSearchPaths =
        NestedSetBuilder.<String>linkOrder()
            .addTransitive(propagatedUserHeaderSearchPaths)
            .addTransitive(nonPropagatedUserHeaderSearchPaths)
            .build();
    NestedSet<String> headerSearchPaths =
        NestedSetBuilder.<String>linkOrder()
            .addTransitive(propagatedHeaderSearchPaths)
            .addTransitive(nonPropagatedHeaderSearchPaths)
            .build();

    // TODO(bazel-team): Add provisioning profile information when Xcodegen supports it.
    TargetControl.Builder targetControl =
        TargetControl.newBuilder()
            .setName(label.getName())
            .setLabel(xcodeTargetName(label))
            .setProductType(productType.getIdentifier())
            .addSupportFile(buildFilePath)
            .addAllImportedLibrary(Artifact.toExecPaths(objcProvider.get(IMPORTED_LIBRARY)))
            .addAllImportedLibrary(Artifact.toExecPaths(ccLibraries(objcProvider)))
            .addAllUserHeaderSearchPath(userHeaderSearchPaths)
            .addAllHeaderSearchPath(headerSearchPaths)
            .addAllSupportFile(Artifact.toExecPaths(headers))
            .addAllCopt(compilationModeCopts)
            .addAllCopt(CompilationSupport.DEFAULT_COMPILER_FLAGS)
            .addAllCopt(Interspersing.prependEach("-D", objcProvider.get(DEFINE)))
            .addAllCopt(copts)
            .addAllLinkopt(
                Interspersing.beforeEach("-force_load", objcProvider.get(FORCE_LOAD_FOR_XCODEGEN)))
            .addAllLinkopt(CompilationSupport.DEFAULT_LINKER_FLAGS)
            .addAllLinkopt(
                Interspersing.beforeEach(
                    "-weak_framework", SdkFramework.names(objcProvider.get(WEAK_SDK_FRAMEWORK))))
            .addAllBuildSetting(xcodeprojBuildSettings)
            .addAllBuildSetting(AppleToolchain.defaultWarningsForXcode())
            .addAllSdkFramework(SdkFramework.names(objcProvider.get(SDK_FRAMEWORK)))
            .addAllFramework(PathFragment.safePathStrings(objcProvider.get(FRAMEWORK_DIR)))
            .addAllFrameworkSearchPathOnly(
                PathFragment.safePathStrings(objcProvider.get(FRAMEWORK_SEARCH_PATH_ONLY)))
            .addAllXcassetsDir(PathFragment.safePathStrings(objcProvider.get(XCASSETS_DIR)))
            .addAllXcdatamodel(
                PathFragment.safePathStrings(
                    Xcdatamodels.datamodelDirs(objcProvider.get(XCDATAMODEL))))
            .addAllBundleImport(PathFragment.safePathStrings(objcProvider.get(BUNDLE_IMPORT_DIR)))
            .addAllSdkDylib(objcProvider.get(SDK_DYLIB))
            .addAllGeneralResourceFile(
                Artifact.toExecPaths(objcProvider.get(GENERAL_RESOURCE_FILE)))
            .addAllGeneralResourceFile(
                PathFragment.safePathStrings(objcProvider.get(GENERAL_RESOURCE_DIR)));

    if (CAN_LINK_PRODUCT_TYPES.contains(productType)) {
      // For builds with --ios_multi_cpus set, we may have several copies of some XCodeProviders
      // in the dependencies (one per cpu architecture). We deduplicate the corresponding
      // xcode target names with a LinkedHashSet before adding to the TargetControl.
      Set<String> jreTargetNames = new HashSet<>();
      for (XcodeProvider jreDependency : jreDependencies) {
        jreTargetNames.add(jreDependency.dependencyXcodeTargetName());
      }
      Set<DependencyControl> dependencySet = new LinkedHashSet<>();
      Set<DependencyControl> jreDependencySet = new LinkedHashSet<>();
      for (XcodeProvider dependency : propagatedDependencies) {
        // Only add a library target to a binary's dependencies if it has source files to compile
        // and it is not from the "non_propagated_deps" attribute. Xcode cannot build targets
        // without a source file in the PBXSourceFilesBuildPhase, so if such a target is present in
        // the control file, it is only to get Xcodegen to put headers and resources not used by the
        // final binary in the Project Navigator.
        //
        // The exceptions to this rule are objc_bundle_library and ios_extension targets. Bundles
        // are generally used for resources and can lack a PBXSourceFilesBuildPhase in the project
        // file and still be considered valid by Xcode.
        //
        // ios_extension targets are an exception because they have no CompilationArtifact object
        // but do have a dummy source file to make Xcode happy.
        boolean hasSources =
            dependency.compilationArtifacts.isPresent()
                && dependency.compilationArtifacts.get().getArchive().isPresent();
        if (hasSources
            || (dependency.productType == XcodeProductType.BUNDLE
                || (dependency.productType == XcodeProductType.WATCH_OS1_APPLICATION))) {
          String dependencyXcodeTargetName = dependency.dependencyXcodeTargetName();
          Set<DependencyControl> set =
              jreTargetNames.contains(dependencyXcodeTargetName) ? jreDependencySet : dependencySet;
          set.add(DependencyControl.newBuilder().setTargetLabel(dependencyXcodeTargetName).build());
        }
      }

      for (DependencyControl dependencyControl : dependencySet) {
        targetControl.addDependency(dependencyControl);
      }
      // Make sure that JRE dependencies are ordered after other propagated dependencies.
      for (DependencyControl dependencyControl : jreDependencySet) {
        targetControl.addDependency(dependencyControl);
      }
    }
    for (XcodeProvider justTestHost : testHost.asSet()) {
      targetControl.addDependency(
          DependencyControl.newBuilder()
              .setTargetLabel(xcodeTargetName(justTestHost.label))
              .setTestHost(true)
              .build());
    }
    for (XcodeProvider extension : extensions) {
      targetControl.addDependency(
          DependencyControl.newBuilder().setTargetLabel(xcodeTargetName(extension.label)).build());
    }

    if (bundleInfoplist.isPresent()) {
      targetControl.setInfoplist(bundleInfoplist.get().getExecPathString());
    }
    for (CompilationArtifacts artifacts : compilationArtifacts.asSet()) {
      targetControl
          .addAllSourceFile(Artifact.toExecPaths(artifacts.getSrcs()))
          .addAllSupportFile(Artifact.toExecPaths(artifacts.getAdditionalHdrs()))
          .addAllSupportFile(Artifact.toExecPaths(artifacts.getPrivateHdrs()))
          .addAllNonArcSourceFile(Artifact.toExecPaths(artifacts.getNonArcSrcs()));

      for (Artifact pchFile : artifacts.getPchFile().asSet()) {
        targetControl
            .setPchPath(pchFile.getExecPathString())
            .addSupportFile(pchFile.getExecPathString());
      }
    }

    for (Artifact artifact : additionalSources) {
      targetControl.addSourceFile(artifact.getExecPathString());
    }

    if (objcProvider.is(Flag.USES_CPP)) {
      targetControl.addSdkDylib("libc++");
    }

    return targetControl.build();
  }