Index: clang/lib/Driver/ToolChains/AVR.cpp =================================================================== --- clang/lib/Driver/ToolChains/AVR.cpp +++ clang/lib/Driver/ToolChains/AVR.cpp @@ -375,8 +375,7 @@ // Only add default libraries if the user hasn't explicitly opted out. if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs) && - GCCInstallation.isValid()) { + !Args.hasArg(options::OPT_nodefaultlibs) && GCCInstallation.isValid()) { GCCInstallPath = GCCInstallation.getInstallPath(); std::string GCCParentPath(GCCInstallation.getParentLibPath()); getProgramPaths().push_back(GCCParentPath + "/../bin"); @@ -429,9 +428,13 @@ // Compute information about the target AVR. std::string CPU = getCPUName(D, Args, getToolChain().getTriple()); llvm::Optional FamilyName = GetMCUFamilyName(CPU); + llvm::Optional AVRLibcRoot = TC.findAVRLibcInstallation(); llvm::Optional SectionAddressData = GetMCUSectionAddressData(CPU); - std::string Linker = getToolChain().GetProgramPath(getShortName()); + // Compute the linker program path, and use GNU "avr-ld" as default. + bool IsLLD = false; + std::string Linker = getToolChain().GetLinkerPath(&IsLLD); + ArgStringList CmdArgs; AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); @@ -450,17 +453,11 @@ if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (!CPU.empty()) { - Optional FamilyName = GetMCUFamilyName(CPU); - Optional AVRLibcRoot = TC.findAVRLibcInstallation(); - if (!FamilyName) { // 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 (TC.getGCCInstallPath().empty()) { - // We can not link since there is no avr-ld. - D.Diag(diag::warn_drv_avr_gcc_not_found); } else if (!AVRLibcRoot) { // No avr-libc found and so no runtime linked. D.Diag(diag::warn_drv_avr_libc_not_found); @@ -473,7 +470,6 @@ LinkStdlib = true; } } - if (!LinkStdlib) D.Diag(diag::warn_drv_avr_stdlib_not_linked); } @@ -508,11 +504,37 @@ CmdArgs.push_back("--end-group"); - // 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)); + // Add user specified linker script. + const Arg *LDS = Args.getLastArg(options::OPT_T); + if (LDS) { + CmdArgs.push_back(Args.MakeArgString("-T")); + CmdArgs.push_back(Args.MakeArgString(LDS->getValue())); + } + + // Add specific options for different linkers. + if (IsLLD && !LDS) { + // We must explicitly specify `__vectors` as the entry, if the user + // does not specify the '-T' option. + CmdArgs.push_back(Args.MakeArgString("-e")); + CmdArgs.push_back(Args.MakeArgString("__vectors")); + // Add the default linker script for current AVR device, if user does not + // specify the '-T' option. The default linker script should has already + // integrated into avr-libc, and whose full path is expected to be + // $AVR-LIBC/lib/ldscripts/$FamilyName.x . + if (AVRLibcRoot && FamilyName) { + std::string Prefix(*AVRLibcRoot + "/lib/ldscripts/"); + if (llvm::sys::fs::is_directory(Prefix)) { + CmdArgs.push_back(Args.MakeArgString("-T")); + CmdArgs.push_back(Args.MakeArgString(Prefix + *FamilyName + ".x")); + } + } + } else if (Linker.find("avr-ld") != std::string::npos) { + // 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(std::make_unique( Index: clang/test/Driver/avr-toolchain.c =================================================================== --- clang/test/Driver/avr-toolchain.c +++ clang/test/Driver/avr-toolchain.c @@ -53,8 +53,24 @@ // LINKA-NOT: warning: {{.*}} data section address // RUN: %clang -### --target=avr --sysroot=%S/Inputs/ -mmcu=atmega328 %s 2>&1 | FileCheck --check-prefixes=NOGCC %s -// NOGCC: warning: no avr-gcc installation can be found on the system, cannot link standard libraries +// NOGCC: error: invalid linker // NOGCC: warning: standard library not linked and so no interrupt vector table or compiler runtime routines will be linked // NOGCC-NOT: warning: {{.*}} microcontroller // NOGCC-NOT: warning: {{.*}} avr-libc // NOGCC-NOT: warning: {{.*}} data section address + +// RUN: %clang -### --target=avr --sysroot=%S/Inputs/basic_avr_tree -mmcu=atmega328 %s -fuse-ld=avrld 2>&1 | FileCheck --check-prefix=NOLD %s +// NOLD: error: invalid linker + +// RUN: %clang -### --target=avr --sysroot=%S/Inputs/basic_avr_tree -mmcu=atmega328 %s -fuse-ld=lld 2>&1 | FileCheck --check-prefix=LLD %s +// LLD: {{".*lld"}} {{.*}} "-e" "__vectors" "-T" {{".*avr5.x"}} +// LLD-NOT: "avr-ld" +// LLD-NOT: "-mavr5" + +// RUN: %clang -### --target=avr --sysroot=%S/Inputs/basic_avr_tree -mmcu=atmega328 %s -T avr.lds 2>&1 | FileCheck --check-prefix=LDS0 %s +// LDS0: "-T" "avr.lds" "-mavr5" + +// RUN: %clang -### --target=avr --sysroot=%S/Inputs/basic_avr_tree -mmcu=atmega328 %s -fuse-ld=lld -T avr.lds 2>&1 | FileCheck --check-prefix=LDS1 %s +// LDS1: "-T" "avr.lds" +// LDS1-NOT: "-e" +// LDS1-NOT: "-mavr5"