dylanmckay updated this revision to Diff 173722.
dylanmckay added a comment.

Add the search path that Ubuntu installs libc to.


Repository:
  rC Clang

https://reviews.llvm.org/D54334

Files:
  include/clang/Basic/DiagnosticDriverKinds.td
  include/clang/Basic/DiagnosticGroups.td
  lib/Driver/ToolChains/AVR.cpp
  lib/Driver/ToolChains/AVR.h
  lib/Driver/ToolChains/Gnu.cpp
  test/Driver/avr-link-mcu-family-unimplemented.c
  test/Driver/avr-link-no-mcu-specified.c
  test/Driver/avr-link-nostdlib-nodefaultlibs.c

Index: test/Driver/avr-link-nostdlib-nodefaultlibs.c
===================================================================
--- /dev/null
+++ test/Driver/avr-link-nostdlib-nodefaultlibs.c
@@ -0,0 +1,8 @@
+// RUN: %clang -### -target avr -no-canonical-prefixes -save-temps -mmcu=atmega328 -nostdlib %s 2>&1 | FileCheck %s
+// RUN: %clang -### -target avr -no-canonical-prefixes -save-temps -mmcu=atmega328 -nodefaultlibs %s 2>&1 | FileCheck %s
+
+// nostdlib and nodefaultlibs programs should compile fine.
+
+// CHECK: main
+int main() { return 0; }
+
Index: test/Driver/avr-link-no-mcu-specified.c
===================================================================
--- /dev/null
+++ test/Driver/avr-link-no-mcu-specified.c
@@ -0,0 +1,10 @@
+// RUN: %clang -### -target avr -no-canonical-prefixes -save-temps %s 2>&1 | FileCheck --check-prefix=WARN %s
+// RUN: %clang -### -target avr -no-canonical-prefixes -save-temps -mmcu=atmega328 %s 2>&1 | FileCheck --check-prefix=NOWARN %s
+
+// WARN: warning: no target microcontroller specified on command line, cannot link standard libraries, please pass -mmcu=<mcu name>
+// WARN: warning: standard library not linked and so no interrupt vector table or compiler runtime routines will be linked
+
+// NOWARN: main
+
+int main() { return 0; }
+
Index: test/Driver/avr-link-mcu-family-unimplemented.c
===================================================================
--- /dev/null
+++ test/Driver/avr-link-mcu-family-unimplemented.c
@@ -0,0 +1,7 @@
+// RUN: %clang -### -target avr -no-canonical-prefixes -save-temps -mmcu=attiny13a %s 2>&1 | FileCheck --check-prefix=WARN %s
+
+// WARN: warning: support for linking stdlibs for microcontroller 'attiny13a' is not implemented, please file an AVR backend bug at http://bugs.llvm.org/ with your mcu name
+// WARN: warning: standard library not linked and so no interrupt vector table or compiler runtime routines will be linked
+
+int main() { return 0; }
+
Index: lib/Driver/ToolChains/Gnu.cpp
===================================================================
--- lib/Driver/ToolChains/Gnu.cpp
+++ lib/Driver/ToolChains/Gnu.cpp
@@ -1865,6 +1865,9 @@
   static const char *const ARMebHFTriples[] = {
       "armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"};
 
+  static const char *const AVRLibDirs[] = {"/lib"};
+  static const char *const AVRTriples[] = {"avr"};
+
   static const char *const X86_64LibDirs[] = {"/lib64", "/lib"};
   static const char *const X86_64Triples[] = {
       "x86_64-linux-gnu",       "x86_64-unknown-linux-gnu",
@@ -2077,6 +2080,10 @@
       TripleAliases.append(begin(ARMebTriples), end(ARMebTriples));
     }
     break;
+  case llvm::Triple::avr:
+    LibDirs.append(begin(AVRLibDirs), end(AVRLibDirs));
+    TripleAliases.append(begin(AVRTriples), end(AVRTriples));
+    break;
   case llvm::Triple::x86_64:
     LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
     TripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
