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