forked from OSchip/llvm-project
[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 llvm-svn: 361116
This commit is contained in:
parent
f8fccb14de
commit
83338b1059
|
@ -27,6 +27,25 @@ def err_drv_invalid_riscv_arch_name : Error<
|
||||||
"invalid arch name '%0', %1">;
|
"invalid arch name '%0', %1">;
|
||||||
def err_drv_invalid_riscv_ext_arch_name : Error<
|
def err_drv_invalid_riscv_ext_arch_name : Error<
|
||||||
"invalid arch name '%0', %1 '%2'">;
|
"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_cuda_bad_gpu_arch : Error<"Unsupported CUDA gpu architecture: %0">;
|
||||||
def err_drv_no_cuda_installation : Error<
|
def err_drv_no_cuda_installation : Error<
|
||||||
"cannot find CUDA installation. Provide its path via --cuda-path, or pass "
|
"cannot find CUDA installation. Provide its path via --cuda-path, or pass "
|
||||||
|
|
|
@ -1033,6 +1033,10 @@ def SerializedDiagnostics : DiagGroup<"serialized-diagnostics">;
|
||||||
// compiling CUDA C/C++ but which is not compatible with the CUDA spec.
|
// compiling CUDA C/C++ but which is not compatible with the CUDA spec.
|
||||||
def CudaCompat : DiagGroup<"cuda-compat">;
|
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.
|
// A warning group for things that will change semantics in the future.
|
||||||
def FutureCompat : DiagGroup<"future-compat">;
|
def FutureCompat : DiagGroup<"future-compat">;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,14 @@
|
||||||
#include "CommonArgs.h"
|
#include "CommonArgs.h"
|
||||||
#include "InputInfo.h"
|
#include "InputInfo.h"
|
||||||
#include "clang/Driver/Compilation.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/Option/ArgList.h"
|
||||||
|
#include "llvm/Support/FileSystem.h"
|
||||||
|
|
||||||
using namespace clang::driver;
|
using namespace clang::driver;
|
||||||
using namespace clang::driver::toolchains;
|
using namespace clang::driver::toolchains;
|
||||||
|
@ -18,12 +25,76 @@ using namespace clang::driver::tools;
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using namespace llvm::opt;
|
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
|
/// AVR Toolchain
|
||||||
AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple,
|
AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple,
|
||||||
const ArgList &Args)
|
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 {
|
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,
|
void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||||
|
@ -31,13 +102,58 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||||
const InputInfoList &Inputs,
|
const InputInfoList &Inputs,
|
||||||
const ArgList &Args,
|
const ArgList &Args,
|
||||||
const char *LinkingOutput) const {
|
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());
|
std::string Linker = getToolChain().GetProgramPath(getShortName());
|
||||||
ArgStringList CmdArgs;
|
ArgStringList CmdArgs;
|
||||||
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
|
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
|
||||||
|
|
||||||
CmdArgs.push_back("-o");
|
CmdArgs.push_back("-o");
|
||||||
CmdArgs.push_back(Output.getFilename());
|
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),
|
C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
|
||||||
CmdArgs, Inputs));
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -19,11 +19,21 @@ namespace driver {
|
||||||
namespace toolchains {
|
namespace toolchains {
|
||||||
|
|
||||||
class LLVM_LIBRARY_VISIBILITY AVRToolChain : public Generic_ELF {
|
class LLVM_LIBRARY_VISIBILITY AVRToolChain : public Generic_ELF {
|
||||||
protected:
|
|
||||||
Tool *buildLinker() const override;
|
|
||||||
public:
|
public:
|
||||||
AVRToolChain(const Driver &D, const llvm::Triple &Triple,
|
AVRToolChain(const Driver &D, const llvm::Triple &Triple,
|
||||||
const llvm::opt::ArgList &Args);
|
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
|
} // end namespace toolchains
|
||||||
|
@ -32,13 +42,20 @@ namespace tools {
|
||||||
namespace AVR {
|
namespace AVR {
|
||||||
class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
|
class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
|
||||||
public:
|
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 hasIntegratedCPP() const override { return false; }
|
||||||
bool isLinkJob() const override { return true; }
|
bool isLinkJob() const override { return true; }
|
||||||
void ConstructJob(Compilation &C, const JobAction &JA,
|
void ConstructJob(Compilation &C, const JobAction &JA,
|
||||||
const InputInfo &Output, const InputInfoList &Inputs,
|
const InputInfo &Output, const InputInfoList &Inputs,
|
||||||
const llvm::opt::ArgList &TCArgs,
|
const llvm::opt::ArgList &TCArgs,
|
||||||
const char *LinkingOutput) const override;
|
const char *LinkingOutput) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const llvm::Triple &Triple;
|
||||||
|
bool LinkStdlib;
|
||||||
};
|
};
|
||||||
} // end namespace AVR
|
} // end namespace AVR
|
||||||
} // end namespace tools
|
} // end namespace tools
|
||||||
|
|
|
@ -1926,6 +1926,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
|
||||||
static const char *const ARMebHFTriples[] = {
|
static const char *const ARMebHFTriples[] = {
|
||||||
"armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"};
|
"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_64LibDirs[] = {"/lib64", "/lib"};
|
||||||
static const char *const X86_64Triples[] = {
|
static const char *const X86_64Triples[] = {
|
||||||
"x86_64-linux-gnu", "x86_64-unknown-linux-gnu",
|
"x86_64-linux-gnu", "x86_64-unknown-linux-gnu",
|
||||||
|
@ -2146,6 +2149,10 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
|
||||||
TripleAliases.append(begin(ARMebTriples), end(ARMebTriples));
|
TripleAliases.append(begin(ARMebTriples), end(ARMebTriples));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case llvm::Triple::avr:
|
||||||
|
LibDirs.append(begin(AVRLibDirs), end(AVRLibDirs));
|
||||||
|
TripleAliases.append(begin(AVRTriples), end(AVRTriples));
|
||||||
|
break;
|
||||||
case llvm::Triple::x86_64:
|
case llvm::Triple::x86_64:
|
||||||
LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
|
LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
|
||||||
TripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
|
TripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
|
||||||
|
@ -2286,6 +2293,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs(
|
||||||
findRISCVMultilibs(D, TargetTriple, Path, Args, Detected);
|
findRISCVMultilibs(D, TargetTriple, Path, Args, Detected);
|
||||||
} else if (isMSP430(TargetArch)) {
|
} else if (isMSP430(TargetArch)) {
|
||||||
findMSP430Multilibs(D, TargetTriple, Path, Args, Detected);
|
findMSP430Multilibs(D, TargetTriple, Path, Args, Detected);
|
||||||
|
} else if (TargetArch == llvm::Triple::avr) {
|
||||||
|
// AVR has no multilibs.
|
||||||
} else if (!findBiarchMultilibs(D, TargetTriple, Path, Args,
|
} else if (!findBiarchMultilibs(D, TargetTriple, Path, Args,
|
||||||
NeedsBiarchSuffix, Detected)) {
|
NeedsBiarchSuffix, Detected)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
Loading…
Reference in New Issue