@@ -2205,6 +2212,8 @@
       return false;
   } else if (isRISCV(TargetArch)) {
     findRISCVMultilibs(D, TargetTriple, Path, Args, Detected);
+  } else if (TargetArch == llvm::Triple::avr) {
+    // AVR has no multilibs.
   } else if (!findBiarchMultilibs(D, TargetTriple, Path, Args,
                                   NeedsBiarchSuffix, Detected)) {
     return false;
Index: lib/Driver/ToolChains/AVR.h
===================================================================
--- lib/Driver/ToolChains/AVR.h
+++ lib/Driver/ToolChains/AVR.h
@@ -20,26 +20,45 @@
 namespace toolchains {
 
 class LLVM_LIBRARY_VISIBILITY AVRToolChain : public Generic_ELF {
-protected:
-  Tool *buildLinker() const override;
 public:
   AVRToolChain(const Driver &D, const llvm::Triple &Triple,
                const llvm::opt::ArgList &Args);
+protected:
+  Tool *buildLinker() const override;
+
+private:
+  /// Whether libgcc, libct, and friends should be linked.
+  ///
+  /// This is not done if the user does not specify a
+  /// microcontroller on the command line.
+  bool LinkStdlib;
+
+  llvm::Optional<std::string> findAVRLibcInstallation() const;
 };
 
 } // end namespace toolchains
 
 namespace tools {
 namespace AVR {
 class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
 public:
-  Linker(const ToolChain &TC) : GnuTool("AVR::Linker", "avr-ld", TC) {}
+  Linker(const llvm::Triple &Triple,
+         const ToolChain &TC,
+         bool LinkStdlib)
+    : GnuTool("AVR::Linker", "avr-ld", TC),
+      Triple(Triple),
+      LinkStdlib(LinkStdlib) {}
+
   bool hasIntegratedCPP() const override { return false; }
   bool isLinkJob() const override { return true; }
   void ConstructJob(Compilation &C, const JobAction &JA,
                     const InputInfo &Output, const InputInfoList &Inputs,
                     const llvm::opt::ArgList &TCArgs,
                     const char *LinkingOutput) const override;
+protected:
+
+  const llvm::Triple &Triple;
+  bool LinkStdlib;
 };
 } // end namespace AVR
 } // end namespace tools
Index: lib/Driver/ToolChains/AVR.cpp
===================================================================
--- lib/Driver/ToolChains/AVR.cpp
+++ lib/Driver/ToolChains/AVR.cpp
@@ -11,34 +11,154 @@
 #include "CommonArgs.h"
 #include "InputInfo.h"
 #include "clang/Driver/Compilation.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/SubtargetFeature.h"
 #include "llvm/Option/ArgList.h"
+#include "llvm/Support/FileSystem.h"
 
 using namespace clang::driver;
 using namespace clang::driver::toolchains;
 using namespace clang::driver::tools;
 using namespace clang;
 using namespace llvm::opt;
 
+namespace {
+
+// TODO: Consider merging this into the AVR device table
+// array in Targets/AVR.cpp.
+llvm::Optional<StringRef> GetMcuFamilyName(StringRef MCU) {
+  return llvm::StringSwitch<llvm::Optional<StringRef>>(MCU)
+                .Case("atmega328", Optional<StringRef>("avr5"))
+                .Case("atmega328p", Optional<StringRef>("avr5"))
+                .Default(Optional<StringRef>());
+}
+
+const std::string PossibleAVRLibcLocations[] = {
+  "/usr/avr",
+  "/usr/lib/avr",
+};
+
+} // end anonymous namespace
+
 /// AVR Toolchain
 AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple,
                            const ArgList &Args)
-  : Generic_ELF(D, Triple, Args) { }
+  : Generic_ELF(D, Triple, Args), LinkStdlib(false) {
+    GCCInstallation.init(Triple, Args);
+
+    // Only add default libraries if the user hasn't explicitly opted out.
+    if (!Args.hasArg(options::OPT_nostdlib) &&
+        !Args.hasArg(options::OPT_nodefaultlibs) &&
+        !Args.hasArg(options::OPT_c /* does not apply when not linking */)) {
+      std::string CPU = getCPUName(Args, Triple);
+
+      if (CPU.empty()) {
+        // We cannot link any standard libraries without an MCU specified.
+        D.Diag(diag::warn_drv_avr_mcu_not_specified);
+      } else {
+        Optional<StringRef> FamilyName = GetMcuFamilyName(CPU);
+        Optional<std::string> AVRLibcRoot = findAVRLibcInstallation();
+
+        if (!FamilyName.hasValue()) {
+          // We do not have an entry for this CPU in the family
+          // mapping table yet.
+          D.Diag(diag::warn_drv_avr_family_linking_stdlibs_not_implemented)
+            << CPU;
+        } else if (!GCCInstallation.isValid()) {
+          // No avr-gcc found and so no runtime linked.
+          D.Diag(diag::warn_drv_avr_gcc_not_found);
+        } else if (!AVRLibcRoot.hasValue()) {
+          // No avr-libc found and so no runtime linked.
+          D.Diag(diag::warn_drv_avr_libc_not_found);
+        } else { // We have enough information to link stdlibs
+          std::string GCCRoot = GCCInstallation.getInstallPath();
+          std::string LibcRoot = AVRLibcRoot.getValue();
+
+          getFilePaths().push_back(LibcRoot + std::string("/lib/") +
+                                   std::string(*FamilyName));
+          getFilePaths().push_back(LibcRoot + std::string("/lib/") +
+                                   std::string(*FamilyName));
+          getFilePaths().push_back(GCCRoot + std::string("/") +
+                                   std::string(*FamilyName));
+
+          LinkStdlib = true;
+        }
+      }
+
+      if (!LinkStdlib) {
+        D.Diag(diag::warn_drv_avr_stdlib_not_linked);
+      }
+    }
+  }
+
 Tool *AVRToolChain::buildLinker() const {
-  return new tools::AVR::Linker(*this);
+  return new tools::AVR::Linker(getTriple(), *this, LinkStdlib);
 }
 
 void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
                                const InputInfo &Output,
                                const InputInfoList &Inputs,
                                const ArgList &Args,
                                const char *LinkingOutput) const {
+  // Compute information about the target AVR.
+  std::string CPU = getCPUName(Args, getToolChain().getTriple());
+  llvm::Optional<StringRef> FamilyName = GetMcuFamilyName(CPU);
 
   std::string Linker = getToolChain().GetProgramPath(getShortName());
   ArgStringList CmdArgs;
   AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+
   CmdArgs.push_back("-o");
   CmdArgs.push_back(Output.getFilename());
+
+  // Enable garbage collection of unused sections.
+  CmdArgs.push_back("--gc-sections");
+
+  // Add library search paths before we specify libraries.
+  Args.AddAllArgs(CmdArgs, options::OPT_L);
+  getToolChain().AddFilePathLibArgs(Args, CmdArgs);
+
+  // If the family name is known, we can link with the device-specific libgcc.
+  // Without it, libgcc will simply not be linked. This matches avr-gcc
+  // behavior.
+  if (LinkStdlib) {
+    assert(!CPU.empty() && "CPU name must be known in order to link stdlibs");
+    auto Family = FamilyName.getValue();
+
+    // Add the object file for the CRT.
+    std::string CrtFileName = std::string("-l:crt") + CPU + std::string(".o");
+    CmdArgs.push_back(Args.MakeArgString(CrtFileName));
+
+    CmdArgs.push_back("-lgcc");
+    CmdArgs.push_back("-lm");
+    CmdArgs.push_back("-lc");
+
+    // Add the link library specific to the MCU.
+    CmdArgs.push_back(Args.MakeArgString(std::string("-l") + CPU));
+
+    // Specify the family name as the emulation mode to use.
+    // This is almost always required because otherwise avr-ld
+    // will assume 'avr2' and warn about the program being larger
+    // than the bare minimum supports.
+    CmdArgs.push_back(Args.MakeArgString(std::string("-m") + Family));
+  }
+
   C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
                                           CmdArgs, Inputs));
 }
