æè¿ã次ã®ããªãŒãã«ãã·ã¹ãã ãéžãã§ãããã®ãããªã·ã¹ãã ãèªåã§äœ¿çšããããšã¯å¯èœã§ããïŒ çµå±ã®ãšãããããã¯ç°¡åã§ã-åãå¿è ãåããååŠçãšã³ã³ãã€ã«ã«åé¢ããã蟌ã¿ããããã¯ãŒã¯äžã§ãã¡ã€ã«ãããåãããŸãã ã©ã®ãããç°¡åã§ããïŒã
ã·ã³ãã«-ãã®ãããªã·ã¹ãã ãèªåã§äœãæ¹æ³ã ãã§ãªããç°¡åã«èª¬æããŸãã
ã¹ããŒãž0ãåé¡ã®èª¬æ
å 責äºé ïŒãã®èšäºã¯ãã¥ãŒããªã¢ã«ãšããŠããŒã¯ãããŠããŸãããããã¯å®å šãªã¹ããããã€ã¹ãããã®ã¬ã€ãã§ã¯ãªããå®æåã®ã³ãŒããã³ããŒãããã®ã§ãã ããã¯ããå€ãã®æ瀺ã§ã-èšç»æ¹æ³ãšæãå Žæã
æåã«ãäœæ¥ã®äžè¬çãªã¢ã«ãŽãªãºã ã決å®ããŸãã
- ã¢ã»ã³ããªã°ã©ããèªã¿åããã³ã³ãã€ã«ã³ãã³ããåé¢ããŸãã
- ã³ã³ãã€ã«ã¯ãååŠçãšã³ãŒãçæã®2ã€ã®æ®µéã«åããããŸãã åŸè ããªã¢ãŒãå®è¡ã®ããã«å¯èœãªéãããŒã¯ããŸãã
- ååŠçãå®è¡ããçµæãã¡ã¢ãªã«èªã¿èŸŒã¿ãŸãã
- ååŠçããããã¡ã€ã«ãšããããã¯ãŒã¯çµç±ã§å¥ã®ãã¹ãã«ã³ãŒããçæããã³ãã³ããéä¿¡ããŸãã
- ã³ãŒãçæã³ãã³ããå®è¡ãããªããžã§ã¯ããã¡ã€ã«ãèªã¿åãããããã¯ãŒã¯çµç±ã§å¿çãšããŠæäŸããŸãã
- çµæã®ãªããžã§ã¯ããã¡ã€ã«ã¯ãã£ã¹ã¯ã«ä¿åãããã³ã³ãã€ã©ã®ã³ã³ãœãŒã«ã¡ãã»ãŒãžã«è¡šç€ºãããŸãã
ããã»ã©æããªãããã§ããã ãããããã®ãã¹ãŠãæžãããã«ããã«å€æ¹ã«ã¯ããããããåäœããŸããã æåã«ãããã€ãã®ãããã¿ã€ããäœæããèšäºã§ãããã«ã€ããŠèª¬æããŸãã
- ãããã¿ã€ã1ãããã°ã©ã ã¯ã³ã³ãã€ã©ãŒãæš¡å£ããã³ãã³ãã2ã€ã«åå²ããã³ã³ãã€ã©ãŒãåå¥ã«åŒã³åºããŸãã
- ãããã¿ã€ã2ãããã«ããã¡ã€ã«èªäœã䜿çšããã«ããããã¯ãŒã¯çµç±ã§ã³ã³ãã€ã«ããã³ãã³ãã®è»¢éãè¿œå ããŸãã
- ãããã¿ã€ã3ãå£ããå¯èœæ§ã®ããã³ãã³ãã衚瀺ããNinjaãã«ãã°ã©ããèŠãŠã¿ãŸãããã
ã©ã€ãã©ãªã䜿çšããªãå Žåã¯ãPOSIXäºæOSã§ãããã¿ã€ãã®éçºãè¡ãããšããå§ãããŸãã
æé 1.ã³ãã³ãã©ã€ã³ã解é€ãã
ãããã¿ã€ãã«ã€ããŠã¯ãGCCã³ã³ãã€ã©ãŒïŒãŸãã¯Clangãããã»ã©éãã¯ãããŸããïŒã«çŠç¹ãåœãŠãŸãã ãã®ã³ãã³ãã©ã€ã³ã¯è§£æãç°¡åã§ãã
ã³ãã³ããtest -c hello.cpp -o hello.oãã䜿çšããŠããã°ã©ã ãåŒã³åºããŸãããã ã-cãã¹ã€ããïŒãªããžã§ã¯ãã³ãŒããžã®ã³ã³ãã€ã«ïŒã®åŸãå ¥åãã¡ã€ã«ã®ååã¯åžžã«ç¶ããšä»®å®ããŸãããããã§ã¯ãããŸããã ãŸããåœé¢ã¯ãããŒã«ã«ãã£ã¬ã¯ããªã§ã®äœæ¥ã®ã¿ã«å°å¿µããŸãã
popené¢æ°ã䜿çšããŠããã»ã¹ãéå§ããæšæºåºåãååŸããŸãã ãã®é¢æ°ã䜿çšãããšããã¡ã€ã«ãéãã®ãšåãæ¹æ³ã§ããã»ã¹ãéãããšãã§ããŸãã
Main.cppãã¡ã€ã«ïŒ
#include <iostream> #include "InvocationRewriter.hpp" #include "LocalExecutor.hpp" int main(int argc, char ** argv) { StringVector args; for (int i = 1; i < argc; ++i) args.emplace_back(argv[i]); InvocationRewriter rewriter; StringVector ppArgs, ccArgs; // . if (!rewriter.SplitInvocation(args, ppArgs, ccArgs)) { std::cerr << "Usage: -c <filename> -o <filename> \n"; return 1; } LocalExecutor localExecutor; const std::string cxxExecutable = "/usr/bin/g++"; // , GNU/Linux. const auto ppResult = localExecutor.Execute(cxxExecutable, ppArgs); if (!ppResult.m_result) { std::cerr << ppResult.m_output; return 1; } const auto ccResult = localExecutor.Execute(cxxExecutable, ccArgs); if (!ccResult.m_result) { std::cerr << ccResult.m_output; return 1; } // , , . return 0; }
InvocationRewriter.hppã³ãŒã
#pragma once #include <string> #include <vector> #include <algorithm> using StringVector = std::vector<std::string>; class InvocationRewriter { public: bool SplitInvocation(const StringVector & original, StringVector & preprocessor, StringVector & compilation) { // -c -o. // , -c , . const auto cIter = std::find(original.cbegin(), original.cend(), "-c"); const auto oIter = std::find(original.cbegin(), original.cend(), "-o"); if (cIter == original.cend() || oIter == original.cend()) return false; const auto cIndex = cIter - original.cbegin(); const auto oIndex = oIter - original.cbegin(); preprocessor = compilation = original; const std::string & inputFilename = original[cIndex + 1]; preprocessor[oIndex + 1] = "pp_" + inputFilename; // preprocessor[cIndex] = "-E"; // - . compilation[cIndex + 1] = "pp_" + inputFilename; return true; } };
LocalExecutor.hppã³ãŒã
#pragma once #include <string> #include <vector> #include <algorithm> #include <stdio.h> using StringVector = std::vector<std::string>; class LocalExecutor { public: /// : + struct ExecutorResult { std::string m_output; bool m_result = false; ExecutorResult(const std::string & output = "", bool result = false) : m_output(output), m_result(result) {} }; /// popen. ExecutorResult Execute(const std::string & executable, const StringVector & args) { std::string cmd = executable; for (const auto & arg : args) cmd += " " + arg; cmd += " 2>&1"; // sterr stdout. FILE * process = popen(cmd.c_str(), "r"); if (!process) return ExecutorResult("Failed to execute:" + cmd); ExecutorResult result; char buffer[1024]; while (fgets(buffer, sizeof(buffer)-1, process) != nullptr) result.m_output += std::string(buffer); result.m_result = pclose(process) == 0; return result; } };
ããŠãä»ã§ã¯å®éã®ã³ã³ãã€ã©ãåŒã£åŒµãå°ããªã³ã³ãã€ã©ãšãã¥ã¬ãŒã¿ããããŸãã ããã«é²ã:)
ãããã¿ã€ãã®ãããªãéçºïŒ
- 絶察ãã¡ã€ã«åãèæ ®ããŠãã ããã
- ããã»ã¹ã®æäœã«ã¯ãBoost.ProcessãQProcessããŸãã¯Ninja Subprocessã®ããããã®ã©ã€ãã©ãªãŒã䜿çšããŸãã
- MSVCã®ã³ãã³ãåé¢ãµããŒããå®è£ ããŸãã
- ã³ãã³ããéåæã§å®è¡ããããã®APIãäœæããå¥ã®ã¹ã¬ããã§å®è¡ãå®è¡ããŸãã
ã¹ããŒãž2.ãããã¯ãŒã¯ãµãã·ã¹ãã
BSDãœã±ããïŒ Berkeley Sockets ïŒã§ãããã¯ãŒã¯äº€æã®ãããã¿ã€ããäœæããŸã
ã¡ãã£ãšããçè«ïŒ
ãœã±ããã¯æåéããç©Žãã§ãããããã«ããŒã¿ãæžã蟌ãã ãããããèªã¿èŸŒãã ãã§ããŸãã ãªã¢ãŒããµãŒããŒã«æ¥ç¶ããããã®ã¢ã«ãŽãªãºã ã¯æ¬¡ã®ãšããã§ãã
- socketïŒïŒé¢æ°ã䜿çšããŠãå¿ èŠãªã¿ã€ãïŒTCPïŒã®ãœã±ãããäœæããŸãã
- äœæåŸãsetsockoptïŒïŒã䜿çšããŠãéããããã³ã°ã¢ãŒããªã©ã®å¿ èŠãªãã©ã°ãèšå®ããŸãã
- getaddrinfoïŒïŒã䜿çšããŠãBSDãœã±ããã«å¿ èŠãªåœ¢åŒã§ã¢ãã¬ã¹ãååŸããŸãã
- connectïŒïŒé¢æ°ã䜿çšããŠTCPãã¹ãã«æ¥ç¶ããæºåãããã¢ãã¬ã¹ãããã«æž¡ããŸãã
- èªã¿åãããã³æžã蟌ã¿çšã®èªã¿åã/éä¿¡é¢æ°ãåŒã³åºããŸãã
- äœæ¥ãçµäºããããcloseïŒïŒãåŒã³åºããŸãã
ãµãŒããŒã¯å°ãé£ãããªããŸãïŒ
- socketïŒïŒé¢æ°ã䜿çšããŠãœã±ãããäœæããŸãã
- ãªãã·ã§ã³ãå ¬éããŸãã
- bindïŒïŒãåŒã³åºããŠããœã±ãããç¹å®ã®ã¢ãã¬ã¹ã«ãã€ã³ãããŸãïŒgetaddrinfoããååŸïŒ
- listenïŒïŒãåŒã³åºããŠããŒãã®ãªãã¹ã³ãéå§ããŸãã
- acceptïŒïŒé¢æ°ã䜿çšããŠçä¿¡æ¥ç¶ãåãå ¥ããŸã-æ°ãããœã±ãããè¿ããŸãã
- åä¿¡ãããœã±ããã䜿çšããŠãèªã¿åã/æžã蟌ã¿æäœãå®è¡ããŸãã
- æ¥ç¶ãœã±ãããšçèŽãœã±ãããéããïŒïŒã§éããŸãã
ãœã±ããã¯ã©ã€ã¢ã³ããšãœã±ãããµãŒããŒãå¿ èŠã§ãã ã€ã³ã¿ãŒãã§ã€ã¹ã次ã®ããã«ããŸãã
/// class IDataSocket { public: using Ptr = std::shared_ptr<IDataSocket>; /// . Success- , TryAgain - , Fail - . enum class WriteState { Success, TryAgain, Fail }; enum class ReadState { Success, TryAgain, Fail }; public: virtual ~IDataSocket() = default; /// virtual bool Connect () = 0; /// virtual void Disconnect () = 0; /// - ; virtual bool IsConnected () const = 0; virtual bool IsPending() const = 0; /// virtual ReadState Read(ByteArrayHolder & buffer) = 0; /// . virtual WriteState Write(const ByteArrayHolder & buffer, size_t maxBytes = size_t(-1)) = 0; }; /// "". . class IDataListener { public: using Ptr = std::shared_ptr<IDataListener>; virtual ~IDataListener() = default; /// virtual IDataSocket::Ptr GetPendingConnection() = 0; /// : virtual bool StartListen() = 0; };
ãã®ã€ã³ã¿ãŒãã§ã€ã¹ã®å®è£ ãèšäºã«åã蟌ãããšã¯ããŸãããèªåã§å®è£ ãããã ããã§èŠããŠã¿ãŠãã ãã ã
ãœã±ããã®æºåãã§ããŠãããšããŸããããã¯ã©ã€ã¢ã³ããšã³ã³ãã€ã©ãµãŒããŒã¯ã©ã®ããã«èŠããŸããïŒ
ãµãŒããŒïŒ
#include <TcpListener.h> #include <algorithm> #include <iostream> #include "LocalExecutor.hpp" int main() { // . TcpConnectionParams tcpParams; tcpParams.SetPoint(6666, "localhost"); // 6666; auto listener = TcpListener::Create(tcpParams); IDataSocket::Ptr connection; // ; while((connection = listener->GetPendingConnection()) == nullptr) ; // . connection->Connect(); ByteArrayHolder incomingBuffer; //!< std::vector<uint8_t>; while (connection->Read(incomingBuffer) == IDataSocket::ReadState::TryAgain) ; // , , . std::string args((const char*)(incomingBuffer.data()), incomingBuffer.size()); std::replace(args.begin(), args.end(), '\n', ' '); LocalExecutor localExecutor; const auto result = localExecutor.Execute("/usr/bin/g++", StringVector(1, args)); std::string stdOutput = result.m_output; if (stdOutput.empty()) stdOutput = "OK\n"; // - , OK. // . ByteArrayHolder outgoingBuffer; std::copy(stdOutput.cbegin(), stdOutput.cend(), std::back_inserter(outgoingBuffer.ref())); connection->Write(outgoingBuffer); connection->Disconnect(); // , . // / . return 0; }
顧客ïŒ
#include <iostream> #include <TcpSocket.h> #include "InvocationRewriter.hpp" #include "LocalExecutor.hpp" int main(int argc, char ** argv) { StringVector args; for (int i = 1; i < argc; ++i) args.emplace_back(argv[i]); InvocationRewriter rewriter; StringVector ppArgs, ccArgs; // . if (!rewriter.SplitInvocation(args, ppArgs, ccArgs)) { std::cerr << "Usage: -c <filename> -o <filename> \n"; return 1; } LocalExecutor localExecutor; const std::string cxxExecutable = "/usr/bin/g++"; // , GNU/Linux. const auto ppResult = localExecutor.Execute(cxxExecutable, ppArgs); if (!ppResult.m_result) { std::cerr << ppResult.m_output; return 1; } // 6666 TcpConnectionParams tcpParams; tcpParams.SetPoint(6666, "localhost"); auto connection = TcpSocket::Create(tcpParams); connection->Connect(); ByteArrayHolder outgoingBuffer; for (auto arg : ccArgs) { arg += " "; // . std::copy(arg.cbegin(), arg.cend(), std::back_inserter(outgoingBuffer.ref())); } connection->Write(outgoingBuffer); ByteArrayHolder incomingBuffer; while (connection->Read(incomingBuffer) == IDataSocket::ReadState::TryAgain) ; std::string response((const char*)(incomingBuffer.data()), incomingBuffer.size()); if (response != "OK\n") { std::cerr << response; return 1; } return 0; }
ã¯ãããã¹ãŠã®ãœãŒã¹ïŒTcpConnectionParamsãByteArrayHolderãªã©ïŒã衚瀺ãããããã§ã¯ãããŸãããããããã¯ããªãåå§çãªæ§é ã§ãã
ãã®ãããã¿ã€ãããããã°ããåŸãååŠçããããã¡ã€ã«ãããŒã«ã«ã§ã³ã³ãã€ã«ã§ããå°ããªãµãŒãã¹ããããŸãïŒããšãã°ãã¯ã©ã€ã¢ã³ããšãµãŒããŒã®äœæ¥ãã£ã¬ã¯ããªãåãã§ãããšããä»®å®ã®äžã§ïŒã
ãããã¿ã€ãã®ãããªãéçºïŒ
- æ¢åã®ãããã¯ãŒã¯ã©ã€ãã©ãªã®1ã€ã§ããBoost.AsioãQTcpSocketïŒQtNetworkïŒã䜿çšããããšã匷ããå§ãããŸããProtobufãŸãã¯ä»ã®åæ§ã®ã©ã€ãã©ãªã䜿çšããã·ãªã¢ã«åãæ€èšããŠãã ãã
- ãããã¯ãŒã¯ãä»ãããã¡ã€ã«è»¢éãå®è£ ããŸãã ã»ãšãã©ã®å Žåããããããã©ã°ã¡ã³ãã«åå²ããå¿ èŠããããŸãããéžæããã©ã€ãã©ãªã«äŸåããŸãã
- éåæã¡ãã»ãŒãžã®éåä¿¡APIã«ã€ããŠèããå¿ èŠããããŸãã ããã«ãæœè±¡åãããœã±ããã«ãŸã£ããçµã³ä»ããªãããã«ããããšãæãŸããã§ãã
ã¹ããŒãž3.ãã³ãžã£ãšã®çµ±å
å§ããã«ã¯ãNinjaã®ååãç解ããå¿ èŠããããŸãã ãã®å©ããåããŠãããžã§ã¯ããæ¢ã«åéããŠãããbuild.ninjaãã©ã®ããã«èŠãããã«ã€ããŠããçšåºŠã®ç¥èãããããšãåæãšãªã£ãŠããŸãã
䜿çšãããæŠå¿µïŒ
- ããŒãã¯åãªããã¡ã€ã«ã§ãã å ¥åïŒãœãŒã¹ïŒãåºåïŒãªããžã§ã¯ããã¡ã€ã«ïŒ-ãããã¯ãã¹ãŠã°ã©ãã®ããŒããŸãã¯é ç¹ã§ãã
- ã«ãŒã«-ããã¯åºæ¬çã«ãåŒæ°ãã³ãã¬ãŒãã䜿çšããåãªãã³ãã³ãã§ãã ããšãã°ãgccã®åŒã³åºãã¯ã«ãŒã«ã§ããããã®åŒæ°ã¯$ FLAGS $ INCLUDES $ DEFINESããã³ãã®ä»ã®äžè¬çãªåŒæ°ã§ãã
- ãšããž ç§ã«ã¯å°ãé©ããŸãããããšããžã¯ã«ãŒã«ãä»ããŠ2ã€ã®ããŒãã§ã¯ãªããè€æ°ã®å ¥åããŒããš1ã€ã®åºåããŒããæ¥ç¶ããŸãã ã¢ã»ã³ããªã·ã¹ãã å šäœã¯ããšããžã®ã³ãã³ããå®è¡ããããšã«ãããã°ã©ããé 次走æ»ããããšã«åºã¥ããŠããŸãã ãã¹ãŠã®ãªããåŠçããããšããããžã§ã¯ããçµã¿ç«ãŠãããŸãã
- ç¶æ ã¯ããã«ãã·ã¹ãã ã䜿çšããäžèšã®ãã¹ãŠãåããã³ã³ããã§ãã
äŸåé¢ä¿ãæããšã©ããªããŸããïŒ
ããã¯ãã¢ããªã±ãŒã·ã§ã³ã«ã³ã³ãã€ã«ããã2ã€ã®ç¿»èš³åäœã®ã¢ã»ã³ããªã°ã©ãã瀺ããŠããŸãã
ã芧ã®ãšããããã«ãã·ã¹ãã ã«å€æŽãå ããã«ã¯ãEdgeãé©åãªå Žæã§2ã€ã«åå²ããæ°ããããŒãïŒååŠçæžã¿ãã¡ã€ã«ïŒãè¿œå ããŠãç¶æ ãæžãæããå¿ èŠããããŸãã
ãã§ã«å¿è ã®ãœãŒã¹ããããããããåéãããã¹ãŠãæ©èœããŠãããšä»®å®ããŸãã
次ã®ã³ãŒãã¹ãããããninja.ccã«è¿œå ããŸãã
// Limit number of rebuilds, to prevent infinite loops. const int kCycleLimit = 100; for (int cycle = 1; cycle <= kCycleLimit; ++cycle) { NinjaMain ninja(ninja_command, config); ManifestParser parser(&ninja.state_, &ninja.disk_interface_, options.dupe_edges_should_err ? kDupeEdgeActionError : kDupeEdgeActionWarn); string err; if (!parser.Load(options.input_file, &err)) { Error("%s", err.c_str()); return 1; } // , : RewriteStateRules(&ninja.state_); //
RewriteStateRulesé¢æ°èªäœã¯ã次ã®ããã«ninja.ccã§å¥ã®ãã¡ã€ã«ã«åã蟌ãããããã§å®£èšã§ããŸãã
#include "InvocationRewriter.hpp" // , Ninja. struct RuleReplace { const Rule* pp; const Rule* cc; std::string toolId; RuleReplace() = default; RuleReplace(const Rule* pp_, const Rule* cc_, std::string id) : pp(pp_), cc(cc_), toolId(id) {} }; void RewriteStateRules(State *state) { // , .. , . const auto rules = state->bindings_.GetRules(); std::map<const Rule*, RuleReplace> ruleReplacement; InvocationRewriter rewriter; // for (const auto & ruleIt : rules) { const Rule * rule = ruleIt.second; const EvalString* command = rule->GetBinding("command"); if (!command) continue; // rewriter-. std::vector<std::string> originalRule; for (const auto & strPair : command->parsed_) { std::string str = strPair.first; if (strPair.second == EvalString::SPECIAL) str = '$' + str; originalRule.push_back(str); } // : std::vector<std::string> preprocessRule, compileRule; if (rewriter.SplitInvocation(originalRule, preprocessRule, compileRule)) { // 2 rule - rulePP ruleCC, bindings_ . // ruleReplacement (ruleReplacement[rule] = ...) } } const auto paths = state->paths_; std::set<Edge*> erasedEdges; // for (const auto & iter : paths) { Node* node = iter.second; Edge* in_egde = node->in_edge(); if (!in_egde) continue; // . // , : const Rule * in_rule = &(in_egde->rule()); auto replacementIt = ruleReplacement.find(in_rule); if (replacementIt != ruleReplacement.end()) { RuleReplace replacement = replacementIt->second; const std::string objectPath = node->path(); const std::string sourcePath = in_egde->inputs_[0]->path(); const std::string ppPath = sourcePath + ".pp"; // . Node *pp_node = state->GetNode(ppPath, node->slash_bits()); // Edge* edge_pp = state->AddEdge(replacement.pp); Edge* edge_cc = state->AddEdge(replacement.cc); // ... ... // edge_pp; // edge_cc // pp_node. // , edge_cc, - // , : edge_cc->is_remote_ = true; // , . in_egde->outputs_.clear(); in_egde->inputs_.clear(); in_egde->env_ = nullptr; erasedEdges.insert(in_egde); } } // . vector<Edge*> newEdges; for (auto * edge : state->edges_) { if (erasedEdges.find(edge) == erasedEdges.end()) newEdges.push_back(edge); } state->edges_ = newEdges; }
ããã€ãã®éå±ãªæçãåãåãããŠããŸã ãå®å šãªã³ãŒãã¯ãã¡ãã§ç¢ºèªã§ããŸã ã
ãããã¿ã€ãã®æ¹è¯ïŒ
- ã»ãšãã©ã®å Žåãæåã®ãªãã·ã§ã³InvocationRewriterã¯æ©èœããŸãããå€ãã®ããšãèæ ®ããå¿ èŠããããŸããããšãã°ãã³ã³ãã€ã«åŒæ° "-c"ã "-c"ã§æå®ã§ãããšããäºå®ã¯ããœãŒã¹ãã¡ã€ã«ã®åã«ãããšã¯éããŸããã
- äžéšã®ãã¡ã€ã«ãããŒã¯ããè¿œå ã®ãã©ã°ãå€æ°ããå Žåããããããããã©ã°ã§ã¯ãªãããã¹ãŠããã¡ã€ã«ã§ãããšã¯éããŸããã
- åå²ã°ã©ããäœæããåŸããååŠçãšã³ã³ãã€ã«ãã®2ã€ã®ãã§ãŒãºã§æ£åžžã«çµã¿ç«ãŠãããå Žåããããã¯ãŒã¯äžã®ãªã¢ãŒãå®è¡ããããã¯ãŒã¯ã¬ã€ã€ãŒãšçµ±åããå¿
èŠããããŸãã Ninjaã®ãã«ããµã€ã¯ã«èªäœã¯ãé¢æ°Builder :: Buildã®build.ccã«ãããŸãã ããªãã¯ããã«é¡æšããŠããã«è¿œå ããããšãã§ããŸã
ãifïŒfailures_allowed && command_runner _-> CanRunMoreïŒïŒïŒãããã³ãifïŒpending_commandsïŒãã¯ãåæ£ã¢ã»ã³ããªã®æé ã§ãã
ã¹ããŒãžXã次ã¯ïŒ
ãããã¿ã€ããæ£åžžã«äœæããåŸã補åãäœæããããã«å°ããªã¹ãããã§ç§»åããå¿ èŠããããŸãã
- ãã¹ãŠã®ã¢ãžã¥ãŒã«ã®æ§æ-ãããã¯ãŒã¯ãµãã·ã¹ãã ãšInvocationRewriterã®äž¡æ¹ã
- ç°ãªãã³ã³ãã€ã©ãŒã§ã®ãªãã·ã§ã³ã®çµã¿åããã®ãµããŒãã
- ãã¡ã€ã«è»¢éå§çž®ã®ãµããŒãã
- ãã°åœ¢åŒã®ããŸããŸãªèšºæã
- è€æ°ã®ã¢ã»ã³ããªãµãŒããŒãžã®æ¥ç¶ãåŠçã§ããã³ãŒãã£ããŒã¿ãŒãäœæããŸãã
- è€æ°ã®ã¯ã©ã€ã¢ã³ããäžåºŠã«ãµãŒããŒã䜿çšãããšããäºå®ãèæ ®ã«å ¥ãããã©ã³ãµãŒãäœæããŸãïŒãããŠããããã枬å®ä»¥äžã«éè² è·ã«ããªãã§ãã ããïŒã
- å¿è ã ãã§ãªããä»ã®ãã«ãã·ã¹ãã ãšã®çµ±åãèšè¿°ããŸãã
äžè¬ã«ãã¿ããªãç§ã¯ãã®æ®µéã§ã©ããã«ç«ã¡å¯ã£ãã ããããã¹ãŠãå®è£ ããApacheã©ã€ã»ã³ã¹ã§ããWuild OpenSourceãããžã§ã¯ãïŒ ããã®ãœãŒã¹ ïŒãäœæããŸããã æžã蟌ã¿ã«çŽ150æéã®ç©ºãæéãããããŸããïŒèª°ããç§ã®ãã¹ãç¹°ãè¿ãããšã«ããå ŽåïŒã ããžãã¹ããžãã¯ã«éäžãããããã¯ãŒã¯ã®ãããã°ãããã»ã¹ã®éå§ãè¡ããªãããã«ãæ¢åã®ç¡æã©ã€ãã©ãªãæ倧éã«äœ¿çšããããšã匷ããå§ãããŸãã
Wuildã§ã§ããããšïŒ
- WinãMacãLinuxã§ã®ã¯ãã¹ã³ã³ãã€ã«ïŒClangïŒæ©èœãåããåæ£ã¢ã»ã³ããªã
- Ninjaããã³Makeãšã®çµ±åã
ã¯ããäžè¬çã«ã¯ãããã§ãã¹ãŠã§ãã ãããžã§ã¯ãã¯ã¢ã«ãã¡çãšããŒã¿çã®éã§å¯èœã§ãïŒå®å®æ§-ã¯ããæ©èœ-ãããïŒDïŒã ãã³ãããŒã¯ãæ²èŒããŸããïŒåºåãæ²èŒããããããŸããïŒããã¢ããã°è£œåã®1ã€ãšæ¯èŒããŠãã¹ããŒãã«æºè¶³ããŠããŸããã
ãã®èšäºã¯æè²çãªãã®ã§ããããããžã§ã¯ãã¯äºé²çãªãã®ã§ãïŒNIHçå矀ã®æå³ã§ããããããªãæ¹æ³-èªè»¢è»ã®æ°ãæžãããŠãã ããïŒã
誰ãæãã§ãã-ãã©ãŒã¯ããã«ãªã¯ãšã¹ããè¡ããæãããç®çã«äœ¿çšããïŒ