r361116 - [AVR] Automatically link CRT and libgcc from the system avr-gcc
Dylan McKay via cfe-commits
cfe-commits at lists.llvm.org
Sun May 19 02:54:14 PDT 2019
Author: dylanmckay
Date: Sun May 19 02:54:14 2019
New Revision: 361116
URL: http://llvm.org/viewvc/llvm-project?rev=361116&view=rev
Log:
[AVR] Automatically link CRT and libgcc from the system avr-gcc
Summary:
This patch modifies the AVR toolchain so that if avr-gcc and avr-libc
are detected during compilation, the CRT, libgcc, libm, and libc anre
linked.
This matches avr-gcc's default behaviour, and the expected behaviour of
all C compilers - including the C runtime.
avr-gcc also needs a -mmcu specified in order to link runtime libraries.
The difference betwen this patch and avr-gcc is that this patch will
warn users whenever they compile without a runtime, as opposed to GCC,
which silently trims the runtime libs from the linker arguments when no
-mmcu is specified.
Reviewers: aaron.ballman, kparzysz, asb, hfinkel, brucehoult, TimNN
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D54334
Added:
cfe/trunk/test/Driver/avr-link-mcu-family-unimplemented.c
cfe/trunk/test/Driver/avr-link-no-mcu-specified.c
cfe/trunk/test/Driver/avr-link-nostdlib-nodefaultlibs.c
Modified:
cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
cfe/trunk/include/clang/Basic/DiagnosticGroups.td
cfe/trunk/lib/Driver/ToolChains/AVR.cpp
cfe/trunk/lib/Driver/ToolChains/AVR.h
cfe/trunk/lib/Driver/ToolChains/Gnu.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td?rev=361116&r1=361115&r2=361116&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td Sun May 19 02:54:14 2019
@@ -27,6 +27,25 @@ def err_drv_invalid_riscv_arch_name : Er
"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">,
+ 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 "
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=361116&r1=361115&r2=361116&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Sun May 19 02:54:14 2019
@@ -1033,6 +1033,10 @@ def SerializedDiagnostics : DiagGroup<"s
// 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">;
Modified: cfe/trunk/lib/Driver/ToolChains/AVR.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChains/AVR.cpp?rev=361116&r1=361115&r2=361116&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/ToolChains/AVR.cpp (original)
+++ cfe/trunk/lib/Driver/ToolChains/AVR.cpp Sun May 19 02:54:14 2019
@@ -10,7 +10,14 @@
#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;
@@ -18,12 +25,76 @@ 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 StringRef 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,
@@ -31,13 +102,58 @@ void AVR::Linker::ConstructJob(Compilati
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");
+
+ // 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") + *FamilyName));
+ }
+
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 llvm::None;
+}
Modified: cfe/trunk/lib/Driver/ToolChains/AVR.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChains/AVR.h?rev=361116&r1=361115&r2=361116&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/ToolChains/AVR.h (original)
+++ cfe/trunk/lib/Driver/ToolChains/AVR.h Sun May 19 02:54:14 2019
@@ -19,11 +19,21 @@ namespace driver {
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
@@ -32,13 +42,20 @@ 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
Modified: cfe/trunk/lib/Driver/ToolChains/Gnu.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChains/Gnu.cpp?rev=361116&r1=361115&r2=361116&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/ToolChains/Gnu.cpp (original)
+++ cfe/trunk/lib/Driver/ToolChains/Gnu.cpp Sun May 19 02:54:14 2019
@@ -1926,6 +1926,9 @@ void Generic_GCC::GCCInstallationDetecto
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",
@@ -2146,6 +2149,10 @@ void Generic_GCC::GCCInstallationDetecto
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));
@@ -2286,6 +2293,8 @@ bool Generic_GCC::GCCInstallationDetecto
findRISCVMultilibs(D, TargetTriple, Path, Args, Detected);
} else if (isMSP430(TargetArch)) {
findMSP430Multilibs(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;
Added: cfe/trunk/test/Driver/avr-link-mcu-family-unimplemented.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/avr-link-mcu-family-unimplemented.c?rev=361116&view=auto
==============================================================================
--- cfe/trunk/test/Driver/avr-link-mcu-family-unimplemented.c (added)
+++ cfe/trunk/test/Driver/avr-link-mcu-family-unimplemented.c Sun May 19 02:54:14 2019
@@ -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
+// WARN: warning: standard library not linked and so no interrupt vector table or compiler runtime routines will be linked
+
+int main() { return 0; }
+
Added: cfe/trunk/test/Driver/avr-link-no-mcu-specified.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/avr-link-no-mcu-specified.c?rev=361116&view=auto
==============================================================================
--- cfe/trunk/test/Driver/avr-link-no-mcu-specified.c (added)
+++ cfe/trunk/test/Driver/avr-link-no-mcu-specified.c Sun May 19 02:54:14 2019
@@ -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; }
+
Added: cfe/trunk/test/Driver/avr-link-nostdlib-nodefaultlibs.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/avr-link-nostdlib-nodefaultlibs.c?rev=361116&view=auto
==============================================================================
--- cfe/trunk/test/Driver/avr-link-nostdlib-nodefaultlibs.c (added)
+++ cfe/trunk/test/Driver/avr-link-nostdlib-nodefaultlibs.c Sun May 19 02:54:14 2019
@@ -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; }
+
More information about the cfe-commits
mailing list