Index: clang/lib/Driver/ToolChains/WebAssembly.h =================================================================== --- clang/lib/Driver/ToolChains/WebAssembly.h +++ 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 Index: clang/lib/Driver/ToolChains/WebAssembly.cpp =================================================================== --- clang/lib/Driver/ToolChains/WebAssembly.cpp +++ clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -14,9 +14,10 @@ #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 +372,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 +422,30 @@ 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); + + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + bool IsKnownOs = (getTriple().getOS() != llvm::Triple::UnknownOS); + const std::string MultiarchTriple = + getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: + addLibCxxIncludePaths(DriverArgs, CC1Args); + break; + case ToolChain::CST_Libstdcxx: + addLibStdCXXIncludePaths(DriverArgs, CC1Args); + if (IsKnownOs) addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include/" + MultiarchTriple + - "/c++/v1"); - } + "/c++/11"); addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/include/c++/v1"); + getDriver().SysRoot + "/include/c++/11"); + break; + default: + llvm_unreachable("Unknown stdlib type"); } } @@ -440,6 +458,9 @@ CmdArgs.push_back("-lc++abi"); break; case ToolChain::CST_Libstdcxx: + CmdArgs.push_back("-lstdc++"); + break; + default: llvm_unreachable("invalid stdlib name"); } } @@ -455,3 +476,81 @@ 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()) { + // FIXME: Fallback correct? + Version = "v1"; + } + + // First add the per-target include path if the OS is known. + std::string TargetDir = LibPath + "/" + MultiarchTriple + "/c++/" + Version; + if (IsKnownOs) + 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; + int MaxVersion = 0; + std::string MaxVersionString; + 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()); + int Version; + if (VersionText[0] != 'v' && + !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { + if (Version > MaxVersion) { + MaxVersion = Version; + MaxVersionString = std::string(VersionText); + } + } + } + if (MaxVersion > 0) + Version = MaxVersionString; + } + + if (Version.empty()) { + // FIXME: Fallback correct? + Version = "11"; + } + + // First add the per-target include path if the OS is known. + std::string TargetDir = LibPath + "/" + MultiarchTriple + "/c++/" + Version; + if (IsKnownOs) + addSystemInclude(DriverArgs, CC1Args, TargetDir); + + // Second add the generic one. + addSystemInclude(DriverArgs, CC1Args, LibPath + "/c++/" + Version); +} Index: clang/test/Driver/wasm-toolchain.cpp =================================================================== --- clang/test/Driver/wasm-toolchain.cpp +++ 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,6 +55,11 @@ // 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 \ @@ -52,3 +72,14 @@ // COMPILE: "-internal-isystem" "[[RESOURCE_DIR]]{{(/|\\\\)}}include" // COMPILE: "-internal-isystem" "/foo/include/wasm32-wasi" // COMPILE: "-internal-isystem" "/foo/include" + +// RUN: %clangxx -### -no-canonical-prefixes -target wasm32-wasi --sysroot=/foo --stdlib=libstdc++ %s 2>&1 \ +// RUN: | FileCheck -check-prefix=COMPILE_STDCXX %s +// COMPILE_STDCXX: clang{{.*}}" "-cc1" +// COMPILE_STDCXX: "-resource-dir" "[[RESOURCE_DIR:[^"]*]]" +// COMPILE_STDCXX: "-isysroot" "/foo" +// COMPILE_STDCXX: "-internal-isystem" "/foo/include/wasm32-wasi/c++/11" +// COMPILE_STDCXX: "-internal-isystem" "/foo/include/c++/11" +// COMPILE_STDCXX: "-internal-isystem" "[[RESOURCE_DIR]]{{(/|\\\\)}}include" +// COMPILE_STDCXX: "-internal-isystem" "/foo/include/wasm32-wasi" +// COMPILE_STDCXX: "-internal-isystem" "/foo/include"