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