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 28 using namespace alone; 29 30 //===----------------------------------------------------------------------===// 31 // Compiler Options 32 //===----------------------------------------------------------------------===// 33 #ifdef TARGET_BUILD 34 static const std::string OptTargetTriple(DEFAULT_TARGET_TRIPLE_STRING); 35 #else 36 static llvm::cl::opt<std::string> 37 OptTargetTriple("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 43 static 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 //===----------------------------------------------------------------------===// 58 static llvm::cl::opt<std::string> 59 OptOutputFilename("o", 60 llvm::cl::desc("Output filename"), 61 llvm::cl::value_desc("filename")); 62 63 static llvm::cl::opt<std::string> 64 OptSysRoot("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 70 static llvm::cl::list<std::string> 71 OptSearchDirList("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 79 static llvm::cl::opt<std::string> 80 OptSOName("soname", 81 llvm::cl::desc("Set internal name of shared library"), 82 llvm::cl::value_desc("name")); 83 84 85 static llvm::cl::opt<bool> 86 OptShared("shared", 87 llvm::cl::desc("Create a shared library."), 88 llvm::cl::init(false)); 89 90 static llvm::cl::opt<bool> 91 OptBsymbolic("Bsymbolic", 92 llvm::cl::desc("Bind references within the shared library."), 93 llvm::cl::init(true)); 94 95 static llvm::cl::opt<std::string> 96 OptDyld("dynamic-linker", 97 llvm::cl::desc("Set the name of the dynamic linker."), 98 llvm::cl::value_desc("Program")); 99 100 static llvm::cl::opt<bool> 101 OptRelocatable("relocatable", 102 llvm::cl::desc("Generate relocatable output"), 103 llvm::cl::init(false)); 104 105 static llvm::cl::alias 106 OptRelocatableAlias("r", 107 llvm::cl::desc("alias for --relocatable"), 108 llvm::cl::aliasopt(OptRelocatable)); 109 110 static llvm::cl::opt<bool> 111 OptDefineCommon("d", 112 llvm::cl::ZeroOrMore, 113 llvm::cl::desc("Define common symbol"), 114 llvm::cl::init(false)); 115 116 static llvm::cl::alias 117 OptDefineCommonAlias1("dc", 118 llvm::cl::desc("alias for -d"), 119 llvm::cl::aliasopt(OptDefineCommon)); 120 121 static llvm::cl::alias 122 OptDefineCommonAlias2("dp", 123 llvm::cl::desc("alias for -d"), 124 llvm::cl::aliasopt(OptDefineCommon)); 125 126 127 //===----------------------------------------------------------------------===// 128 // Inputs 129 //===----------------------------------------------------------------------===// 130 static llvm::cl::list<std::string> 131 OptInputObjectFiles(llvm::cl::Positional, 132 llvm::cl::desc("[input object files]"), 133 llvm::cl::OneOrMore); 134 135 static llvm::cl::list<std::string> 136 OptNameSpecList("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 //===----------------------------------------------------------------------===// 146 static llvm::cl::list<std::string> 147 OptWrapList("wrap", 148 llvm::cl::ZeroOrMore, 149 llvm::cl::desc("Use a wrap function fo symbol."), 150 llvm::cl::value_desc("symbol")); 151 152 static llvm::cl::list<std::string> 153 OptPortableList("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" 162 static 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" 176 static inline 177 std::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 205 static inline 206 bool 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 275 static inline 276 bool 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 337 static 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 347 int 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