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; @@ -29,13 +30,14 @@ std::string WebAssembly::getMultiarchTriple(const Driver &D, const llvm::Triple &TargetTriple, StringRef SysRoot) const { - return (TargetTriple.getArchName() + "-" + - TargetTriple.getOSAndEnvironmentName()).str(); + return (TargetTriple.getArchName() + "-" + + TargetTriple.getOSAndEnvironmentName()) + .str(); } std::string wasm::Linker::getLinkerPath(const ArgList &Args) const { const ToolChain &ToolChain = getToolChain(); - if (const Arg* A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { + if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { StringRef UseLinker = A->getValue(); if (!UseLinker.empty()) { if (llvm::sys::path::is_absolute(UseLinker) && @@ -159,9 +161,9 @@ /// Given a base library directory, append path components to form the /// LTO directory. static std::string AppendLTOLibDir(const std::string &Dir) { - // The version allows the path to be keyed to the specific version of - // LLVM in used, as the bitcode format is not stable. - return Dir + "/llvm-lto/" LLVM_VERSION_STRING; + // The version allows the path to be keyed to the specific version of + // LLVM in used, as the bitcode format is not stable. + return Dir + "/llvm-lto/" LLVM_VERSION_STRING; } WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, @@ -371,9 +373,15 @@ WebAssembly::GetCXXStdlibType(const ArgList &Args) const { if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { StringRef Value = A->getValue(); - if (Value != "libc++") + if (Value == "libstdc++") { + return ToolChain::CST_Libstdcxx; + } else if (Value == "libc++") { + return ToolChain::CST_Libcxx; + } else { getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); + return ToolChain::CST_Libcxx; + } } return ToolChain::CST_Libcxx; } @@ -410,37 +418,67 @@ if (getTriple().getOS() != llvm::Triple::UnknownOS) { const std::string MultiarchTriple = getMultiarchTriple(D, getTriple(), D.SysRoot); - addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include/" + MultiarchTriple); + addSystemInclude(DriverArgs, CC1Args, + D.SysRoot + "/include/" + MultiarchTriple); } addSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include"); } void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (!DriverArgs.hasArg(options::OPT_nostdlibinc) && - !DriverArgs.hasArg(options::OPT_nostdincxx)) { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + std::string SysRoot = getDriver().SysRoot; + const std::string MultiarchTriple = + getMultiarchTriple(getDriver(), getTriple(), SysRoot); + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: { if (getTriple().getOS() != llvm::Triple::UnknownOS) { - const std::string MultiarchTriple = - getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/include/" + MultiarchTriple + - "/c++/v1"); + SysRoot + "/include/" + MultiarchTriple + "/c++/v1"); } + addSystemInclude(DriverArgs, CC1Args, SysRoot + "/include/c++/v1"); + break; + } + case ToolChain::CST_Libstdcxx: { + std::error_code EC; + Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; + std::string CxxIncludePath = SysRoot + "/include/c++/"; + // Walk the subdirs, and find the one with the newest gcc version: + for (llvm::vfs::directory_iterator + LI = getVFS().dir_begin(CxxIncludePath, EC), + LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); + if (CandidateVersion.Major == -1) + continue; + if (CandidateVersion <= Version) + continue; + Version = CandidateVersion; + } + if (Version.Major == -1) + break; + std::string LibstdcxxInclude = SysRoot + "/include/c++/" + Version.Text; addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/include/c++/v1"); + LibstdcxxInclude + "/" + MultiarchTriple); + addSystemInclude(DriverArgs, CC1Args, LibstdcxxInclude); + break; + } } } void WebAssembly::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { - switch (GetCXXStdlibType(Args)) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); CmdArgs.push_back("-lc++abi"); break; case ToolChain::CST_Libstdcxx: - llvm_unreachable("invalid stdlib name"); + CmdArgs.push_back("-lstdc++"); + break; } } Index: clang/test/Driver/wasm-toolchain.cpp =================================================================== --- clang/test/Driver/wasm-toolchain.cpp +++ clang/test/Driver/wasm-toolchain.cpp @@ -14,35 +14,35 @@ // A basic C++ link command-line with unknown OS. -// RUN: %clangxx -### -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo --stdlib=c++ %s 2>&1 \ +// RUN: %clangxx -### -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo --stdlib=libc++ %s 2>&1 \ // RUN: | FileCheck -check-prefix=LINK %s // 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" // 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=c++ 2>&1 \ +// RUN: %clangxx -### -O2 -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo %s --stdlib=libc++ 2>&1 \ // RUN: | FileCheck -check-prefix=LINK_OPT %s // 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" // A basic C++ link command-line with known OS. -// RUN: %clangxx -### -no-canonical-prefixes -target wasm32-wasi --sysroot=/foo --stdlib=c++ %s 2>&1 \ +// RUN: %clangxx -### -no-canonical-prefixes -target wasm32-wasi --sysroot=/foo --stdlib=libc++ %s 2>&1 \ // RUN: | FileCheck -check-prefix=LINK_KNOWN %s // 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" // A basic C++ link command-line with optimization with known OS. -// RUN: %clangxx -### -O2 -no-canonical-prefixes -target wasm32-wasi --sysroot=/foo %s --stdlib=c++ 2>&1 \ +// RUN: %clangxx -### -O2 -no-canonical-prefixes -target wasm32-wasi --sysroot=/foo %s --stdlib=libc++ 2>&1 \ // RUN: | FileCheck -check-prefix=LINK_OPT_KNOWN %s // 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" // A basic C++ compile command-line with known OS. -// RUN: %clangxx -### -no-canonical-prefixes -target wasm32-wasi --sysroot=/foo --stdlib=c++ %s 2>&1 \ +// RUN: %clangxx -### -no-canonical-prefixes -target wasm32-wasi --sysroot=/foo --stdlib=libc++ %s 2>&1 \ // RUN: | FileCheck -check-prefix=COMPILE %s // COMPILE: clang{{.*}}" "-cc1" // COMPILE: "-resource-dir" "[[RESOURCE_DIR:[^"]*]]" @@ -52,3 +52,21 @@ // COMPILE: "-internal-isystem" "[[RESOURCE_DIR]]{{(/|\\\\)}}include" // COMPILE: "-internal-isystem" "/foo/include/wasm32-wasi" // COMPILE: "-internal-isystem" "/foo/include" + +// A basic C++ link command-line with known OS for -stdlib=libstdc++. + +// RUN: %clangxx -### -no-canonical-prefixes -target wasm32-wasi --sysroot=/foo --stdlib=libstdc++ %s 2>&1 \ +// RUN: | FileCheck -check-prefix=LINK_OPT_KNOWN_GCC %s +// LINK_OPT_KNOWN_GCC: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]" +// LINK_OPT_KNOWN_GCC: 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 for -stdlib=libstdc++. + +// RUN: %clangxx -### -no-canonical-prefixes -target wasm32-wasi --sysroot=/foo --stdlib=libstdc++ %s 2>&1 \ +// RUN: | FileCheck -check-prefix=COMPILE_GCC %s +// COMPILE_GCC: clang{{.*}}" "-cc1" +// COMPILE_GCC: "-resource-dir" "[[RESOURCE_DIR:[^"]*]]" +// COMPILE_GCC: "-isysroot" "/foo" +// COMPILE_GCC: "-internal-isystem" "[[RESOURCE_DIR]]{{(/|\\\\)}}include" +// COMPILE_GCC: "-internal-isystem" "/foo/include/wasm32-wasi" +// COMPILE_GCC: "-internal-isystem" "/foo/include"