blob: d6dc80b2dfeb1605d38274a31d450388441b9171 [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 Ueyama81247062013-05-29 05:07:49 +000016#include "llvm/ADT/StringSwitch.h"
Rui Ueyama9e568392013-05-28 18:13:31 +000017#include "llvm/Option/Arg.h"
18#include "llvm/Option/Option.h"
Rui Ueyamab33e8bc2013-05-30 06:00:10 +000019#include "llvm/Support/PathV2.h"
Rui Ueyama9e568392013-05-28 18:13:31 +000020
21#include "lld/Driver/Driver.h"
22#include "lld/ReaderWriter/PECOFFTargetInfo.h"
23
24namespace lld {
25
26namespace {
27
28// Create enum with OPT_xxx values for each option in WinLinkOptions.td
29enum WinLinkOpt {
30 OPT_INVALID = 0,
31#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \
32 OPT_##ID,
33#include "WinLinkOptions.inc"
34 LastOption
35#undef OPTION
36};
37
38// Create prefix string literals used in WinLinkOptions.td
39#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
40#include "WinLinkOptions.inc"
41#undef PREFIX
42
43// Create table mapping all options defined in WinLinkOptions.td
44static const llvm::opt::OptTable::Info infoTable[] = {
45#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
46 HELPTEXT, METAVAR) \
47 { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
48 PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS },
49#include "WinLinkOptions.inc"
50#undef OPTION
51};
52
53// Create OptTable class for parsing actual command line arguments
54class WinLinkOptTable : public llvm::opt::OptTable {
55public:
56 WinLinkOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
57};
58
59// Returns the index of "--" or -1 if not found.
60int findDoubleDash(int argc, const char *argv[]) {
61 for (int i = 0; i < argc; ++i)
62 if (std::strcmp(argv[i], "--") == 0)
63 return i;
64 return -1;
65}
66
Rui Ueyama81247062013-05-29 05:07:49 +000067// Parses -subsystem command line option.
68llvm::COFF::WindowsSubsystem strToWinSubsystem(std::string str) {
69 std::string arg(StringRef(str).lower());
70 return llvm::StringSwitch<llvm::COFF::WindowsSubsystem>(arg)
71 .Case("windows", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI)
72 .Case("console", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI)
73 .Default(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN);
74}
75
Rui Ueyamab33e8bc2013-05-30 06:00:10 +000076// Add ".obj" extension if the given path name has no file extension.
Rui Ueyama5f037592013-05-30 23:17:58 +000077std::string canonicalizeInputFileName(std::string path) {
Rui Ueyamab33e8bc2013-05-30 06:00:10 +000078 if (llvm::sys::path::extension(path).empty())
Rui Ueyama5f037592013-05-30 23:17:58 +000079 return path.append(".obj");
Rui Ueyamab33e8bc2013-05-30 06:00:10 +000080 return path;
81}
82
83// Replace a file extension with ".exe". If the given file has no
84// extension, just add ".exe".
Rui Ueyama5f037592013-05-30 23:17:58 +000085std::string getDefaultOutputFileName(std::string path) {
Rui Ueyamab33e8bc2013-05-30 06:00:10 +000086 StringRef ext = llvm::sys::path::extension(path);
Rui Ueyama5f037592013-05-30 23:17:58 +000087 if (!ext.empty())
88 path.erase(path.size() - ext.size());
89 return path.append(".exe");
Rui Ueyamab33e8bc2013-05-30 06:00:10 +000090}
91
Rui Ueyama9e568392013-05-28 18:13:31 +000092} // namespace
93
94
95bool WinLinkDriver::linkPECOFF(int argc, const char *argv[],
96 raw_ostream &diagnostics) {
97 PECOFFTargetInfo info;
98 if (parse(argc, argv, info, diagnostics))
99 return true;
100 return link(info, diagnostics);
101}
102
103bool WinLinkDriver::parse(int argc, const char *argv[],
104 PECOFFTargetInfo &info, raw_ostream &diagnostics) {
105 // Arguments after "--" are interpreted as filenames even if they start with
106 // a hyphen or a slash. This is not compatible with link.exe but useful for
107 // us to test lld on Unix.
108 int doubleDashPosition = findDoubleDash(argc, argv);
109 int argEnd = (doubleDashPosition > 0) ? doubleDashPosition : argc;
110
111 // Parse command line options using WinLinkOptions.td
112 std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
113 WinLinkOptTable table;
114 unsigned missingIndex;
115 unsigned missingCount;
116 parsedArgs.reset(
117 table.ParseArgs(&argv[1], &argv[argEnd], missingIndex, missingCount));
118 if (missingCount) {
119 diagnostics << "error: missing arg value for '"
120 << parsedArgs->getArgString(missingIndex) << "' expected "
121 << missingCount << " argument(s).\n";
122 return true;
123 }
124
125 // Handle -help
126 if (parsedArgs->getLastArg(OPT_help)) {
127 table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
128 return true;
129 }
130
Rui Ueyama81247062013-05-29 05:07:49 +0000131 // Show warning for unknown arguments
132 for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN),
133 ie = parsedArgs->filtered_end(); it != ie; ++it) {
134 diagnostics << "warning: ignoring unknown argument: "
135 << (*it)->getAsString(*parsedArgs) << "\n";
136 }
137
Rui Ueyama9e568392013-05-28 18:13:31 +0000138 // Copy -mllvm
139 for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm),
140 ie = parsedArgs->filtered_end();
141 it != ie; ++it) {
142 info.appendLLVMOption((*it)->getValue());
143 }
144
Rui Ueyama81247062013-05-29 05:07:49 +0000145 // Handle -subsystem
146 if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_subsystem)) {
147 llvm::COFF::WindowsSubsystem subsystem = strToWinSubsystem(arg->getValue());
148 if (subsystem == llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN) {
149 diagnostics << "error: unknown subsystem name: "
150 << arg->getValue() << "\n";
151 return true;
152 }
153 info.setSubsystem(subsystem);
154 }
155
156 // Hanlde -out
157 if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_out))
158 info.setOutputPath(outpath->getValue());
159
Rui Ueyama9e568392013-05-28 18:13:31 +0000160 // Add input files
Rui Ueyamab33e8bc2013-05-30 06:00:10 +0000161 std::vector<StringRef> inputPaths;
Rui Ueyama9e568392013-05-28 18:13:31 +0000162 for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT),
163 ie = parsedArgs->filtered_end();
164 it != ie; ++it) {
Rui Ueyamab33e8bc2013-05-30 06:00:10 +0000165 inputPaths.push_back((*it)->getValue());
Rui Ueyama9e568392013-05-28 18:13:31 +0000166 }
167
168 // Arguments after "--" are also input files
169 if (doubleDashPosition > 0)
170 for (int i = doubleDashPosition + 1; i < argc; ++i)
Rui Ueyamab33e8bc2013-05-30 06:00:10 +0000171 inputPaths.push_back(argv[i]);
172
173 // Add ".obj" extension for those who have no file extension.
174 for (const StringRef &path : inputPaths)
175 info.appendInputFile(canonicalizeInputFileName(path));
176
177 // If -out option was not specified, the default output file name is
178 // constructed by replacing an extension with ".exe".
179 if (info.outputPath().empty() && !inputPaths.empty())
180 info.setOutputPath(getDefaultOutputFileName(inputPaths[0]));
Rui Ueyama9e568392013-05-28 18:13:31 +0000181
182 // Validate the combination of options used.
183 return info.validate(diagnostics);
184}
185
186} // namespace lld