blob: f22349841961d34fc8ad19c3d987b0056da8de92 [file] [log] [blame]
/*
* Copyright 2014-present Facebook, Inc.
*
* 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.facebook.buck.cxx;
import com.facebook.buck.cli.BuckConfig;
import com.facebook.buck.model.Flavor;
import com.facebook.buck.model.ImmutableFlavor;
import com.facebook.buck.util.HumanReadableException;
import com.facebook.buck.util.environment.Platform;
import com.google.common.base.Optional;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Utility class to create a C/C++ platform described in the "cxx"
* section of .buckconfig, with reasonable system defaults.
*/
public class DefaultCxxPlatforms {
// Utility class, do not instantiate.
private DefaultCxxPlatforms() { }
private static enum LinkerType {
DARWIN,
GNU,
WINDOWS,
}
private static final Flavor FLAVOR = ImmutableFlavor.of("default");
private static final Path DEFAULT_AS = Paths.get("/usr/bin/as");
private static final ImmutableList<String> DEFAULT_ASFLAGS = ImmutableList.of();
private static final Path DEFAULT_ASPP = Paths.get("/usr/bin/gcc");
private static final ImmutableList<String> DEFAULT_ASPPFLAGS = ImmutableList.of();
private static final Path DEFAULT_CC = Paths.get("/usr/bin/gcc");
private static final ImmutableList<String> DEFAULT_CFLAGS = ImmutableList.of();
private static final Path DEFAULT_CXX = Paths.get("/usr/bin/g++");
private static final ImmutableList<String> DEFAULT_CXXFLAGS = ImmutableList.of();
private static final Path DEFAULT_CPP = Paths.get("/usr/bin/gcc");
private static final ImmutableList<String> DEFAULT_CPPFLAGS = ImmutableList.of();
private static final Path DEFAULT_CXXPP = Paths.get("/usr/bin/g++");
private static final ImmutableList<String> DEFAULT_CXXPPFLAGS = ImmutableList.of();
private static final Path DEFAULT_CXXLD = Paths.get("/usr/bin/g++");
private static final ImmutableList<String> DEFAULT_CXXLDFLAGS = ImmutableList.of();
private static final Path DEFAULT_LD = Paths.get("/usr/bin/ld");
private static final ImmutableList<String> DEFAULT_LDFLAGS = ImmutableList.of();
private static final Path DEFAULT_AR = Paths.get("/usr/bin/ar");
private static final ImmutableList<String> DEFAULT_ARFLAGS = ImmutableList.of();
private static final Path DEFAULT_LEX = Paths.get("/usr/bin/flex");
private static final ImmutableList<String> DEFAULT_LEX_FLAGS = ImmutableList.of();
private static final Path DEFAULT_YACC = Paths.get("/usr/bin/bison");
private static final ImmutableList<String> DEFAULT_YACC_FLAGS = ImmutableList.of("-y");
private static final Optional<DebugPathSanitizer> DEBUG_PATH_SANITIZER =
Optional.of(
new DebugPathSanitizer(
250,
File.separatorChar,
Paths.get("."),
ImmutableBiMap.<Path, Path>of()));
public static CxxPlatform build(BuckConfig delegate) {
return build(Platform.detect(), delegate);
}
public static CxxPlatform build(
Platform platform,
BuckConfig delegate) {
ImmutableCxxPlatform.Builder builder = ImmutableCxxPlatform.builder();
// TODO(user, agallagher): Generalize this so we don't need all these setters.
builder
.setFlavor(FLAVOR)
.setAs(getTool("cxx", "as", DEFAULT_AS, delegate))
.setAspp(getTool("cxx", "aspp", DEFAULT_ASPP, delegate))
.setCc(getTool("cxx", "cc", DEFAULT_CC, delegate))
.setCxx(getTool("cxx", "cxx", DEFAULT_CXX, delegate))
.setCpp(getTool("cxx", "cpp", DEFAULT_CPP, delegate))
.setCxxpp(getTool("cxx", "cxxpp", DEFAULT_CXXPP, delegate))
.setCxxld(getTool("cxx", "cxxld", DEFAULT_CXXLD, delegate))
.setLd(getLd(platform, delegate))
.setAr(getTool("cxx", "ar", DEFAULT_AR, delegate))
.setLex(getToolPath("cxx", "lex", DEFAULT_LEX, delegate))
.setYacc(getToolPath("cxx", "yacc", DEFAULT_YACC, delegate))
.setSharedLibraryExtension(getSharedLibraryExtension(platform))
.setDebugPathSanitizer(DEBUG_PATH_SANITIZER);
addToolFlagsFromConfig(delegate, builder);
return builder.build();
}
public static void addToolFlagsFromConfig(
BuckConfig delegate,
ImmutableCxxPlatform.Builder builder) {
ImmutableList<String> asflags = getFlags("cxx", "asflags", DEFAULT_ASFLAGS, delegate);
ImmutableList<String> cflags = getFlags("cxx", "cflags", DEFAULT_CFLAGS, delegate);
ImmutableList<String> cxxflags = getFlags("cxx", "cxxflags", DEFAULT_CXXFLAGS, delegate);
builder
.addAllAsflags(asflags)
.addAllAsppflags(getFlags("cxx", "asppflags", DEFAULT_ASPPFLAGS, delegate))
.addAllAsppflags(asflags)
.addAllCflags(cflags)
.addAllCxxflags(cxxflags)
.addAllCppflags(getFlags("cxx", "cppflags", DEFAULT_CPPFLAGS, delegate))
.addAllCppflags(cflags)
.addAllCxxppflags(getFlags("cxx", "cxxppflags", DEFAULT_CXXPPFLAGS, delegate))
.addAllCxxppflags(cxxflags)
.addAllCxxldflags(getFlags("cxx", "cxxldflags", DEFAULT_CXXLDFLAGS, delegate))
.addAllLdflags(getFlags("cxx", "ldflags", DEFAULT_LDFLAGS, delegate))
.addAllArflags(getFlags("cxx", "arflags", DEFAULT_ARFLAGS, delegate))
.addAllLexFlags(getFlags("cxx", "lexflags", DEFAULT_LEX_FLAGS, delegate))
.addAllYaccFlags(getFlags("cxx", "yaccflags", DEFAULT_YACC_FLAGS, delegate));
}
private static ImmutableList<String> getFlags(
String section,
String field,
ImmutableList<String> def,
BuckConfig delegate) {
Optional<String> value = delegate.getValue(section, field);
if (!value.isPresent()) {
return def;
}
ImmutableList.Builder<String> split = ImmutableList.builder();
if (!value.get().trim().isEmpty()) {
split.addAll(Splitter.on(" ").split(value.get().trim()));
}
return split.build();
}
private static Path getToolPath(
String section,
String field,
Path def,
BuckConfig delegate) {
return delegate.getPath(section, field).or(def);
}
private static Tool getTool(
String section,
String field,
Path def,
BuckConfig delegate) {
return new HashedFileTool(getToolPath(section, field, def, delegate));
}
private static LinkerType getLinkerTypeForPlatform(Platform platform) {
switch (platform) {
case LINUX:
return LinkerType.GNU;
case MACOS:
return LinkerType.DARWIN;
case WINDOWS:
return LinkerType.WINDOWS;
//$CASES-OMITTED$
default:
throw new HumanReadableException(
"cannot detect linker type, try explicitly setting it in " +
".buckconfig's [cxx] ld_type section");
}
}
private static LinkerType getLinkerType(Platform platform, BuckConfig delegate) {
Optional<LinkerType> type = delegate.getEnum("cxx", "ld_type", LinkerType.class);
return type.or(getLinkerTypeForPlatform(platform));
}
private static Linker getLd(
Platform platform,
BuckConfig delegate) {
Tool tool = new HashedFileTool(
getToolPath("cxx", "ld", DEFAULT_LD, delegate));
LinkerType type = getLinkerType(platform, delegate);
switch (type) {
case GNU:
return new GnuLinker(tool);
case DARWIN:
return new DarwinLinker(tool);
case WINDOWS:
return new WindowsLinker(tool);
// Add a "default" case, even thought we've handled all cases above, just to make the
// compiler happy.
default:
throw new IllegalStateException();
}
}
private static String getSharedLibraryExtension(Platform platform) {
switch (platform) {
case MACOS:
return "dylib";
case WINDOWS:
return "dll";
// $CASES-OMITTED$
default:
return "so";
}
}
}