aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/objc/IosSdkCommands.java
blob: 99a2ad03bcddd2c9af0438833ee5e99afc91d3c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright 2014 Google Inc. All rights reserved.
//
// 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.

package com.google.devtools.build.lib.rules.objc;

import static com.google.devtools.build.lib.rules.objc.ObjcProvider.FRAMEWORK_DIR;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.xcode.xcodegen.proto.XcodeGenProtos.XcodeprojBuildSetting;

import java.util.List;

/**
 * Utility code for use when generating iOS SDK commands.
 */
public class IosSdkCommands {
  public static final String DEVELOPER_DIR = "/Applications/Xcode.app/Contents/Developer";
  public static final String ACTOOL_PATH = DEVELOPER_DIR + "/usr/bin/actool";
  public static final String MOMC_PATH = DEVELOPER_DIR + "/usr/bin/momc";

  // There is a handy reference to many clang warning flags at
  // http://nshipster.com/clang-diagnostics/
  // There is also a useful narrative for many Xcode settings at
  // http://www.xs-labs.com/en/blog/2011/02/04/xcode-build-settings/
  @VisibleForTesting
  static final ImmutableMap<String, String> DEFAULT_WARNINGS =
      new ImmutableMap.Builder<String, String>()
          .put("GCC_WARN_64_TO_32_BIT_CONVERSION", "-Wshorten-64-to-32")
          .put("CLANG_WARN_BOOL_CONVERSION", "-Wbool-conversion")
          .put("CLANG_WARN_CONSTANT_CONVERSION", "-Wconstant-conversion")
          // Double-underscores are intentional - thanks Xcode.
          .put("CLANG_WARN__DUPLICATE_METHOD_MATCH", "-Wduplicate-method-match")
          .put("CLANG_WARN_EMPTY_BODY", "-Wempty-body")
          .put("CLANG_WARN_ENUM_CONVERSION", "-Wenum-conversion")
          .put("CLANG_WARN_INT_CONVERSION", "-Wint-conversion")
          .put("CLANG_WARN_UNREACHABLE_CODE", "-Wunreachable-code")
          .put("GCC_WARN_ABOUT_RETURN_TYPE", "-Wmismatched-return-types")
          .put("GCC_WARN_UNDECLARED_SELECTOR", "-Wundeclared-selector")
          .put("GCC_WARN_UNINITIALIZED_AUTOS", "-Wuninitialized")
          .put("GCC_WARN_UNUSED_FUNCTION", "-Wunused-function")
          .put("GCC_WARN_UNUSED_VARIABLE", "-Wunused-variable")
          .build();

  static final ImmutableList<String> DEFAULT_COMPILER_FLAGS = ImmutableList.of("-DOS_IOS");

  static final ImmutableList<String> DEFAULT_LINKER_FLAGS = ImmutableList.of("-ObjC");

  private IosSdkCommands() {
    throw new UnsupportedOperationException("static-only");
  }

  private static String getPlatformPlistName(ObjcConfiguration configuration) {
    return Platform.forArch(configuration.getIosCpu()).getNameInPlist();
  }

  public static String platformDir(ObjcConfiguration configuration) {
    return DEVELOPER_DIR + "/Platforms/" + getPlatformPlistName(configuration) + ".platform";
  }

  public static String sdkDir(ObjcConfiguration configuration) {
    return platformDir(configuration) + "/Developer/SDKs/"
        + getPlatformPlistName(configuration) + configuration.getIosSdkVersion() + ".sdk";
  }

  public static String frameworkDir(ObjcConfiguration configuration) {
    return platformDir(configuration) + "/Developer/Library/Frameworks";
  }

  /**
   * Returns swift libraries path.
   */
  public static String swiftLibDir(ObjcConfiguration configuration) {
    return DEVELOPER_DIR + "/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/"
        + swiftPlatform(configuration);
  }

  /**
   * Returns a platform name string suitable for use in Swift tools.
   */
  public static String swiftPlatform(ObjcConfiguration configuration) {
    return getPlatformPlistName(configuration).toLowerCase();
  }

  /**
   * Returns the target string for swift compiler. For example, "x86_64-apple-ios8.2"
   */
  public static String swiftTarget(ObjcConfiguration configuration) {
    return configuration.getIosCpu() + "-apple-" + "ios" + configuration.getIosSdkVersion();
  }

  private static Iterable<PathFragment> uniqueParentDirectories(Iterable<PathFragment> paths) {
    ImmutableSet.Builder<PathFragment> parents = new ImmutableSet.Builder<>();
    for (PathFragment path : paths) {
      parents.add(path.getParentDirectory());
    }
    return parents.build();
  }

  public static List<String> commonLinkAndCompileFlagsForClang(
      ObjcProvider provider, ObjcConfiguration configuration) {
    ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
    if (Platform.forArch(configuration.getIosCpu()) == Platform.SIMULATOR) {
      builder.add("-mios-simulator-version-min=" + configuration.getMinimumOs());
    } else {
      builder.add("-miphoneos-version-min=" + configuration.getMinimumOs());
    }

    if (configuration.generateDebugSymbols()) {
      builder.add("-g");
    }

    return builder
        .add("-arch", configuration.getIosCpu())
        .add("-isysroot", sdkDir(configuration))
        // TODO(bazel-team): Pass framework search paths to Xcodegen.
        .add("-F", sdkDir(configuration) + "/Developer/Library/Frameworks")
        // As of sdk8.1, XCTest is in a base Framework dir
        .add("-F", frameworkDir(configuration))
        // Add custom (non-SDK) framework search paths. For each framework foo/bar.framework,
        // include "foo" as a search path.
        .addAll(Interspersing.beforeEach(
            "-F",
            PathFragment.safePathStrings(uniqueParentDirectories(provider.get(FRAMEWORK_DIR)))))
        .build();
  }

  public static Iterable<String> compileFlagsForClang(ObjcConfiguration configuration) {
    return Iterables.concat(
        DEFAULT_WARNINGS.values(),
        platformSpecificCompileFlagsForClang(configuration),
        DEFAULT_COMPILER_FLAGS
    );
  }

  private static List<String> platformSpecificCompileFlagsForClang(
      ObjcConfiguration configuration) {
    switch (Platform.forArch(configuration.getIosCpu())) {
      case DEVICE:
        return ImmutableList.of();
      case SIMULATOR:
        // These are added by Xcode when building, because the simulator is built on OSX
        // frameworks so we aim compile to match the OSX objc runtime.
        return ImmutableList.of(
          "-fexceptions",
          "-fasm-blocks",
          "-fobjc-abi-version=2",
          "-fobjc-legacy-dispatch");
      default:
        throw new AssertionError();
    }
  }

  public static Iterable<? extends XcodeprojBuildSetting> defaultWarningsForXcode() {
    return Iterables.transform(DEFAULT_WARNINGS.keySet(),
        new Function<String, XcodeprojBuildSetting>() {
      @Override
      public XcodeprojBuildSetting apply(String key) {
        return XcodeprojBuildSetting.newBuilder().setName(key).setValue("YES").build();
      }
    });
  }
}