/* * 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.io.ExecutableFinder; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.model.Flavor; import com.facebook.buck.model.InternalFlavor; import com.facebook.buck.rules.ConstantToolProvider; import com.facebook.buck.rules.HashedFileTool; import com.facebook.buck.util.environment.Platform; import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Optional; /** * 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() {} public static final Flavor FLAVOR = InternalFlavor.of("default"); private static final Path DEFAULT_C_FRONTEND = Paths.get("/usr/bin/gcc"); private static final Path DEFAULT_CXX_FRONTEND = Paths.get("/usr/bin/g++"); private static final Path DEFAULT_AR = Paths.get("/usr/bin/ar"); private static final Path DEFAULT_STRIP = Paths.get("/usr/bin/strip"); private static final Path DEFAULT_RANLIB = Paths.get("/usr/bin/ranlib"); private static final Path DEFAULT_NM = Paths.get("/usr/bin/nm"); private static final Path DEFAULT_OSX_C_FRONTEND = Paths.get("/usr/bin/clang"); private static final Path DEFAULT_OSX_CXX_FRONTEND = Paths.get("/usr/bin/clang++"); private static final String DEFAULT_WINDOWS_CXX_FRONTEND = "cl"; private static final String DEFAULT_WINDOWS_LINK = "link"; private static final String DEFAULT_WINDOWS_LIB = "lib"; public static CxxPlatform build( Platform platform, ProjectFilesystem filesystem, CxxBuckConfig config) { String sharedLibraryExtension; String sharedLibraryVersionedExtensionFormat; String staticLibraryExtension; String objectFileExtension; Path defaultCFrontend; Path defaultCxxFrontend; Path defaultLinker; LinkerProvider.Type linkerType; Archiver archiver; DebugPathSanitizer compilerSanitizer; Optional<String> binaryExtension; ImmutableMap<String, String> env = config.getEnvironment(); Optional<CxxToolProvider.Type> defaultToolType = Optional.empty(); switch (platform) { case LINUX: sharedLibraryExtension = "so"; sharedLibraryVersionedExtensionFormat = "so.%s"; staticLibraryExtension = "a"; objectFileExtension = "o"; defaultCFrontend = getExecutablePath("gcc", DEFAULT_C_FRONTEND, env); defaultCxxFrontend = getExecutablePath("g++", DEFAULT_CXX_FRONTEND, env); defaultLinker = defaultCxxFrontend; linkerType = LinkerProvider.Type.GNU; archiver = new GnuArchiver(new HashedFileTool(getExecutablePath("ar", DEFAULT_AR, env))); compilerSanitizer = new PrefixMapDebugPathSanitizer( config.getDebugPathSanitizerLimit(), File.separatorChar, Paths.get("."), ImmutableBiMap.of(), filesystem.getRootPath().toAbsolutePath(), CxxToolProvider.Type.GCC, filesystem); binaryExtension = Optional.empty(); break; case MACOS: sharedLibraryExtension = "dylib"; sharedLibraryVersionedExtensionFormat = ".%s.dylib"; staticLibraryExtension = "a"; objectFileExtension = "o"; defaultCFrontend = getExecutablePath("clang", DEFAULT_OSX_C_FRONTEND, env); defaultCxxFrontend = getExecutablePath("clang++", DEFAULT_OSX_CXX_FRONTEND, env); defaultLinker = defaultCxxFrontend; linkerType = LinkerProvider.Type.DARWIN; archiver = new BsdArchiver(new HashedFileTool(getExecutablePath("ar", DEFAULT_AR, env))); compilerSanitizer = new PrefixMapDebugPathSanitizer( config.getDebugPathSanitizerLimit(), File.separatorChar, Paths.get("."), ImmutableBiMap.of(), filesystem.getRootPath().toAbsolutePath(), CxxToolProvider.Type.CLANG, filesystem); binaryExtension = Optional.empty(); break; case WINDOWS: sharedLibraryExtension = "dll"; sharedLibraryVersionedExtensionFormat = "dll"; staticLibraryExtension = "lib"; objectFileExtension = "obj"; defaultCFrontend = getExecutablePath( DEFAULT_WINDOWS_CXX_FRONTEND, Paths.get(DEFAULT_WINDOWS_CXX_FRONTEND), env); defaultCxxFrontend = getExecutablePath( DEFAULT_WINDOWS_CXX_FRONTEND, Paths.get(DEFAULT_WINDOWS_CXX_FRONTEND), env); defaultLinker = getExecutablePath(DEFAULT_WINDOWS_LINK, Paths.get(DEFAULT_WINDOWS_LINK), env); linkerType = LinkerProvider.Type.WINDOWS; archiver = new WindowsArchiver( new HashedFileTool( getExecutablePath(DEFAULT_WINDOWS_LIB, Paths.get(DEFAULT_WINDOWS_LIB), env))); compilerSanitizer = new PrefixMapDebugPathSanitizer( config.getDebugPathSanitizerLimit(), File.separatorChar, Paths.get("."), ImmutableBiMap.of(), filesystem.getRootPath().toAbsolutePath(), CxxToolProvider.Type.GCC, filesystem); binaryExtension = Optional.of("exe"); defaultToolType = Optional.of(CxxToolProvider.Type.WINDOWS); break; case FREEBSD: sharedLibraryExtension = "so"; sharedLibraryVersionedExtensionFormat = "so.%s"; staticLibraryExtension = "a"; objectFileExtension = "o"; defaultCFrontend = getExecutablePath("gcc", DEFAULT_C_FRONTEND, env); defaultCxxFrontend = getExecutablePath("g++", DEFAULT_CXX_FRONTEND, env); defaultLinker = defaultCxxFrontend; linkerType = LinkerProvider.Type.GNU; archiver = new BsdArchiver(new HashedFileTool(getExecutablePath("ar", DEFAULT_AR, env))); compilerSanitizer = new PrefixMapDebugPathSanitizer( config.getDebugPathSanitizerLimit(), File.separatorChar, Paths.get("."), ImmutableBiMap.of(), filesystem.getRootPath().toAbsolutePath(), CxxToolProvider.Type.GCC, filesystem); binaryExtension = Optional.empty(); break; //$CASES-OMITTED$ default: throw new RuntimeException(String.format("Unsupported platform: %s", platform)); } PreprocessorProvider aspp = new PreprocessorProvider(defaultCFrontend, defaultToolType); CompilerProvider as = new CompilerProvider(defaultCFrontend, defaultToolType); PreprocessorProvider cpp = new PreprocessorProvider(defaultCFrontend, defaultToolType); CompilerProvider cc = new CompilerProvider(defaultCFrontend, defaultToolType); PreprocessorProvider cxxpp = new PreprocessorProvider(defaultCxxFrontend, defaultToolType); CompilerProvider cxx = new CompilerProvider(defaultCxxFrontend, defaultToolType); return CxxPlatforms.build( FLAVOR, platform, config, as, aspp, cc, cxx, cpp, cxxpp, new DefaultLinkerProvider( linkerType, new ConstantToolProvider(new HashedFileTool(defaultLinker))), ImmutableList.of(), new HashedFileTool(getExecutablePath("strip", DEFAULT_STRIP, env)), archiver, new HashedFileTool(getExecutablePath("ranlib", DEFAULT_RANLIB, env)), new PosixNmSymbolNameTool(new HashedFileTool(getExecutablePath("nm", DEFAULT_NM, env))), ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), sharedLibraryExtension, sharedLibraryVersionedExtensionFormat, staticLibraryExtension, objectFileExtension, compilerSanitizer, new MungingDebugPathSanitizer( config.getDebugPathSanitizerLimit(), File.separatorChar, Paths.get("."), ImmutableBiMap.of()), ImmutableMap.of(), binaryExtension, config.getHeaderVerification()); } private static Path getExecutablePath( String executableName, Path unresolvedLocation, ImmutableMap<String, String> env) { return new ExecutableFinder() .getOptionalExecutable(Paths.get(executableName), env) .orElse(unresolvedLocation); } }