当前位置: 首页>>代码示例>>C++>>正文


C++ opt::getValue方法代码示例

本文整理汇总了C++中cl::opt::getValue方法的典型用法代码示例。如果您正苦于以下问题:C++ opt::getValue方法的具体用法?C++ opt::getValue怎么用?C++ opt::getValue使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在cl::opt的用法示例。


在下文中一共展示了opt::getValue方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。

示例1: ImmutablePass

// Out of line constructor provides default values for pass options and
// registers all common codegen passes.
TargetPassConfig::TargetPassConfig(LLVMTargetMachine &TM, PassManagerBase &pm)
    : ImmutablePass(ID), PM(&pm), TM(&TM) {
  Impl = new PassConfigImpl();

  // Register all target independent codegen passes to activate their PassIDs,
  // including this pass itself.
  initializeCodeGen(*PassRegistry::getPassRegistry());

  // Also register alias analysis passes required by codegen passes.
  initializeBasicAAWrapperPassPass(*PassRegistry::getPassRegistry());
  initializeAAResultsWrapperPassPass(*PassRegistry::getPassRegistry());

  if (StringRef(PrintMachineInstrs.getValue()).equals(""))
    TM.Options.PrintMachineCode = true;

  if (EnableIPRA.getNumOccurrences())
    TM.Options.EnableIPRA = EnableIPRA;
  else {
    // If not explicitly specified, use target default.
    TM.Options.EnableIPRA |= TM.useIPRA();
  }

  if (TM.Options.EnableIPRA)
    setRequiresCodeGenSCCOrder();

  if (EnableGlobalISelAbort.getNumOccurrences())
    TM.Options.GlobalISelAbort = EnableGlobalISelAbort;

  setStartStopPasses();
}
开发者ID:jamboree,项目名称:llvm,代码行数:32,代码来源:TargetPassConfig.cpp

示例2: main

int main(int argc, char **argv) {

  sys::PrintStackTraceOnErrorSignal();
  llvm::PrettyStackTraceProgram X(argc, argv);

  llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
  LLVMContext &Context = getGlobalContext();

  cl::ParseCommandLineOptions(argc, argv, "Bitcode strip tool\n");

  int input_fd = open(InputFilename.c_str(), O_RDONLY);

  unsigned char *wrapper = NULL;
  char *bitcode = NULL;

  // Read bitcode wrapper
  size_t bitcode_size = 0;
  size_t wrapper_size = ReadBitcodeWrapper(input_fd, &wrapper, bitcode_size);

  // Read bitcode
  bitcode = (char*) calloc(1, bitcode_size);
  size_t nread = read(input_fd, (void*) bitcode, bitcode_size);
  if (nread != bitcode_size) {
    errs() << "Could not read bitcode\n";
    return 1;
  }

  // Strip bitcode
  std::string BCString;
  StripBitcode(bitcode, bitcode_size, BCString, Context);

  // Update bitcode size
  WriteInt32(wrapper, 12, BCString.length());

  // Default to input filename
  if (OutputFilename.empty())
    OutputFilename.getValue() = InputFilename;

  // Output stripped bitcode
  std::error_code EC;
  tool_output_file Out(OutputFilename.c_str(), EC, sys::fs::F_None);
  if (EC) {
    errs() << EC.message() << '\n';
    return 1;
  }

  Out.os().write((const char *) wrapper, wrapper_size);
  Out.os().write(BCString.c_str(), BCString.length());
  Out.keep();

  // Clean up
  free((void *) wrapper);
  free((void *) bitcode);
  close(input_fd);

  return 0;
}
开发者ID:crystax,项目名称:android-toolchain-llvm-3-7,代码行数:57,代码来源:ndk-strip.cpp

示例3: main

