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 OptTargetTripe(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 100//===----------------------------------------------------------------------===// 101// Inputs 102//===----------------------------------------------------------------------===// 103static llvm::cl::list<std::string> 104OptInputObjectFiles(llvm::cl::Positional, 105 llvm::cl::desc("[input object files]"), 106 llvm::cl::OneOrMore); 107 108static llvm::cl::list<std::string> 109OptNameSpecList("l", 110 llvm::cl::ZeroOrMore, 111 llvm::cl::desc("Add the archive or object file specified by " 112 "namespec to the list of files to link."), 113 llvm::cl::value_desc("namespec"), 114 llvm::cl::Prefix); 115 116//===----------------------------------------------------------------------===// 117// Scripting Options 118//===----------------------------------------------------------------------===// 119static llvm::cl::list<std::string> 120OptWrapList("wrap", 121 llvm::cl::ZeroOrMore, 122 llvm::cl::desc("Use a wrap function fo symbol."), 123 llvm::cl::value_desc("symbol")); 124 125static llvm::cl::list<std::string> 126OptPortableList("portable", 127 llvm::cl::ZeroOrMore, 128 llvm::cl::desc("Use a portable function to symbol."), 129 llvm::cl::value_desc("symbol")); 130 131//===----------------------------------------------------------------------===// 132// Helper Functions 133//===----------------------------------------------------------------------===// 134// Override "mcld -version" 135static void MCLDVersionPrinter() { 136 llvm::raw_ostream &os = llvm::outs(); 137 os << "mcld (The MCLinker Project, http://mclinker.googlecode.com/):\n" 138 << " version: "MCLD_VERSION"\n" 139 << " Default target: " << DEFAULT_TARGET_TRIPLE_STRING << "\n"; 140 141 os << "\n"; 142 143 os << "LLVM (http://llvm.org/):\n"; 144 145 return; 146} 147 148#define DEFAULT_OUTPUT_PATH "a.out" 149static inline 150std::string DetermineOutputFilename(const std::string &pOutputPath) { 151 if (!pOutputPath.empty()) { 152 return pOutputPath; 153 } 154 155 // User does't specify the value to -o 156 if (OptInputObjectFiles.size() > 1) { 157 llvm::errs() << "Use " DEFAULT_OUTPUT_PATH " for output file!\n"; 158 return DEFAULT_OUTPUT_PATH; 159 } 160 161 // There's only one input file 162 const std::string &input_path = OptInputObjectFiles[0]; 163 llvm::SmallString<200> output_path(input_path); 164 165 llvm::error_code err = llvm::sys::fs::make_absolute(output_path); 166 if (llvm::errc::success != err) { 167 llvm::errs() << "Failed to determine the absolute path of `" << input_path 168 << "'! (detail: " << err.message() << ")\n"; 169 return ""; 170 } 171 172 llvm::sys::path::remove_filename(output_path); 173 llvm::sys::path::append(output_path, "a.out"); 174 175 return output_path.c_str(); 176} 177 178static inline 179bool ConfigLinker(Linker &pLinker, const std::string &pOutputFilename) { 180 LinkerConfig* config = NULL; 181 182#ifdef TARGET_BUILD 183 config = new (std::nothrow) DefaultLinkerConfig(); 184#else 185 config = new (std::nothrow) LinkerConfig(OptTargetTriple); 186#endif 187 if (config == NULL) { 188 llvm::errs() << "Out of memory when create the linker configuration!\n"; 189 return false; 190 } 191 192 // Setup the configuration accroding to the command line options. 193 194 // 1. Set up soname. 195 if (!OptSOName.empty()) { 196 config->setSOName(OptSOName); 197 } else { 198 config->setSOName(pOutputFilename); 199 } 200 201 // 2. If given, set up sysroot. 202 if (!OptSysRoot.empty()) { 203 config->setSysRoot(OptSysRoot); 204 } 205 206 // 3. If given, set up dynamic linker path. 207 if (!OptDyld.empty()) { 208 config->setDyld(OptDyld); 209 } 210 211 // 4. If given, set up wrapped symbols. 212 llvm::cl::list<std::string>::iterator wrap, wrap_end = OptWrapList.end(); 213 for (wrap = OptWrapList.begin(); wrap != wrap_end; ++wrap) { 214 config->addWrap(*wrap); 215 } 216 217 // 5. If given, set up portable symbols. 218 llvm::cl::list<std::string>::iterator portable, portable_end = OptPortableList.end(); 219 for (portable = OptPortableList.begin(); portable != portable_end; ++portable) { 220 config->addPortable(*portable); 221 } 222 223 // 6. if given, set up search directories. 224 llvm::cl::list<std::string>::iterator sdir, sdir_end = OptSearchDirList.end(); 225 for (sdir = OptSearchDirList.begin(); sdir != sdir_end; ++sdir) { 226 config->addSearchDir(*sdir); 227 } 228 229 // set up default search directories 230 config->addSearchDir("=/lib"); 231 config->addSearchDir("=/usr/lib"); 232 233 // 7. Set up output's type. 234 config->setShared(OptShared); 235 236 // 8. Set up -Bsymbolic. 237 config->setBsymbolic(OptBsymbolic); 238 239 Linker::ErrorCode result = pLinker.config(*config); 240 if (Linker::kSuccess != result) { 241 llvm::errs() << "Failed to configure the linker! (detail: " 242 << Linker::GetErrorString(result) << ")\n"; 243 return false; 244 } 245 246 return true; 247} 248 249static inline 250bool PrepareInputOutput(Linker &pLinker, const std::string &pOutputPath) { 251 // ----- Set output ----- // 252 253 // FIXME: Current MCLinker requires one to set up output before inputs. The 254 // constraint will be relaxed in the furture. 255 Linker::ErrorCode result = pLinker.setOutput(pOutputPath); 256 257 if (Linker::kSuccess != result) { 258 llvm::errs() << "Failed to open the output file! (detail: " 259 << pOutputPath << ": " 260 << Linker::GetErrorString(result) << ")\n"; 261 return false; 262 } 263 264 // ----- Set inputs ----- // 265 llvm::cl::list<std::string>::iterator file_it = OptInputObjectFiles.begin(); 266 llvm::cl::list<std::string>::iterator lib_it = OptNameSpecList.begin(); 267 268 llvm::cl::list<std::string>::iterator file_begin = OptInputObjectFiles.begin(); 269 llvm::cl::list<std::string>::iterator lib_begin = OptNameSpecList.begin(); 270 llvm::cl::list<std::string>::iterator file_end = OptInputObjectFiles.end(); 271 llvm::cl::list<std::string>::iterator lib_end = OptNameSpecList.end(); 272 273 unsigned lib_pos = 0, file_pos = 0; 274 while (true) { 275 if (lib_it != lib_end) { 276 lib_pos = OptNameSpecList.getPosition(lib_it - lib_begin); 277 } else { 278 lib_pos = 0; 279 } 280 281 if (file_it != file_end) { 282 file_pos = OptInputObjectFiles.getPosition(file_it - file_begin); 283 } else { 284 file_pos = 0; 285 } 286 287 if ((file_pos != 0) && ((lib_pos == 0) || (file_pos < lib_pos))) { 288 result = pLinker.addObject(*file_it); 289 if (Linker::kSuccess != result) { 290 llvm::errs() << "Failed to open the input file! (detail: " << *file_it 291 << ": " << Linker::GetErrorString(result) << ")\n"; 292 return false; 293 } 294 ++file_it; 295 } else if ((lib_pos != 0) && ((file_pos == 0) || (lib_pos < file_pos))) { 296 result = pLinker.addNameSpec(*lib_it); 297 if (Linker::kSuccess != result) { 298 llvm::errs() << "Failed to open the namespec! (detail: " << *lib_it 299 << ": " << Linker::GetErrorString(result) << ")\n"; 300 return false; 301 } 302 ++lib_it; 303 } else { 304 break; // we're done with the list 305 } 306 } 307 308 return true; 309} 310 311static inline bool LinkFiles(Linker &pLinker) { 312 Linker::ErrorCode result = pLinker.link(); 313 if (Linker::kSuccess != result) { 314 llvm::errs() << "Failed to linking! (detail: " 315 << Linker::GetErrorString(result) << "\n"; 316 return false; 317 } 318 return true; 319} 320 321int main(int argc, char** argv) { 322 llvm::cl::SetVersionPrinter(MCLDVersionPrinter); 323 llvm::cl::ParseCommandLineOptions(argc, argv); 324 init::Initialize(); 325 326 std::string OutputFilename = DetermineOutputFilename(OptOutputFilename); 327 if (OutputFilename.empty()) { 328 return EXIT_FAILURE; 329 } 330 331 Linker linker; 332 if (!ConfigLinker(linker, OutputFilename)) { 333 return EXIT_FAILURE; 334 } 335 336 if (!PrepareInputOutput(linker, OutputFilename)) { 337 return EXIT_FAILURE; 338 } 339 340 if (!LinkFiles(linker)) { 341 return EXIT_FAILURE; 342 } 343 344 return EXIT_SUCCESS; 345} 346 347