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