int main(int argc, const char **argv) {
    CommonOptionsParser OptionsParser(argc, argv, NoGlobalStyleCategory);
    ClangTool Tool(OptionsParser.getCompilations(),
                   OptionsParser.getSourcePathList());
    
    MatchFinder finder;

    // Snarf abstract-only namespaces from the environment.
    std::vector<std::string> abstract_namespaces_v, banned_namespaces_v;
    std::copy(abstract_namespaces.begin(), abstract_namespaces.end(), std::back_inserter(abstract_namespaces_v));
    std::copy(banned_namespaces.begin(), banned_namespaces.end(), std::back_inserter(banned_namespaces_v));
    std::unique_ptr<RuleCheckerBase> rules[] = {
        make_unique<DisallowNew>(),
        make_unique<DisallowDelete>(),
        make_unique<DisallowGlobals>(),
        make_unique<DisallowNonAbstract>(abstract_namespaces_v),
        make_unique<DisallowCoupling>(banned_namespaces_v)
    };
    size_t rules_size = sizeof(rules) / sizeof(rules[0]);
    auto rules_begin = &rules[0];
    auto rules_end = &rules[rules_size];

    std::vector<std::string> analyze_paths_v;
    std::copy(analyze_paths.begin(), analyze_paths.end(), std::back_inserter(analyze_paths_v));

    for (size_t i = 0; i < sizeof(rules) / sizeof(rules[0]); ++i) {
        auto &rule = rules[i];
        rule->setAnalyzePaths(analyze_paths_v);
        rule->SetupMatches(finder);
        rule->getPrinter().setDebug(Debug.getValue());
    }
    
#ifndef NDEBUG
    llvm::DebugFlag = Debug.getValue();
#endif

    return Tool.run(newFrontendActionFactory(&finder).get()) || 
        (Werror.getValue() && 
         std::any_of
         (rules_begin, rules_end, 
          [] (const std::unique_ptr<RuleCheckerBase> &rule) {
             return rule->getPrinter().getWarnings();
         }));
}
开发者ID:prozacchiwawa,项目名称:clang-tooling-style,代码行数:44,代码来源:tool.cpp

示例4: initialize

/*!
 * Initialization of pointer analysis
 */
void PointerAnalysis::initialize(Module& module) {

    /// whether we have already built PAG
    if(pag == NULL) {

        /// run class hierarchy analysis
        chgraph = new CHGraph();
        chgraph->buildCHG(module);

        DBOUT(DGENERAL, outs() << pasMsg("Building Symbol table ...\n"));
        SymbolTableInfo* symTable = SymbolTableInfo::Symbolnfo();
        symTable->buildMemModel(module);

        DBOUT(DGENERAL, outs() << pasMsg("Building PAG ...\n"));
        if (!Graphtxt.getValue().empty()) {
            PAGBuilderFromFile fileBuilder(Graphtxt.getValue());
            pag = fileBuilder.build();

        } else {
            PAGBuilder builder;
            pag = builder.build(module);
        }

        // dump the PAG graph
        if (dumpGraph())
            PAG::getPAG()->dump("pag_initial");

        // print to command line of the PAG graph
        if (PAGPrint)
            pag->print();
    }

    typeSystem = new TypeSystem(pag);

    mod = &module;

    /// initialise pta call graph
    if(EnableThreadCallGraph)
        ptaCallGraph = new ThreadCallGraph(mod);
    else
        ptaCallGraph = new PTACallGraph(mod);
    callGraphSCCDetection();
}
开发者ID:dtzWill,项目名称:SVF,代码行数:46,代码来源:PointerAnalysis.cpp

示例5: runOnModule

