/* * Copyright 2015-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.log.Logger; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.Flavor; import com.facebook.buck.model.InternalFlavor; import com.facebook.buck.rules.HashedFileTool; import com.facebook.buck.rules.LazyDelegatingTool; import com.facebook.buck.rules.Tool; import com.facebook.buck.util.HumanReadableException; import com.facebook.buck.util.environment.Platform; 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 java.util.Optional; public class CxxPlatforms { private static final Logger LOG = Logger.get(CxxPlatforms.class); private static final ImmutableList<String> DEFAULT_ASFLAGS = ImmutableList.of(); private static final ImmutableList<String> DEFAULT_ASPPFLAGS = ImmutableList.of(); private static final ImmutableList<String> DEFAULT_CFLAGS = ImmutableList.of(); private static final ImmutableList<String> DEFAULT_CXXFLAGS = ImmutableList.of(); private static final ImmutableList<String> DEFAULT_CPPFLAGS = ImmutableList.of(); private static final ImmutableList<String> DEFAULT_CXXPPFLAGS = ImmutableList.of(); private static final ImmutableList<String> DEFAULT_LDFLAGS = ImmutableList.of(); private static final ImmutableList<String> DEFAULT_ARFLAGS = ImmutableList.of(); private static final ImmutableList<String> DEFAULT_RANLIBFLAGS = ImmutableList.of(); private static final ImmutableList<String> DEFAULT_COMPILER_ONLY_FLAGS = ImmutableList.of(); // Utility class, do not instantiate. private CxxPlatforms() {} private static Optional<SharedLibraryInterfaceFactory> getSharedLibraryInterfaceFactory( CxxBuckConfig config, Platform platform) { Optional<SharedLibraryInterfaceFactory> sharedLibraryInterfaceFactory = Optional.empty(); if (config.shouldUseSharedLibraryInterfaces()) { switch (platform) { case LINUX: sharedLibraryInterfaceFactory = Optional.of( ElfSharedLibraryInterfaceFactory.of(config.getToolProvider("objcopy").get())); break; // $CASES-OMITTED$ default: } } return sharedLibraryInterfaceFactory; } public static CxxPlatform build( Flavor flavor, Platform platform, final CxxBuckConfig config, CompilerProvider as, PreprocessorProvider aspp, CompilerProvider cc, CompilerProvider cxx, PreprocessorProvider cpp, PreprocessorProvider cxxpp, LinkerProvider ld, Iterable<String> ldFlags, Tool strip, final Archiver ar, final Tool ranlib, final SymbolNameTool nm, ImmutableList<String> asflags, ImmutableList<String> asppflags, ImmutableList<String> cflags, ImmutableList<String> cppflags, String sharedLibraryExtension, String sharedLibraryVersionedExtensionFormat, String staticLibraryExtension, String objectFileExtension, DebugPathSanitizer compilerDebugPathSanitizer, DebugPathSanitizer assemblerDebugPathSanitizer, ImmutableMap<String, String> flagMacros, Optional<String> binaryExtension, HeaderVerification headerVerification) { // TODO(beng, agallagher): Generalize this so we don't need all these setters. CxxPlatform.Builder builder = CxxPlatform.builder(); final Archiver arDelegate = ar instanceof LazyDelegatingArchiver ? ((LazyDelegatingArchiver) ar).getDelegate() : ar; builder .setFlavor(flavor) .setAs(config.getCompilerProvider("as").orElse(as)) .setAspp(config.getPreprocessorProvider("aspp").orElse(aspp)) .setCc(config.getCompilerProvider("cc").orElse(cc)) .setCxx(config.getCompilerProvider("cxx").orElse(cxx)) .setCpp(config.getPreprocessorProvider("cpp").orElse(cpp)) .setCxxpp(config.getPreprocessorProvider("cxxpp").orElse(cxxpp)) .setCuda(config.getCompilerProvider("cuda")) .setCudapp(config.getPreprocessorProvider("cudapp")) .setAsm(config.getCompilerProvider("asm")) .setAsmpp(config.getPreprocessorProvider("asmpp")) .setLd(config.getLinkerProvider("ld", ld.getType()).orElse(ld)) .addAllLdflags(ldFlags) .setAr( new LazyDelegatingArchiver( () -> getTool("ar", config) .map(getArchiver(arDelegate.getClass(), config)::apply) .orElse(arDelegate))) .setRanlib(new LazyDelegatingTool(() -> getTool("ranlib", config).orElse(ranlib))) .setStrip(getTool("strip", config).orElse(strip)) .setSharedLibraryExtension(sharedLibraryExtension) .setSharedLibraryVersionedExtensionFormat(sharedLibraryVersionedExtensionFormat) .setStaticLibraryExtension(staticLibraryExtension) .setObjectFileExtension(objectFileExtension) .setCompilerDebugPathSanitizer(compilerDebugPathSanitizer) .setAssemblerDebugPathSanitizer(assemblerDebugPathSanitizer) .setFlagMacros(flagMacros) .setBinaryExtension(binaryExtension) .setHeaderVerification(headerVerification) .setPublicHeadersSymlinksEnabled(config.getPublicHeadersSymlinksEnabled()) .setPrivateHeadersSymlinksEnabled(config.getPrivateHeadersSymlinksEnabled()); builder.setSymbolNameTool( new LazyDelegatingSymbolNameTool( () -> { Optional<Tool> configNm = getTool("nm", config); if (configNm.isPresent()) { return new PosixNmSymbolNameTool(configNm.get()); } else { return nm; } })); builder.setSharedLibraryInterfaceFactory(getSharedLibraryInterfaceFactory(config, platform)); builder.addAllCflags(cflags); builder.addAllCxxflags(cflags); builder.addAllCppflags(cppflags); builder.addAllCxxppflags(cppflags); builder.addAllAsflags(asflags); builder.addAllAsppflags(asppflags); CxxPlatforms.addToolFlagsFromConfig(config, builder); return builder.build(); } /** * Creates a CxxPlatform with a defined flavor for a CxxBuckConfig with default values provided * from another default CxxPlatform */ public static CxxPlatform copyPlatformWithFlavorAndConfig( CxxPlatform defaultPlatform, Platform platform, CxxBuckConfig config, Flavor flavor) { return CxxPlatforms.build( flavor, platform, config, defaultPlatform.getAs(), defaultPlatform.getAspp(), defaultPlatform.getCc(), defaultPlatform.getCxx(), defaultPlatform.getCpp(), defaultPlatform.getCxxpp(), defaultPlatform.getLd(), defaultPlatform.getLdflags(), defaultPlatform.getStrip(), defaultPlatform.getAr(), defaultPlatform.getRanlib(), defaultPlatform.getSymbolNameTool(), defaultPlatform.getAsflags(), defaultPlatform.getAsppflags(), defaultPlatform.getCflags(), defaultPlatform.getCppflags(), defaultPlatform.getSharedLibraryExtension(), defaultPlatform.getSharedLibraryVersionedExtensionFormat(), defaultPlatform.getStaticLibraryExtension(), defaultPlatform.getObjectFileExtension(), defaultPlatform.getCompilerDebugPathSanitizer(), defaultPlatform.getAssemblerDebugPathSanitizer(), defaultPlatform.getFlagMacros(), defaultPlatform.getBinaryExtension(), defaultPlatform.getHeaderVerification()); } private static Function<Tool, Archiver> getArchiver( final Class<? extends Archiver> arClass, final CxxBuckConfig config) { return input -> { try { return config .getArchiver(input) .orElse(arClass.getConstructor(Tool.class).newInstance(input)); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } }; } private static ImmutableMap<String, Flavor> getHostFlavorMap() { // TODO(coneko): base the host flavor on architecture, too. return ImmutableMap.<String, Flavor>builder() .put(Platform.LINUX.getAutoconfName(), InternalFlavor.of("linux-x86_64")) .put(Platform.MACOS.getAutoconfName(), InternalFlavor.of("macosx-x86_64")) .put(Platform.WINDOWS.getAutoconfName(), InternalFlavor.of("windows-x86_64")) .put(Platform.FREEBSD.getAutoconfName(), InternalFlavor.of("freebsd-x86_64")) .build(); } public static ImmutableSet<Flavor> getAllPossibleHostFlavors() { return ImmutableSet.copyOf(getHostFlavorMap().values()); } public static Flavor getHostFlavor() { String platformName = Platform.detect().getAutoconfName(); Flavor hostFlavor = getHostFlavorMap().get(platformName); if (hostFlavor == null) { throw new HumanReadableException("Unable to determine the host platform."); } return hostFlavor; } public static void addToolFlagsFromConfig(CxxBuckConfig config, CxxPlatform.Builder builder) { ImmutableList<String> asflags = config.getFlags("asflags").orElse(DEFAULT_ASFLAGS); ImmutableList<String> cflags = config.getFlags("cflags").orElse(DEFAULT_CFLAGS); ImmutableList<String> cxxflags = config.getFlags("cxxflags").orElse(DEFAULT_CXXFLAGS); ImmutableList<String> compilerOnlyFlags = config.getFlags("compiler_only_flags").orElse(DEFAULT_COMPILER_ONLY_FLAGS); builder .addAllAsflags(asflags) .addAllAsppflags(config.getFlags("asppflags").orElse(DEFAULT_ASPPFLAGS)) .addAllCflags(cflags) .addAllCflags(compilerOnlyFlags) .addAllCxxflags(cxxflags) .addAllCxxflags(compilerOnlyFlags) .addAllCppflags(config.getFlags("cppflags").orElse(DEFAULT_CPPFLAGS)) .addAllCxxppflags(config.getFlags("cxxppflags").orElse(DEFAULT_CXXPPFLAGS)) .addAllCudaflags(config.getFlags("cudaflags").orElse(ImmutableList.of())) .addAllCudappflags(config.getFlags("cudappflags").orElse(ImmutableList.of())) .addAllAsmflags(config.getFlags("asmflags").orElse(ImmutableList.of())) .addAllAsmppflags(config.getFlags("asmppflags").orElse(ImmutableList.of())) .addAllLdflags(config.getFlags("ldflags").orElse(DEFAULT_LDFLAGS)) .addAllArflags(config.getFlags("arflags").orElse(DEFAULT_ARFLAGS)) .addAllRanlibflags(config.getFlags("ranlibflags").orElse(DEFAULT_RANLIBFLAGS)); } public static CxxPlatform getConfigDefaultCxxPlatform( CxxBuckConfig cxxBuckConfig, ImmutableMap<Flavor, CxxPlatform> cxxPlatformsMap, CxxPlatform systemDefaultCxxPlatform) { CxxPlatform defaultCxxPlatform; Optional<String> defaultPlatform = cxxBuckConfig.getDefaultPlatform(); if (defaultPlatform.isPresent()) { defaultCxxPlatform = cxxPlatformsMap.get(InternalFlavor.of(defaultPlatform.get())); if (defaultCxxPlatform == null) { LOG.warn( "Couldn't find default platform %s, falling back to system default", defaultPlatform.get()); } else { LOG.debug("Using config default C++ platform %s", defaultCxxPlatform); return defaultCxxPlatform; } } else { LOG.debug("Using system default C++ platform %s", systemDefaultCxxPlatform); } return systemDefaultCxxPlatform; } private static Optional<Tool> getTool(String name, CxxBuckConfig config) { return config.getPath(name).map(HashedFileTool::new); } public static Iterable<BuildTarget> getParseTimeDeps(CxxPlatform cxxPlatform) { ImmutableList.Builder<BuildTarget> deps = ImmutableList.builder(); deps.addAll(cxxPlatform.getAspp().getParseTimeDeps()); deps.addAll(cxxPlatform.getAs().getParseTimeDeps()); deps.addAll(cxxPlatform.getCpp().getParseTimeDeps()); deps.addAll(cxxPlatform.getCc().getParseTimeDeps()); deps.addAll(cxxPlatform.getCxxpp().getParseTimeDeps()); deps.addAll(cxxPlatform.getCxx().getParseTimeDeps()); if (cxxPlatform.getCudapp().isPresent()) { deps.addAll(cxxPlatform.getCudapp().get().getParseTimeDeps()); } if (cxxPlatform.getCuda().isPresent()) { deps.addAll(cxxPlatform.getCuda().get().getParseTimeDeps()); } if (cxxPlatform.getAsmpp().isPresent()) { deps.addAll(cxxPlatform.getAsmpp().get().getParseTimeDeps()); } if (cxxPlatform.getAsm().isPresent()) { deps.addAll(cxxPlatform.getAsm().get().getParseTimeDeps()); } deps.addAll(cxxPlatform.getLd().getParseTimeDeps()); cxxPlatform .getSharedLibraryInterfaceFactory() .ifPresent(f -> deps.addAll(f.getParseTimeDeps())); return deps.build(); } public static Iterable<BuildTarget> getParseTimeDeps(Iterable<CxxPlatform> cxxPlatforms) { ImmutableList.Builder<BuildTarget> deps = ImmutableList.builder(); for (CxxPlatform cxxPlatform : cxxPlatforms) { deps.addAll(getParseTimeDeps(cxxPlatform)); } return deps.build(); } }