blob: a1874d8a9c1a2eddf7f1b6c9956415eae9beb1a5 [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.
77StringRef canonicalizeInputFileName(StringRef path) {
78 if (llvm::sys::path::extension(path).empty())
79 return path.str() + ".obj";
80 return path;
81}
82
83// Replace a file extension with ".exe". If the given file has no
84// extension, just add ".exe".
85StringRef getDefaultOutputFileName(StringRef path) {
86 StringRef ext = llvm::sys::path::extension(path);
87 StringRef filename = ext.empty() ? path : path.drop_back(ext.size());
88 return filename.str() + ".exe";
89}
90
Rui Ueyama9e568392013-05-28 18:13:31 +000091} // namespace
92
93
94bool WinLinkDriver::linkPECOFF(int argc, const char *argv[],
95 raw_ostream &diagnostics) {
96 PECOFFTargetInfo info;
97 if (parse(argc, argv, info, diagnostics))
98 return true;
99 return link(info, diagnostics);
100}
101
102bool WinLinkDriver::parse(int argc, const char *argv[],
103 PECOFFTargetInfo &info, raw_ostream &diagnostics) {
104 // Arguments after "--" are interpreted as filenames even if they start with
105 // a hyphen or a slash. This is not compatible with link.exe but useful for
106 // us to test lld on Unix.
107 int doubleDashPosition = findDoubleDash(argc, argv);
108 int argEnd = (doubleDashPosition > 0) ? doubleDashPosition : argc;
109
110 // Parse command line options using WinLinkOptions.td
111 std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
112 WinLinkOptTable table;
113 unsigned missingIndex;
114 unsigned missingCount;
115 parsedArgs.reset(
116 table.ParseArgs(&argv[1], &argv[argEnd], missingIndex, missingCount));
117 if (missingCount) {
118 diagnostics << "error: missing arg value for '"
119 << parsedArgs->getArgString(missingIndex) << "' expected "
120 << missingCount << " argument(s).\n";
121 return true;
122 }
123
124 // Handle -help
125 if (parsedArgs->getLastArg(OPT_help)) {
126 table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
127 return true;
128 }
129
Rui Ueyama81247062013-05-29 05:07:49 +0000130 // Show warning for unknown arguments
131 for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN),
132 ie = parsedArgs->filtered_end(); it != ie; ++it) {
133 diagnostics << "warning: ignoring unknown argument: "
134 << (*it)->getAsString(*parsedArgs) << "\n";
135 }
136
Rui Ueyama9e568392013-05-28 18:13:31 +0000137 // Copy -mllvm
138 for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm),
139 ie = parsedArgs->filtered_end();
140 it != ie; ++it) {
141 info.appendLLVMOption((*it)->getValue());
142 }
143
Rui Ueyama81247062013-05-29 05:07:49 +0000144 // Handle -subsystem
145 if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_subsystem)) {
146 llvm::COFF::WindowsSubsystem subsystem = strToWinSubsystem(arg->getValue());
147 if (subsystem == llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN) {
148 diagnostics << "error: unknown subsystem name: "
149 << arg->getValue() << "\n";
150 return true;
151 }
152 info.setSubsystem(subsystem);
153 }
154
155 // Hanlde -out
156 if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_out))
157 info.setOutputPath(outpath->getValue());
158
Rui Ueyama9e568392013-05-28 18:13:31 +0000159 // Add input files
Rui Ueyamab33e8bc2013-05-30 06:00:10 +0000160 std::vector<StringRef> inputPaths;
Rui Ueyama9e568392013-05-28 18:13:31 +0000161 for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT),
162 ie = parsedArgs->filtered_end();
163 it != ie; ++it) {
Rui Ueyamab33e8bc2013-05-30 06:00:10 +0000164 inputPaths.push_back((*it)->getValue());
Rui Ueyama9e568392013-05-28 18:13:31 +0000165 }
166
167 // Arguments after "--" are also input files
168 if (doubleDashPosition > 0)
169 for (int i = doubleDashPosition + 1; i < argc; ++i)
Rui Ueyamab33e8bc2013-05-30 06:00:10 +0000170 inputPaths.push_back(argv[i]);
171
172 // Add ".obj" extension for those who have no file extension.
173 for (const StringRef &path : inputPaths)
174 info.appendInputFile(canonicalizeInputFileName(path));
175
176 // If -out option was not specified, the default output file name is
177 // constructed by replacing an extension with ".exe".
178 if (info.outputPath().empty() && !inputPaths.empty())
179 info.setOutputPath(getDefaultOutputFileName(inputPaths[0]));
Rui Ueyama9e568392013-05-28 18:13:31 +0000180
181 // Validate the combination of options used.
182 return info.validate(diagnostics);
183}
184
185} // namespace lld