/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/Driver/ToolChains/AVR.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- AVR.cpp - AVR ToolChain Implementations ----------------*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "AVR.h" |
10 | | #include "CommonArgs.h" |
11 | | #include "InputInfo.h" |
12 | | #include "clang/Driver/Compilation.h" |
13 | | #include "clang/Driver/DriverDiagnostic.h" |
14 | | #include "clang/Driver/Options.h" |
15 | | #include "llvm/ADT/Optional.h" |
16 | | #include "llvm/ADT/StringSwitch.h" |
17 | | #include "llvm/MC/MCSubtargetInfo.h" |
18 | | #include "llvm/MC/SubtargetFeature.h" |
19 | | #include "llvm/Option/ArgList.h" |
20 | | #include "llvm/Support/FileSystem.h" |
21 | | |
22 | | using namespace clang::driver; |
23 | | using namespace clang::driver::toolchains; |
24 | | using namespace clang::driver::tools; |
25 | | using namespace clang; |
26 | | using namespace llvm::opt; |
27 | | |
28 | | namespace { |
29 | | |
30 | | // TODO: Consider merging this into the AVR device table |
31 | | // array in Targets/AVR.cpp. |
32 | 10 | llvm::Optional<StringRef> GetMcuFamilyName(StringRef MCU) { |
33 | 10 | return llvm::StringSwitch<llvm::Optional<StringRef>>(MCU) |
34 | 10 | .Case("atmega328", Optional<StringRef>("avr5")) |
35 | 10 | .Case("atmega328p", Optional<StringRef>("avr5")) |
36 | 10 | .Default(Optional<StringRef>()); |
37 | 10 | } |
38 | | |
39 | | const StringRef PossibleAVRLibcLocations[] = { |
40 | | "/usr/avr", |
41 | | "/usr/lib/avr", |
42 | | }; |
43 | | |
44 | | } // end anonymous namespace |
45 | | |
46 | | /// AVR Toolchain |
47 | | AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple, |
48 | | const ArgList &Args) |
49 | 7 | : Generic_ELF(D, Triple, Args), LinkStdlib(false) { |
50 | 7 | GCCInstallation.init(Triple, Args); |
51 | 7 | |
52 | 7 | // Only add default libraries if the user hasn't explicitly opted out. |
53 | 7 | if (!Args.hasArg(options::OPT_nostdlib) && |
54 | 7 | !Args.hasArg(options::OPT_nodefaultlibs)6 && |
55 | 7 | !Args.hasArg(options::OPT_c /* does not apply when not linking */)5 ) { |
56 | 5 | std::string CPU = getCPUName(Args, Triple); |
57 | 5 | |
58 | 5 | if (CPU.empty()) { |
59 | 2 | // We cannot link any standard libraries without an MCU specified. |
60 | 2 | D.Diag(diag::warn_drv_avr_mcu_not_specified); |
61 | 3 | } else { |
62 | 3 | Optional<StringRef> FamilyName = GetMcuFamilyName(CPU); |
63 | 3 | Optional<std::string> AVRLibcRoot = findAVRLibcInstallation(); |
64 | 3 | |
65 | 3 | if (!FamilyName.hasValue()) { |
66 | 1 | // We do not have an entry for this CPU in the family |
67 | 1 | // mapping table yet. |
68 | 1 | D.Diag(diag::warn_drv_avr_family_linking_stdlibs_not_implemented) |
69 | 1 | << CPU; |
70 | 2 | } else if (!GCCInstallation.isValid()) { |
71 | 2 | // No avr-gcc found and so no runtime linked. |
72 | 2 | D.Diag(diag::warn_drv_avr_gcc_not_found); |
73 | 2 | } else if (0 !AVRLibcRoot.hasValue()0 ) { |
74 | 0 | // No avr-libc found and so no runtime linked. |
75 | 0 | D.Diag(diag::warn_drv_avr_libc_not_found); |
76 | 0 | } else { // We have enough information to link stdlibs |
77 | 0 | std::string GCCRoot = GCCInstallation.getInstallPath(); |
78 | 0 | std::string LibcRoot = AVRLibcRoot.getValue(); |
79 | 0 |
|
80 | 0 | getFilePaths().push_back(LibcRoot + std::string("/lib/") + |
81 | 0 | std::string(*FamilyName)); |
82 | 0 | getFilePaths().push_back(LibcRoot + std::string("/lib/") + |
83 | 0 | std::string(*FamilyName)); |
84 | 0 | getFilePaths().push_back(GCCRoot + std::string("/") + |
85 | 0 | std::string(*FamilyName)); |
86 | 0 |
|
87 | 0 | LinkStdlib = true; |
88 | 0 | } |
89 | 3 | } |
90 | 5 | |
91 | 5 | if (!LinkStdlib) |
92 | 5 | D.Diag(diag::warn_drv_avr_stdlib_not_linked); |
93 | 5 | } |
94 | 7 | } |
95 | | |
96 | 7 | Tool *AVRToolChain::buildLinker() const { |
97 | 7 | return new tools::AVR::Linker(getTriple(), *this, LinkStdlib); |
98 | 7 | } |
99 | | |
100 | | void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, |
101 | | const InputInfo &Output, |
102 | | const InputInfoList &Inputs, |
103 | | const ArgList &Args, |
104 | 7 | const char *LinkingOutput) const { |
105 | 7 | // Compute information about the target AVR. |
106 | 7 | std::string CPU = getCPUName(Args, getToolChain().getTriple()); |
107 | 7 | llvm::Optional<StringRef> FamilyName = GetMcuFamilyName(CPU); |
108 | 7 | |
109 | 7 | std::string Linker = getToolChain().GetProgramPath(getShortName()); |
110 | 7 | ArgStringList CmdArgs; |
111 | 7 | AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); |
112 | 7 | |
113 | 7 | CmdArgs.push_back("-o"); |
114 | 7 | CmdArgs.push_back(Output.getFilename()); |
115 | 7 | |
116 | 7 | // Enable garbage collection of unused sections. |
117 | 7 | CmdArgs.push_back("--gc-sections"); |
118 | 7 | |
119 | 7 | // Add library search paths before we specify libraries. |
120 | 7 | Args.AddAllArgs(CmdArgs, options::OPT_L); |
121 | 7 | getToolChain().AddFilePathLibArgs(Args, CmdArgs); |
122 | 7 | |
123 | 7 | // If the family name is known, we can link with the device-specific libgcc. |
124 | 7 | // Without it, libgcc will simply not be linked. This matches avr-gcc |
125 | 7 | // behavior. |
126 | 7 | if (LinkStdlib) { |
127 | 0 | assert(!CPU.empty() && "CPU name must be known in order to link stdlibs"); |
128 | 0 |
|
129 | 0 | // Add the object file for the CRT. |
130 | 0 | std::string CrtFileName = std::string("-l:crt") + CPU + std::string(".o"); |
131 | 0 | CmdArgs.push_back(Args.MakeArgString(CrtFileName)); |
132 | 0 |
|
133 | 0 | CmdArgs.push_back("-lgcc"); |
134 | 0 | CmdArgs.push_back("-lm"); |
135 | 0 | CmdArgs.push_back("-lc"); |
136 | 0 |
|
137 | 0 | // Add the link library specific to the MCU. |
138 | 0 | CmdArgs.push_back(Args.MakeArgString(std::string("-l") + CPU)); |
139 | 0 |
|
140 | 0 | // Specify the family name as the emulation mode to use. |
141 | 0 | // This is almost always required because otherwise avr-ld |
142 | 0 | // will assume 'avr2' and warn about the program being larger |
143 | 0 | // than the bare minimum supports. |
144 | 0 | CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName)); |
145 | 0 | } |
146 | 7 | |
147 | 7 | C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), |
148 | 7 | CmdArgs, Inputs)); |
149 | 7 | } |
150 | | |
151 | 3 | llvm::Optional<std::string> AVRToolChain::findAVRLibcInstallation() const { |
152 | 6 | for (StringRef PossiblePath : PossibleAVRLibcLocations) { |
153 | 6 | // Return the first avr-libc installation that exists. |
154 | 6 | if (llvm::sys::fs::is_directory(PossiblePath)) |
155 | 0 | return Optional<std::string>(std::string(PossiblePath)); |
156 | 6 | } |
157 | 3 | |
158 | 3 | return llvm::None; |
159 | 3 | } |