diff --git a/clang/lib/Driver/ToolChains/WebAssembly.h b/clang/lib/Driver/ToolChains/WebAssembly.h --- a/clang/lib/Driver/ToolChains/WebAssembly.h +++ b/clang/lib/Driver/ToolChains/WebAssembly.h @@ -70,11 +70,20 @@ const char *getDefaultLinker() const override { return "wasm-ld"; } + CXXStdlibType GetDefaultCXXStdlibType() const override { + return ToolChain::CST_Libcxx; + } + Tool *buildLinker() const override; std::string getMultiarchTriple(const Driver &D, const llvm::Triple &TargetTriple, StringRef SysRoot) const override; + + void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + void addLibStdCXXIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -8,15 +8,17 @@ #include "WebAssembly.h" #include "CommonArgs.h" +#include "Gnu.h" #include "clang/Basic/Version.h" #include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" -#include "llvm/Option/ArgList.h" +#include "llvm/Support/VirtualFileSystem.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -371,7 +373,11 @@ WebAssembly::GetCXXStdlibType(const ArgList &Args) const { if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { StringRef Value = A->getValue(); - if (Value != "libc++") + if (Value == "libc++") + return ToolChain::CST_Libcxx; + else if (Value == "libstdc++") + return ToolChain::CST_Libstdcxx; + else getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); } @@ -417,17 +423,20 @@ void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (!DriverArgs.hasArg(options::OPT_nostdlibinc) && - !DriverArgs.hasArg(options::OPT_nostdincxx)) { - if (getTriple().getOS() != llvm::Triple::UnknownOS) { - const std::string MultiarchTriple = - getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/include/" + MultiarchTriple + - "/c++/v1"); - } - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/include/c++/v1"); + + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: + addLibCxxIncludePaths(DriverArgs, CC1Args); + break; + case ToolChain::CST_Libstdcxx: + addLibStdCXXIncludePaths(DriverArgs, CC1Args); + break; + default: + llvm_unreachable("Unknown stdlib type"); } } @@ -440,6 +449,9 @@ CmdArgs.push_back("-lc++abi"); break; case ToolChain::CST_Libstdcxx: + CmdArgs.push_back("-lstdc++"); + break; + default: llvm_unreachable("invalid stdlib name"); } } @@ -455,3 +467,75 @@ Tool *WebAssembly::buildLinker() const { return new tools::wasm::Linker(*this); } + +void WebAssembly::addLibCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + std::string SysRoot = computeSysRoot(); + std::string LibPath = SysRoot + "/include"; + const std::string MultiarchTriple = + getMultiarchTriple(D, getTriple(), SysRoot); + bool IsKnownOs = (getTriple().getOS() != llvm::Triple::UnknownOS); + + std::string Version = detectLibcxxVersion(LibPath); + if (Version.empty()) + return; + + // First add the per-target include path if the OS is known. + if (IsKnownOs) { + std::string TargetDir = LibPath + "/" + MultiarchTriple + "/c++/" + Version; + addSystemInclude(DriverArgs, CC1Args, TargetDir); + } + + // Second add the generic one. + addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version); +} + +void WebAssembly::addLibStdCXXIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + // We cannot use GCCInstallationDetector here as the sysroot usually does + // not contain a full GCC installation. + // Instead, we search the given sysroot for /usr/include/xx, similar + // to how we do it for libc++. + const Driver &D = getDriver(); + std::string SysRoot = computeSysRoot(); + std::string LibPath = SysRoot + "/include"; + const std::string MultiarchTriple = + getMultiarchTriple(D, getTriple(), SysRoot); + bool IsKnownOs = (getTriple().getOS() != llvm::Triple::UnknownOS); + + // This is similar to detectLibcxxVersion() + std::string Version = ""; + { + std::error_code EC; + Generic_GCC::GCCVersion MaxVersion = + Generic_GCC::GCCVersion::Parse("0.0.0"); + SmallString<128> Path(LibPath); + llvm::sys::path::append(Path, "c++"); + for (llvm::vfs::directory_iterator LI = getVFS().dir_begin(Path, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + if (VersionText[0] != 'v') { + auto Version = Generic_GCC::GCCVersion::Parse(VersionText); + if (Version > MaxVersion) + MaxVersion = Version; + } + } + if (MaxVersion.Major > 0) + Version = MaxVersion.Text; + } + + if (Version.empty()) + return; + + // First add the per-target include path if the OS is known. + if (IsKnownOs) { + std::string TargetDir = LibPath + "/" + MultiarchTriple + "/c++/" + Version; + addSystemInclude(DriverArgs, CC1Args, TargetDir); + } + + // Second add the generic one. + addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version); +} diff --git a/clang/test/Driver/wasm-toolchain.cpp b/clang/test/Driver/wasm-toolchain.cpp --- a/clang/test/Driver/wasm-toolchain.cpp +++ b/clang/test/Driver/wasm-toolchain.cpp @@ -19,6 +19,11 @@ // LINK: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" // LINK: wasm-ld{{.*}}" "-L/foo/lib" "crt1.o" "[[temp]]" "-lc++" "-lc++abi" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out" +// RUN: %clangxx -### -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo --stdlib=libstdc++ %s 2>&1 \ +// RUN: | FileCheck -check-prefix=LINK_STDCXX %s +// LINK_STDCXX: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" +// LINK_STDCXX: wasm-ld{{.*}}" "-L/foo/lib" "crt1.o" "[[temp]]" "-lstdc++" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out" + // A basic C++ link command-line with optimization with unknown OS. // RUN: %clangxx -### -O2 -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo %s --stdlib=libc++ 2>&1 \ @@ -26,6 +31,11 @@ // LINK_OPT: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" // LINK_OPT: wasm-ld{{.*}}" "-L/foo/lib" "crt1.o" "[[temp]]" "-lc++" "-lc++abi" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out" +// RUN: %clangxx -### -O2 -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo %s --stdlib=libstdc++ 2>&1 \ +// RUN: | FileCheck -check-prefix=LINK_OPT_STDCXX %s +// LINK_OPT_STDCXX: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" +// LINK_OPT_STDCXX: wasm-ld{{.*}}" "-L/foo/lib" "crt1.o" "[[temp]]" "-lstdc++" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out" + // A basic C++ link command-line with known OS. // RUN: %clangxx -### -no-canonical-prefixes -target wasm32-wasi --sysroot=/foo --stdlib=libc++ %s 2>&1 \ @@ -33,6 +43,11 @@ // LINK_KNOWN: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" // LINK_KNOWN: wasm-ld{{.*}}" "-L/foo/lib/wasm32-wasi" "crt1.o" "[[temp]]" "-lc++" "-lc++abi" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out" +// RUN: %clangxx -### -no-canonical-prefixes -target wasm32-wasi --sysroot=/foo --stdlib=libstdc++ %s 2>&1 \ +// RUN: | FileCheck -check-prefix=LINK_KNOWN_STDCXX %s +// LINK_KNOWN_STDCXX: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" +// LINK_KNOWN_STDCXX: wasm-ld{{.*}}" "-L/foo/lib/wasm32-wasi" "crt1.o" "[[temp]]" "-lstdc++" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out" + // A basic C++ link command-line with optimization with known OS. // RUN: %clangxx -### -O2 -no-canonical-prefixes -target wasm32-wasi --sysroot=/foo %s --stdlib=libc++ 2>&1 \ @@ -40,15 +55,33 @@ // LINK_OPT_KNOWN: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" // LINK_OPT_KNOWN: wasm-ld{{.*}}" "-L/foo/lib/wasm32-wasi" "crt1.o" "[[temp]]" "-lc++" "-lc++abi" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out" +// RUN: %clangxx -### -O2 -no-canonical-prefixes -target wasm32-wasi --sysroot=/foo %s --stdlib=libstdc++ 2>&1 \ +// RUN: | FileCheck -check-prefix=LINK_OPT_KNOWN_STDCXX %s +// LINK_OPT_KNOWN_STDCXX: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" +// LINK_OPT_KNOWN_STDCXX: wasm-ld{{.*}}" "-L/foo/lib/wasm32-wasi" "crt1.o" "[[temp]]" "-lstdc++" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out" + // A basic C++ compile command-line with known OS. -// RUN: %clangxx -### -no-canonical-prefixes -target wasm32-wasi --sysroot=/foo --stdlib=libc++ %s 2>&1 \ +// RUN: %clangxx -### -no-canonical-prefixes -target wasm32-wasi --stdlib=libc++ %s 2>&1 \ +// RUN: --sysroot=%S/Inputs/basic_linux_libcxx_tree/usr \ // RUN: | FileCheck -check-prefix=COMPILE %s // COMPILE: clang{{.*}}" "-cc1" // COMPILE: "-resource-dir" "[[RESOURCE_DIR:[^"]*]]" -// COMPILE: "-isysroot" "/foo" -// COMPILE: "-internal-isystem" "/foo/include/wasm32-wasi/c++/v1" -// COMPILE: "-internal-isystem" "/foo/include/c++/v1" +// COMPILE: "-isysroot" "[[SYSROOT:[^"]+]]" +// COMPILE: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/wasm32-wasi/c++/v1" +// COMPILE: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/c++/v1" // COMPILE: "-internal-isystem" "[[RESOURCE_DIR]]{{(/|\\\\)}}include" -// COMPILE: "-internal-isystem" "/foo/include/wasm32-wasi" -// COMPILE: "-internal-isystem" "/foo/include" +// COMPILE: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/wasm32-wasi" +// COMPILE: "-internal-isystem" "[[SYSROOT:[^"]+]]/include" + +// RUN: %clangxx -### -no-canonical-prefixes -target wasm32-wasi --stdlib=libstdc++ %s 2>&1 \ +// RUN: --sysroot=%S/Inputs/basic_linux_libstdcxx_libcxxv2_tree/usr \ +// RUN: | FileCheck -check-prefix=COMPILE_STDCXX %s +// COMPILE_STDCXX: clang{{.*}}" "-cc1" +// COMPILE_STDCXX: "-resource-dir" "[[RESOURCE_DIR:[^"]*]]" +// COMPILE_STDCXX: "-isysroot" "[[SYSROOT:[^"]+]]" +// COMPILE_STDCXX: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/wasm32-wasi/c++/4.8" +// COMPILE_STDCXX: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/c++/4.8" +// COMPILE_STDCXX: "-internal-isystem" "[[RESOURCE_DIR]]{{(/|\\\\)}}include" +// COMPILE_STDCXX: "-internal-isystem" "[[SYSROOT:[^"]+]]/include/wasm32-wasi" +// COMPILE_STDCXX: "-internal-isystem" "[[SYSROOT:[^"]+]]/include"