// 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 IBTOOL_PATH = DEVELOPER_DIR + "/usr/bin/ibtool"; 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 DEFAULT_WARNINGS = new ImmutableMap.Builder() .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 DEFAULT_COMPILER_FLAGS = ImmutableList.of("-DOS_IOS"); static final ImmutableList 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(); } private 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"; } private static Iterable uniqueParentDirectories(Iterable paths) { ImmutableSet.Builder parents = new ImmutableSet.Builder<>(); for (PathFragment path : paths) { parents.add(path.getParentDirectory()); } return parents.build(); } public static List commonLinkAndCompileFlagsForClang( ObjcProvider provider, ObjcConfiguration configuration) { ImmutableList.Builder 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 compileFlagsForClang(ObjcConfiguration configuration) { return Iterables.concat( DEFAULT_WARNINGS.values(), platformSpecificCompileFlagsForClang(configuration), DEFAULT_COMPILER_FLAGS ); } private static List 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 defaultWarningsForXcode() { return Iterables.transform(DEFAULT_WARNINGS.keySet(), new Function() { @Override public XcodeprojBuildSetting apply(String key) { return XcodeprojBuildSetting.newBuilder().setName(key).setValue("YES").build(); } }); } }