main.cpp revision affc150dc44fab1911775a49636d0ce85333b634
1//===- mcld.cpp -----------------------------------------------------------===// 2// 3// The MCLinker Project 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9#include <stdlib.h> 10#include <string> 11 12#include <llvm/ADT/SmallString.h> 13#include <llvm/Support/CommandLine.h> 14#include <llvm/Support/FileSystem.h> 15#include <llvm/Support/Path.h> 16#include <llvm/Support/raw_ostream.h> 17#include <llvm/Support/system_error.h> 18 19#include <alone/Config/Config.h> 20#include <alone/Support/LinkerConfig.h> 21#include <alone/Support/Initialization.h> 22#include <alone/Support/TargetLinkerConfigs.h> 23#include <alone/Linker.h> 24 25using namespace alone; 26 27//===----------------------------------------------------------------------===// 28// Compiler Options 29//===----------------------------------------------------------------------===// 30#ifdef TARGET_BUILD 31const std::string OptTargetTripe(DEFAULT_TARGET_TRIPLE_STRING); 32#else 33llvm::cl::opt<std::string> 34OptTargetTriple("mtriple", 35 llvm::cl::desc("Specify the target triple (default: " 36 DEFAULT_TARGET_TRIPLE_STRING ")"), 37 llvm::cl::init(DEFAULT_TARGET_TRIPLE_STRING), 38 llvm::cl::value_desc("triple")); 39 40llvm::cl::alias OptTargetTripleC("C", llvm::cl::NotHidden, 41 llvm::cl::desc("Alias for -mtriple"), 42 llvm::cl::aliasopt(OptTargetTriple)); 43#endif 44 45//===----------------------------------------------------------------------===// 46// Command Line Options 47// There are four kinds of command line options: 48// 1. input, (may be a file, such as -m and /tmp/XXXX.o.) 49// 2. scripting options, (represent a subset of link scripting language, such 50// as --defsym.) 51// 3. and general options. (the rest of options) 52//===----------------------------------------------------------------------===// 53// General Options 54//===----------------------------------------------------------------------===// 55static llvm::cl::opt<std::string> 56OptOutputFilename("o", 57 llvm::cl::desc("Output filename"), 58 llvm::cl::value_desc("filename")); 59 60static llvm::cl::opt<std::string> 61OptSysRoot("sysroot", 62 llvm::cl::desc("Use directory as the location of the sysroot, overriding " 63 "the configure-time default."), 64 llvm::cl::value_desc("directory"), 65 llvm::cl::ValueRequired); 66 67static llvm::cl::list<std::string> 68OptSearchDirList("L", 69 llvm::cl::ZeroOrMore, 70 llvm::cl::desc("Add path searchdir to the list of paths that ld will " 71 "search for archive libraries and ld control scripts."), 72 llvm::cl::value_desc("searchdir"), 73 llvm::cl::Prefix); 74 75static llvm::cl::opt<std::string> 76OptSOName("soname", 77 llvm::cl::desc("Set internal name of shared library"), 78 llvm::cl::value_desc("name")); 79 80 81static llvm::cl::opt<bool> 82OptShared("shared", 83 llvm::cl::desc("Create a shared library."), 84 llvm::cl::init(false)); 85 86static llvm::cl::opt<std::string> 87OptDyld("dynamic-linker", 88 llvm::cl::desc("Set the name of the dynamic linker."), 89 llvm::cl::value_desc("Program")); 90 91//===----------------------------------------------------------------------===// 92// Inputs 93//===----------------------------------------------------------------------===// 94static llvm::cl::list<std::string> 95OptInputObjectFiles(llvm::cl::Positional, 96 llvm::cl::desc("[input object files]"), 97 llvm::cl::ZeroOrMore); 98 99static llvm::cl::list<std::string> 100OptNameSpecList("l", 101 llvm::cl::ZeroOrMore, 102 llvm::cl::desc("Add the archive or object file specified by " 103 "namespec to the list of files to link."), 104 llvm::cl::value_desc("namespec"), 105 llvm::cl::Prefix); 106 107//===----------------------------------------------------------------------===// 108// Scripting Options 109//===----------------------------------------------------------------------===// 110static llvm::cl::list<std::string> 111OptWrapList("wrap", 112 llvm::cl::ZeroOrMore, 113 llvm::cl::desc("Use a wrap function fo symbol."), 114 llvm::cl::value_desc("symbol")); 115 116//===----------------------------------------------------------------------===// 117// Helper Functions 118//===----------------------------------------------------------------------===// 119// Override "mcld -version" 120void MCLDVersionPrinter() { 121 llvm::raw_ostream &os = llvm::outs(); 122 os << "mcld (The MCLinker Project, http://mclinker.googlecode.com/):\n" 123 << " Default target: " << DEFAULT_TARGET_TRIPLE_STRING << "\n"; 124 125 os << "\n"; 126 127 os << "LLVM (http://llvm.org/):\n"; 128 return; 129} 130 131#define DEFAULT_OUTPUT_PATH "a.out" 132static inline 133std::string DetermineOutputFilename(const std::string pOutputPath) 134{ 135 if (!pOutputPath.empty()) { 136 return pOutputPath; 137 } 138 139 // User does't specify the value to -o 140 if (OptInputObjectFiles.size() > 1) { 141 llvm::errs() << "Use " DEFAULT_OUTPUT_PATH " for output file!\n"; 142 return DEFAULT_OUTPUT_PATH; 143 } 144 145 // There's only one input file 146 const std::string &input_path = OptInputObjectFiles[0]; 147 llvm::SmallString<200> output_path(input_path); 148 149 llvm::error_code err = llvm::sys::fs::make_absolute(output_path); 150 if (llvm::errc::success != err) { 151 llvm::errs() << "Failed to determine the absolute path of `" << input_path 152 << "'! (detail: " << err.message() << ")\n"; 153 return ""; 154 } 155 156 llvm::sys::path::remove_filename(output_path); 157 llvm::sys::path::append(output_path, "a.out"); 158 159 return output_path.c_str(); 160} 161 162static inline 163bool ConfigLinker(Linker &pLinker, const std::string &pOutputFilename) 164{ 165 LinkerConfig* config = NULL; 166 167#ifdef TARGET_BUILD 168 config = new (std::nothrow) DefaultLinkerConfig(); 169#else 170 config = new (std::nothrow) LinkerConfig(OptTargetTriple); 171#endif 172 if (config == NULL) { 173 llvm::errs() << "Out of memory when create the linker configuration!\n"; 174 return false; 175 } 176 177 // Setup the configuration accroding to the value of command line options. 178 // 1. set up soname 179 if (!OptSOName.empty()) 180 config->setSOName(OptSOName); 181 else 182 config->setSOName(pOutputFilename); 183 184 // 2. if given, set up sysroot 185 if (!OptSysRoot.empty()) 186 config->setSysRoot(OptSysRoot); 187 188 // 3. if given, set up dynamic linker path. 189 if (!OptDyld.empty()) 190 config->setDyld(OptDyld); 191 192 // 4. if given, set up wrapped symbols 193 llvm::cl::list<std::string>::iterator wrap, wEnd = OptWrapList.end(); 194 for (wrap = OptWrapList.begin(); wrap != wEnd; ++wrap) 195 config->addWrap(*wrap); 196 197 // 5. if given, set up search directories 198 llvm::cl::list<std::string>::iterator sdir, sdirEnd = OptSearchDirList.end(); 199 for (sdir = OptSearchDirList.begin(); sdir != sdirEnd; ++sdir) 200 config->addSearchDir(*sdir); 201 202 Linker::ErrorCode result = pLinker.config(*config); 203 204 if (Linker::kSuccess != result) { 205 llvm::errs() << "Failed to configure the linker! (detail: " 206 << Linker::GetErrorString(result) << ")\n"; 207 return false; 208 } 209 210 return true; 211} 212 213static inline 214bool PrepareInputOutput(Linker& pLinker, const std::string &pOutputPath) 215{ 216 // ----- set output ----- // 217 // FIXME: In MCLinker, we have to set up output before setting up inputs. 218 // This constraint is wired, and we should break this constraint. 219 Linker::ErrorCode result = pLinker.setOutput(pOutputPath); 220 221 if (Linker::kSuccess != result) { 222 llvm::errs() << "Failed to open the output file! (detail: " 223 << pOutputPath << ": " 224 << Linker::GetErrorString(result) << ")\n"; 225 return false; 226 } 227 228 // ----- set inputs ----- // 229 llvm::cl::list<std::string>::iterator fileIt = OptInputObjectFiles.begin(); 230 llvm::cl::list<std::string>::iterator libIt = OptNameSpecList.begin(); 231 232 llvm::cl::list<std::string>::iterator fileBegin = OptInputObjectFiles.begin(); 233 llvm::cl::list<std::string>::iterator libBegin = OptNameSpecList.begin(); 234 llvm::cl::list<std::string>::iterator fileEnd = OptInputObjectFiles.end(); 235 llvm::cl::list<std::string>::iterator libEnd = OptNameSpecList.end(); 236 237 unsigned libPos = 0, filePos = 0; 238 while (true) { 239 if (libIt != libEnd) 240 libPos = OptNameSpecList.getPosition(libIt - libBegin); 241 else 242 libPos = 0; 243 244 if (fileIt != fileEnd) 245 filePos = OptInputObjectFiles.getPosition(fileIt - fileBegin); 246 else 247 filePos = 0; 248 249 if ( filePos != 0 && (libPos == 0 || filePos < libPos) ) { 250 result = pLinker.addObject(*fileIt); 251 if (Linker::kSuccess != result) { 252 llvm::errs() << "Failed to open the input file! (detail: " 253 << *fileIt << ": " 254 << Linker::GetErrorString(result) << ")\n"; 255 return false; 256 } 257 ++fileIt; 258 } 259 else if ( libPos != 0 && (filePos == 0 || libPos < filePos) ) { 260 result = pLinker.addNameSpec(*libIt); 261 if (Linker::kSuccess != result) { 262 llvm::errs() << "Failed to open the namespec! (detail: " 263 << *libIt << ": " 264 << Linker::GetErrorString(result) << ")\n"; 265 return false; 266 } 267 ++libIt; 268 } 269 270 else 271 break; // we're done with the list 272 } 273 274 return true; 275} 276 277static inline 278bool LinkFiles(Linker& pLinker) { 279 Linker::ErrorCode result = pLinker.link(); 280 if (Linker::kSuccess != result) { 281 llvm::errs() << "Failed to linking! (detail: " 282 << Linker::GetErrorString(result) << "\n"; 283 return false; 284 } 285 return true; 286} 287 288int main(int argc, char* argv[]) 289{ 290 llvm::cl::SetVersionPrinter(MCLDVersionPrinter); 291 llvm::cl::ParseCommandLineOptions(argc, argv); 292 init::Initialize(); 293 294 std::string OutputFilename = DetermineOutputFilename(OptOutputFilename); 295 if (OutputFilename.empty()) { 296 return EXIT_FAILURE; 297 } 298 299 Linker linker; 300 if (!ConfigLinker(linker, OutputFilename)) { 301 return EXIT_FAILURE; 302 } 303 304 if (!PrepareInputOutput(linker, OutputFilename)) { 305 return EXIT_FAILURE; 306 } 307 308 if (!LinkFiles(linker)) { 309 return EXIT_FAILURE; 310 } 311 return EXIT_SUCCESS; 312} 313 314