-// AVR tools end.
+
+llvm::Optional<std::string> AVRToolChain::findAVRLibcInstallation() const {
+  for (StringRef PossiblePath : PossibleAVRLibcLocations) {
+    // Return the first avr-libc installation that exists.
+    if (llvm::sys::fs::is_directory(PossiblePath)) {
+      return Optional<std::string>(std::string(PossiblePath));
+    }
+  }
+
+  return Optional<std::string>();
+}
+
Index: include/clang/Basic/DiagnosticGroups.td
===================================================================
--- include/clang/Basic/DiagnosticGroups.td
+++ include/clang/Basic/DiagnosticGroups.td
@@ -1016,6 +1016,10 @@
 // compiling CUDA C/C++ but which is not compatible with the CUDA spec.
 def CudaCompat : DiagGroup<"cuda-compat">;
 
+// Warnings which cause linking of the runtime libraries like
+// libc and the CRT to be skipped.
+def AVRRtlibLinkingQuirks : DiagGroup<"avr-rtlib-linking-quirks">;
+
 // A warning group for things that will change semantics in the future.
 def FutureCompat : DiagGroup<"future-compat">;
 
Index: include/clang/Basic/DiagnosticDriverKinds.td
===================================================================
--- include/clang/Basic/DiagnosticDriverKinds.td
+++ include/clang/Basic/DiagnosticDriverKinds.td
@@ -28,6 +28,26 @@
   "invalid arch name '%0', %1">;
 def err_drv_invalid_riscv_ext_arch_name : Error<
   "invalid arch name '%0', %1 '%2'">;
+def warn_drv_avr_mcu_not_specified : Warning<
+  "no target microcontroller specified on command line, cannot "
+  "link standard libraries, please pass -mmcu=<mcu name>">,
+  InGroup<AVRRtlibLinkingQuirks>;
+def warn_drv_avr_gcc_not_found: Warning<
+  "no avr-gcc installation can be found on the system, "
+  "cannot link standard libraries">,
+  InGroup<AVRRtlibLinkingQuirks>;
+def warn_drv_avr_libc_not_found: Warning<
+  "no avr-libc installation can be found on the system, "
+  "cannot link standard libraries">,
+  InGroup<AVRRtlibLinkingQuirks>;
+def warn_drv_avr_family_linking_stdlibs_not_implemented: Warning<
+  "support for linking stdlibs for microcontroller '%0' is not implemented, "
+  "please file an AVR backend bug at http://bugs.llvm.org/ with your mcu name">,
+  InGroup<AVRRtlibLinkingQuirks>;
+def warn_drv_avr_stdlib_not_linked: Warning<
+  "standard library not linked and so no interrupt vector table or "
+  "compiler runtime routines will be linked">,
+  InGroup<AVRRtlibLinkingQuirks>;
 def err_drv_cuda_bad_gpu_arch : Error<"Unsupported CUDA gpu architecture: %0">;
 def err_drv_no_cuda_installation : Error<
   "cannot find CUDA installation.  Provide its path via --cuda-path, or pass "
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to