bool TFA::runOnModule(Module &M) {
	if (Input.getValue() == llvm::cl::BOU_UNSET || Input.getValue()
			== llvm::cl::BOU_TRUE) {
		InputValues &IV = getAnalysis<InputValues> ();
		inputDepValues = IV.getInputDepValues();
	} else {
		InputDep &IV = getAnalysis<InputDep> ();
		inputDepValues = IV.getInputDepValues();
	}
	bSSA &bssa = getAnalysis<bSSA> ();
	depGraph = bssa.newGraph;
	DEBUG( // display dependence graph
	string Error;
	std::string tmp = M.getModuleIdentifier();
	replace(tmp.begin(), tmp.end(), '\\', '_');
	std::string Filename = "/tmp/" + tmp + ".dot";

	//Print dependency graph (in dot format)
	depGraph->toDot(M.getModuleIdentifier(), Filename);
	DisplayGraph(Filename, true, GraphProgram::DOT);
	);
开发者ID:dtzWill,项目名称:ecosoc,代码行数:21,代码来源:TFA.cpp

示例6: initTimers

void Executor::initTimers() {
  static bool first = true;

  if (first) {
    first = false;
    setupHandler();
  }

  if (MaxTime) {
    addTimer(new HaltTimer(this), MaxTime.getValue());
  }
}
开发者ID:HankFaan,项目名称:klee,代码行数:12,代码来源:ExecutorTimers.cpp

示例7: emitInlineHints

/// \brief Emit an inline hint if \p F is globally hot or cold.
///
/// If \p F consumes a significant fraction of samples (indicated by
/// SampleProfileGlobalHotThreshold), apply the InlineHint attribute for the
/// inliner to consider the function hot.
///
/// If \p F consumes a small fraction of samples (indicated by
/// SampleProfileGlobalColdThreshold), apply the Cold attribute for the inliner
/// to consider the function cold.
///
/// FIXME - This setting of inline hints is sub-optimal. Instead of marking a
/// function globally hot or cold, we should be annotating individual callsites.
/// This is not currently possible, but work on the inliner will eventually
/// provide this ability. See http://reviews.llvm.org/D15003 for details and
/// discussion.
///
/// \returns True if either attribute was applied to \p F.
bool SampleProfileLoader::emitInlineHints(Function &F) {
  if (TotalCollectedSamples == 0)
    return false;

  uint64_t FunctionSamples = Samples->getTotalSamples();
  double SamplesPercent =
      (double)FunctionSamples / (double)TotalCollectedSamples * 100.0;

  // If the function collected more samples than the hot threshold, mark
  // it globally hot.
  if (SamplesPercent >= SampleProfileGlobalHotThreshold) {
    F.addFnAttr(llvm::Attribute::InlineHint);
    std::string Msg;
    raw_string_ostream S(Msg);
    S << "Applied inline hint to globally hot function '" << F.getName()
      << "' with " << format("%.2f", SamplesPercent)
      << "% of samples (threshold: "
      << format("%.2f", SampleProfileGlobalHotThreshold.getValue()) << "%)";
    S.flush();
    emitOptimizationRemark(F.getContext(), DEBUG_TYPE, F, DebugLoc(), Msg);
    return true;
  }

  // If the function collected fewer samples than the cold threshold, mark
  // it globally cold.
  if (SamplesPercent <= SampleProfileGlobalColdThreshold) {
    F.addFnAttr(llvm::Attribute::Cold);
    std::string Msg;
    raw_string_ostream S(Msg);
    S << "Applied cold hint to globally cold function '" << F.getName()
      << "' with " << format("%.2f", SamplesPercent)
      << "% of samples (threshold: "
      << format("%.2f", SampleProfileGlobalColdThreshold.getValue()) << "%)";
    S.flush();
    emitOptimizationRemark(F.getContext(), DEBUG_TYPE, F, DebugLoc(), Msg);
    return true;
  }

  return false;
}
开发者ID:UWOS,项目名称:llvm,代码行数:57,代码来源:SampleProfile.cpp

示例8: if

// This checks whether the transformation is legal.
// Also returns false in cases where it's potentially legal, but
// we don't even want to try.
bool X86CallFrameOptimization::isLegal(MachineFunction &MF) {
  if (NoX86CFOpt.getValue())
    return false;

  // We currently only support call sequences where *all* parameters.
  // are passed on the stack.
  // No point in running this in 64-bit mode, since some arguments are
  // passed in-register in all common calling conventions, so the pattern
  // we're looking for will never match.
  if (STI->is64Bit())
    return false;

  // We can't encode multiple DW_CFA_GNU_args_size or DW_CFA_def_cfa_offset
  // in the compact unwind encoding that Darwin uses. So, bail if there
  // is a danger of that being generated.
  if (STI->isTargetDarwin() && 
     (!MF.getMMI().getLandingPads().empty() || 
       (MF.getFunction()->needsUnwindTableEntry() && !TFL->hasFP(MF))))
    return false;

  // You would expect straight-line code between call-frame setup and
  // call-frame destroy. You would be wrong. There are circumstances (e.g.
  // CMOV_GR8 expansion of a select that feeds a function call!) where we can
  // end up with the setup and the destroy in different basic blocks.
  // This is bad, and breaks SP adjustment.
  // So, check that all of the frames in the function are closed inside
  // the same block, and, for good measure, that there are no nested frames.
  unsigned FrameSetupOpcode = TII->getCallFrameSetupOpcode();
  unsigned FrameDestroyOpcode = TII->getCallFrameDestroyOpcode();
  for (MachineBasicBlock &BB : MF) {
    bool InsideFrameSequence = false;
    for (MachineInstr &MI : BB) {
      if (MI.getOpcode() == FrameSetupOpcode) {
        if (InsideFrameSequence)
          return false;
        InsideFrameSequence = true;
      } else if (MI.getOpcode() == FrameDestroyOpcode) {
        if (!InsideFrameSequence)
          return false;
        InsideFrameSequence = false;
      }
    }

    if (InsideFrameSequence)
      return false;
  }

  return true;
}
开发者ID:abeck99,项目名称:llvm,代码行数:52,代码来源:X86CallFrameOptimization.cpp

示例9: if

// This checks whether the transformation is legal.
// Also returns false in cases where it's potentially legal, but
// we don't even want to try.
bool X86CallFrameOptimization::isLegal(MachineFunction &MF) {
  if (NoX86CFOpt.getValue())
    return false;

  // We can't encode multiple DW_CFA_GNU_args_size or DW_CFA_def_cfa_offset
  // in the compact unwind encoding that Darwin uses. So, bail if there
  // is a danger of that being generated.
  if (STI->isTargetDarwin() &&
      (!MF.getLandingPads().empty() ||
       (MF.getFunction().needsUnwindTableEntry() && !TFL->hasFP(MF))))
    return false;

  // It is not valid to change the stack pointer outside the prolog/epilog
  // on 64-bit Windows.
  if (STI->isTargetWin64())
    return false;

  // You would expect straight-line code between call-frame setup and
  // call-frame destroy. You would be wrong. There are circumstances (e.g.
  // CMOV_GR8 expansion of a select that feeds a function call!) where we can
  // end up with the setup and the destroy in different basic blocks.
  // This is bad, and breaks SP adjustment.
  // So, check that all of the frames in the function are closed inside
  // the same block, and, for good measure, that there are no nested frames.
  unsigned FrameSetupOpcode = TII->getCallFrameSetupOpcode();
  unsigned FrameDestroyOpcode = TII->getCallFrameDestroyOpcode();
  for (MachineBasicBlock &BB : MF) {
    bool InsideFrameSequence = false;
    for (MachineInstr &MI : BB) {
      if (MI.getOpcode() == FrameSetupOpcode) {
        if (InsideFrameSequence)
          return false;
        InsideFrameSequence = true;
      } else if (MI.getOpcode() == FrameDestroyOpcode) {
        if (!InsideFrameSequence)
          return false;
        InsideFrameSequence = false;
      }
    }

    if (InsideFrameSequence)
      return false;
  }

  return true;
}
开发者ID:jamboree,项目名称:llvm,代码行数:49,代码来源:X86CallFrameOptimization.cpp

示例10: if

// This checks whether the transformation is legal.
// Also returns false in cases where it's potentially legal, but
// we don't even want to try.
bool X86CallFrameOptimization::isLegal(MachineFunction &MF) {
    if (NoX86CFOpt.getValue())
        return false;

    // We currently only support call sequences where *all* parameters.
    // are passed on the stack.
    // No point in running this in 64-bit mode, since some arguments are
    // passed in-register in all common calling conventions, so the pattern
    // we're looking for will never match.
    const X86Subtarget &STI = MF.getSubtarget<X86Subtarget>();
    if (STI.is64Bit())
        return false;

    // You would expect straight-line code between call-frame setup and
    // call-frame destroy. You would be wrong. There are circumstances (e.g.
    // CMOV_GR8 expansion of a select that feeds a function call!) where we can
    // end up with the setup and the destroy in different basic blocks.
    // This is bad, and breaks SP adjustment.
    // So, check that all of the frames in the function are closed inside
    // the same block, and, for good measure, that there are no nested frames.
    unsigned FrameSetupOpcode = TII->getCallFrameSetupOpcode();
    unsigned FrameDestroyOpcode = TII->getCallFrameDestroyOpcode();
    for (MachineBasicBlock &BB : MF) {
        bool InsideFrameSequence = false;
        for (MachineInstr &MI : BB) {
            if (MI.getOpcode() == FrameSetupOpcode) {
                if (InsideFrameSequence)
                    return false;
                InsideFrameSequence = true;
            } else if (MI.getOpcode() == FrameDestroyOpcode) {
                if (!InsideFrameSequence)
                    return false;
                InsideFrameSequence = false;
            }
        }

        if (InsideFrameSequence)
            return false;
    }

    return true;
}
开发者ID:Dagrol,项目名称:llvm,代码行数:45,代码来源:X86CallFrameOptimization.cpp

示例11: main

int main(int argc, const char *argv[]) {
  cl::ParseCommandLineOptions(argc, argv, "SPIR verifier");

  if (InputFilename.empty()) {
    errs() << HelpMessage;
    return 1;
  }

  StringRef Path = InputFilename;
  LLVMContext Ctx;
  OwningPtr<MemoryBuffer> result;

  // Parse the bitcode file into a module.
  error_code ErrCode = MemoryBuffer::getFile(Path, result);

  if (!result.get()) {
    errs() << "Buffer Creation Error. " << ErrCode.message() << "\n";
    return 1;
  }

  std::string ErrMsg;
  Module *M = ParseBitcodeFile(result.get(), Ctx, &ErrMsg);
  if (!M) {
    outs() << "According to this SPIR Verifier, " << Path << " is an invalid SPIR module.\n";
    errs() << "Bitcode parsing error. " << ErrMsg << "\n";
    return 1;
  }

  // Run the verification pass, and report errors if necessary.
  SpirValidation Validation;
  Validation.runOnModule(*M);
  const ErrorPrinter *EP = Validation.getErrorPrinter();
  if (EP->hasErrors()) {
    outs() << "According to this SPIR Verifier, " << Path << " is an invalid SPIR module.\n";
    errs() << "The module contains the following errors:\n\n";
    EP->print(errs(), LITMode.getValue());
    return 1;
  }

  outs() << "According to this SPIR Verifier, " << Path << " is a valid SPIR module.\n";
  return 0;
}
开发者ID:KhronosGroup,项目名称:SPIR-Tools,代码行数:42,代码来源:SpirVerifier.cpp

示例12: ImmutablePass

// Out of line constructor provides default values for pass options and
// registers all common codegen passes.
TargetPassConfig::TargetPassConfig(TargetMachine *tm, PassManagerBase &pm)
    : ImmutablePass(ID), PM(&pm), Started(true), Stopped(false),
      AddingMachinePasses(false), TM(tm), Impl(nullptr), Initialized(false),
      DisableVerify(false), EnableTailMerge(true) {

  Impl = new PassConfigImpl();

  // Register all target independent codegen passes to activate their PassIDs,
  // including this pass itself.
  initializeCodeGen(*PassRegistry::getPassRegistry());

  // Also register alias analysis passes required by codegen passes.
  initializeBasicAAWrapperPassPass(*PassRegistry::getPassRegistry());
  initializeAAResultsWrapperPassPass(*PassRegistry::getPassRegistry());

  // Substitute Pseudo Pass IDs for real ones.
  substitutePass(&EarlyTailDuplicateID, &TailDuplicateID);
  substitutePass(&PostRAMachineLICMID, &MachineLICMID);

  if (StringRef(PrintMachineInstrs.getValue()).equals(""))
    TM->Options.PrintMachineCode = true;
}
开发者ID:AstroVPK,项目名称:LLVM-4.0.0,代码行数:24,代码来源:TargetPassConfig.cpp

示例13: print

void RegionInfo::print(raw_ostream &OS, const Module *) const {
  OS << "Region tree:\n";
  TopLevelRegion->print(OS, true, 0, printStyle.getValue());
  OS << "End region tree\n";
}
开发者ID:Abocer,项目名称:android-4.2_r1,代码行数:5,代码来源:RegionInfo.cpp

示例14: dump

void Region::dump() const {
  print(dbgs(), true, getDepth(), printStyle.getValue());
}
开发者ID:Abocer,项目名称:android-4.2_r1,代码行数:3,代码来源:RegionInfo.cpp

示例15: addMachinePasses

/// Add the complete set of target-independent postISel code generator passes.
///
/// This can be read as the standard order of major LLVM CodeGen stages. Stages
/// with nontrivial configuration or multiple passes are broken out below in
/// add%Stage routines.
///
/// Any TargetPassConfig::addXX routine may be overriden by the Target. The
/// addPre/Post methods with empty header implementations allow injecting
/// target-specific fixups just before or after major stages. Additionally,
/// targets have the flexibility to change pass order within a stage by
/// overriding default implementation of add%Stage routines below. Each
/// technique has maintainability tradeoffs because alternate pass orders are
/// not well supported. addPre/Post works better if the target pass is easily
/// tied to a common pass. But if it has subtle dependencies on multiple passes,
/// the target should override the stage instead.
///
/// TODO: We could use a single addPre/Post(ID) hook to allow pass injection
/// before/after any target-independent pass. But it's currently overkill.
void TargetPassConfig::addMachinePasses() {
  // Insert a machine instr printer pass after the specified pass.
  // If -print-machineinstrs specified, print machineinstrs after all passes.
  if (StringRef(PrintMachineInstrs.getValue()).equals(""))
    TM->Options.PrintMachineCode = true;
  else if (!StringRef(PrintMachineInstrs.getValue())
           .equals("option-unspecified")) {
    const PassRegistry *PR = PassRegistry::getPassRegistry();
    const PassInfo *TPI = PR->getPassInfo(PrintMachineInstrs.getValue());
    const PassInfo *IPI = PR->getPassInfo(StringRef("print-machineinstrs"));
    assert (TPI && IPI && "Pass ID not registered!");
    const char *TID = (const char *)(TPI->getTypeInfo());
    const char *IID = (const char *)(IPI->getTypeInfo());
    insertPass(TID, IID);
  }

  // Print the instruction selected machine code...
  printAndVerify("After Instruction Selection");

  // Expand pseudo-instructions emitted by ISel.
  if (addPass(&ExpandISelPseudosID))
    printAndVerify("After ExpandISelPseudos");

  // Add passes that optimize machine instructions in SSA form.
  if (getOptLevel() != CodeGenOpt::None) {
    addMachineSSAOptimization();
  } else {
    // If the target requests it, assign local variables to stack slots relative
    // to one another and simplify frame index references where possible.
    addPass(&LocalStackSlotAllocationID);
  }

  // Run pre-ra passes.
  if (addPreRegAlloc())
    printAndVerify("After PreRegAlloc passes");

  // Run register allocation and passes that are tightly coupled with it,
  // including phi elimination and scheduling.
  if (getOptimizeRegAlloc())
    addOptimizedRegAlloc(createRegAllocPass(true));
  else
    addFastRegAlloc(createRegAllocPass(false));

  // Run post-ra passes.
  if (addPostRegAlloc())
    printAndVerify("After PostRegAlloc passes");

  // Insert prolog/epilog code.  Eliminate abstract frame index references...
  addPass(&PrologEpilogCodeInserterID);
  printAndVerify("After PrologEpilogCodeInserter");

  /// Add passes that optimize machine instructions after register allocation.
  if (getOptLevel() != CodeGenOpt::None)
    addMachineLateOptimization();

  // Expand pseudo instructions before second scheduling pass.
  addPass(&ExpandPostRAPseudosID);
  printAndVerify("After ExpandPostRAPseudos");

  // Run pre-sched2 passes.
  if (addPreSched2())
    printAndVerify("After PreSched2 passes");

  // Second pass scheduler.
  if (getOptLevel() != CodeGenOpt::None) {
    if (MISchedPostRA)
      addPass(&PostMachineSchedulerID);
    else
      addPass(&PostRASchedulerID);
    printAndVerify("After PostRAScheduler");
  }

  // GC
  if (addGCPasses()) {
    if (PrintGCInfo)
      addPass(createGCInfoPrinter(dbgs()));
  }

  // Basic block placement.
  if (getOptLevel() != CodeGenOpt::None)
    addBlockPlacement();

//.........这里部分代码省略.........
开发者ID:MrFredMiles,项目名称:llvm,代码行数:101,代码来源:Passes.cpp


注:本文中的cl::opt::getValue方法示例由纯净天空整理自Github/MSDocs等开源代码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。