blob: 7bdbd4928a0141888590ebd00e99b6fc24110d1e [file] [log] [blame]
Rui Ueyama9e568392013-05-28 18:13:31 +00001//===- lib/Driver/WinLinkDriver.cpp ---------------------------------------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11///
12/// Concrete instance of the Driver for Windows link.exe.
13///
14//===----------------------------------------------------------------------===//
15
Rui Ueyamace42bcc2013-05-31 06:30:10 +000016#include <cstdlib>
17
Rui Ueyama81247062013-05-29 05:07:49 +000018#include "llvm/ADT/StringSwitch.h"
Rui Ueyama9e568392013-05-28 18:13:31 +000019#include "llvm/Option/Arg.h"
20#include "llvm/Option/Option.h"
Rui Ueyamab33e8bc2013-05-30 06:00:10 +000021#include "llvm/Support/PathV2.h"
Rui Ueyama9e568392013-05-28 18:13:31 +000022
23#include "lld/Driver/Driver.h"
24#include "lld/ReaderWriter/PECOFFTargetInfo.h"
25
26namespace lld {
27
28namespace {
29
30// Create enum with OPT_xxx values for each option in WinLinkOptions.td
31enum WinLinkOpt {
32 OPT_INVALID = 0,
33#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \
34 OPT_##ID,
35#include "WinLinkOptions.inc"
36 LastOption
37#undef OPTION
38};
39
40// Create prefix string literals used in WinLinkOptions.td
41#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
42#include "WinLinkOptions.inc"
43#undef PREFIX
44
45// Create table mapping all options defined in WinLinkOptions.td
46static const llvm::opt::OptTable::Info infoTable[] = {
47#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
48 HELPTEXT, METAVAR) \
49 { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
50 PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS },
51#include "WinLinkOptions.inc"
52#undef OPTION
53};
54
55// Create OptTable class for parsing actual command line arguments
56class WinLinkOptTable : public llvm::opt::OptTable {
57public:
58 WinLinkOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
59};
60
61// Returns the index of "--" or -1 if not found.
62int findDoubleDash(int argc, const char *argv[]) {
63 for (int i = 0; i < argc; ++i)
64 if (std::strcmp(argv[i], "--") == 0)
65 return i;
66 return -1;
67}
68
Rui Ueyamace42bcc2013-05-31 06:30:10 +000069// Returns subsystem type for the given string.
70llvm::COFF::WindowsSubsystem stringToWinSubsystem(StringRef str) {
71 std::string arg(str.lower());
Rui Ueyama81247062013-05-29 05:07:49 +000072 return llvm::StringSwitch<llvm::COFF::WindowsSubsystem>(arg)
73 .Case("windows", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI)
74 .Case("console", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI)
75 .Default(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN);
76}
77
Rui Ueyamace42bcc2013-05-31 06:30:10 +000078
79// Displays error message if the given version does not match with
80// /^\d+$/.
81bool checkOSVersion(StringRef version, const char *errorMessage,
82 raw_ostream &diagnostics) {
83 if (version.str().find_first_not_of("0123456789") != std::string::npos
84 || version.empty()) {
85 diagnostics << "error: " << errorMessage << version << "\n";
86 return false;
87 }
88 return true;
89}
90
91bool parseMinOSVersion(PECOFFTargetInfo &info, StringRef &osVersion,
92 raw_ostream &diagnostics) {
93 StringRef majorVersion, minorVersion;
94 llvm::tie(majorVersion, minorVersion) = osVersion.split('.');
95 if (minorVersion.empty())
96 minorVersion = "0";
97 if (!checkOSVersion(majorVersion, "invalid OS major version: ", diagnostics))
98 return false;
99 if (!checkOSVersion(minorVersion, "invalid OS minor version: ", diagnostics))
100 return false;
101 PECOFFTargetInfo::OSVersion minOSVersion(atoi(majorVersion.str().c_str()),
102 atoi(minorVersion.str().c_str()));
103 info.setMinOSVersion(minOSVersion);
104 return true;
105}
106
107// Parse -subsystem command line option. The form of -subsystem is
Rui Ueyamafeaa72a2013-05-31 22:08:30 +0000108// "subsystem_name[,majorOSVersion[.minorOSVersion]]".
Rui Ueyamace42bcc2013-05-31 06:30:10 +0000109bool parseSubsystemOption(PECOFFTargetInfo &info, std::string arg,
110 raw_ostream &diagnostics) {
111 StringRef subsystemStr, osVersionStr;
112 llvm::tie(subsystemStr, osVersionStr) = StringRef(arg).split(',');
113
114 // Parse optional OS version if exists.
115 if (!osVersionStr.empty())
116 if (!parseMinOSVersion(info, osVersionStr, diagnostics))
117 return false;
118
119 // Parse subsystem name.
120 llvm::COFF::WindowsSubsystem subsystem = stringToWinSubsystem(subsystemStr);
121 if (subsystem == llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN) {
122 diagnostics << "error: unknown subsystem name: " << subsystemStr << "\n";
123 return false;
124 }
125 info.setSubsystem(subsystem);
126 return true;
127}
128
Rui Ueyamab33e8bc2013-05-30 06:00:10 +0000129// Add ".obj" extension if the given path name has no file extension.
Rui Ueyama5f037592013-05-30 23:17:58 +0000130std::string canonicalizeInputFileName(std::string path) {
Rui Ueyamab33e8bc2013-05-30 06:00:10 +0000131 if (llvm::sys::path::extension(path).empty())
Rui Ueyama5f037592013-05-30 23:17:58 +0000132 return path.append(".obj");
Rui Ueyamab33e8bc2013-05-30 06:00:10 +0000133 return path;
134}
135
136// Replace a file extension with ".exe". If the given file has no
137// extension, just add ".exe".
Rui Ueyama5f037592013-05-30 23:17:58 +0000138std::string getDefaultOutputFileName(std::string path) {
Rui Ueyamab33e8bc2013-05-30 06:00:10 +0000139 StringRef ext = llvm::sys::path::extension(path);
Rui Ueyama5f037592013-05-30 23:17:58 +0000140 if (!ext.empty())
141 path.erase(path.size() - ext.size());
142 return path.append(".exe");
Rui Ueyamab33e8bc2013-05-30 06:00:10 +0000143}
144
Rui Ueyama9e568392013-05-28 18:13:31 +0000145} // namespace
146
147
148bool WinLinkDriver::linkPECOFF(int argc, const char *argv[],
149 raw_ostream &diagnostics) {
150 PECOFFTargetInfo info;
151 if (parse(argc, argv, info, diagnostics))
152 return true;
153 return link(info, diagnostics);
154}
155
156bool WinLinkDriver::parse(int argc, const char *argv[],
157 PECOFFTargetInfo &info, raw_ostream &diagnostics) {
158 // Arguments after "--" are interpreted as filenames even if they start with
159 // a hyphen or a slash. This is not compatible with link.exe but useful for
160 // us to test lld on Unix.
161 int doubleDashPosition = findDoubleDash(argc, argv);
162 int argEnd = (doubleDashPosition > 0) ? doubleDashPosition : argc;
163
164 // Parse command line options using WinLinkOptions.td
165 std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
166 WinLinkOptTable table;
167 unsigned missingIndex;
168 unsigned missingCount;
169 parsedArgs.reset(
170 table.ParseArgs(&argv[1], &argv[argEnd], missingIndex, missingCount));
171 if (missingCount) {
172 diagnostics << "error: missing arg value for '"
173 << parsedArgs->getArgString(missingIndex) << "' expected "
174 << missingCount << " argument(s).\n";
175 return true;
176 }
177
178 // Handle -help
179 if (parsedArgs->getLastArg(OPT_help)) {
180 table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
181 return true;
182 }
183
Rui Ueyama81247062013-05-29 05:07:49 +0000184 // Show warning for unknown arguments
185 for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN),
186 ie = parsedArgs->filtered_end(); it != ie; ++it) {
187 diagnostics << "warning: ignoring unknown argument: "
188 << (*it)->getAsString(*parsedArgs) << "\n";
189 }
190
Rui Ueyama9e568392013-05-28 18:13:31 +0000191 // Copy -mllvm
192 for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm),
193 ie = parsedArgs->filtered_end();
194 it != ie; ++it) {
195 info.appendLLVMOption((*it)->getValue());
196 }
197
Rui Ueyama81247062013-05-29 05:07:49 +0000198 // Handle -subsystem
Rui Ueyamace42bcc2013-05-31 06:30:10 +0000199 if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_subsystem))
200 if (!parseSubsystemOption(info, arg->getValue(), diagnostics))
Rui Ueyama81247062013-05-29 05:07:49 +0000201 return true;
Rui Ueyama81247062013-05-29 05:07:49 +0000202
Rui Ueyama739730e2013-05-31 19:34:29 +0000203 // Handle -entry
204 if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_entry))
205 info.setEntrySymbolName(arg->getValue());
206
Rui Ueyama81247062013-05-29 05:07:49 +0000207 // Hanlde -out
208 if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_out))
209 info.setOutputPath(outpath->getValue());
210
Rui Ueyama9e568392013-05-28 18:13:31 +0000211 // Add input files
Rui Ueyamab33e8bc2013-05-30 06:00:10 +0000212 std::vector<StringRef> inputPaths;
Rui Ueyama9e568392013-05-28 18:13:31 +0000213 for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT),
214 ie = parsedArgs->filtered_end();
215 it != ie; ++it) {
Rui Ueyamab33e8bc2013-05-30 06:00:10 +0000216 inputPaths.push_back((*it)->getValue());
Rui Ueyama9e568392013-05-28 18:13:31 +0000217 }
218
219 // Arguments after "--" are also input files
220 if (doubleDashPosition > 0)
221 for (int i = doubleDashPosition + 1; i < argc; ++i)
Rui Ueyamab33e8bc2013-05-30 06:00:10 +0000222 inputPaths.push_back(argv[i]);
223
224 // Add ".obj" extension for those who have no file extension.
225 for (const StringRef &path : inputPaths)
226 info.appendInputFile(canonicalizeInputFileName(path));
227
228 // If -out option was not specified, the default output file name is
229 // constructed by replacing an extension with ".exe".
230 if (info.outputPath().empty() && !inputPaths.empty())
231 info.setOutputPath(getDefaultOutputFileName(inputPaths[0]));
Rui Ueyama9e568392013-05-28 18:13:31 +0000232
233 // Validate the combination of options used.
234 return info.validate(diagnostics);
235}
236
237} // namespace lld