20 #elif defined( _WIN32)
35 #include <sys/types.h>
45 #if defined(__APPLE__) || defined(__FreeBSD__)
46 #include <sys/sysctl.h>
47 #elif defined(__SVR4) && defined(__sun)
49 #include <sys/loadavg.h>
50 #elif defined(_AIX) && !defined(__PASE__)
51 #include <libperfstat.h>
52 #elif defined(__linux__) || defined(__GLIBC__)
53 #include <sys/sysinfo.h>
59 #if defined(__FreeBSD__)
60 #include <sys/cpuset.h>
67 void Fatal(
const char* msg, ...) {
69 fprintf(stderr,
"ninja: fatal: ");
71 vfprintf(stderr, msg, ap);
73 fprintf(stderr,
"\n");
85 void Warning(
const char* msg, va_list ap) {
86 fprintf(stderr,
"ninja: warning: ");
87 vfprintf(stderr, msg, ap);
88 fprintf(stderr,
"\n");
98 void Error(
const char* msg, va_list ap) {
99 fprintf(stderr,
"ninja: error: ");
100 vfprintf(stderr, msg, ap);
101 fprintf(stderr,
"\n");
111 void Info(
const char* msg, va_list ap) {
112 fprintf(stdout,
"ninja: ");
113 vfprintf(stdout, msg, ap);
114 fprintf(stdout,
"\n");
117 void Info(
const char* msg, ...) {
125 size_t len = path->size();
135 return c ==
'/' || c ==
'\\';
150 char* dst_start = dst;
151 const char* src = start;
152 const char* end = start + *len;
153 const char* src_next;
176 while (src + 3 <= end && src[0] ==
'.' && src[1] ==
'.' &&
185 int component_count = 0;
187 for (; src < end; src = src_next) {
192 const char* next_sep =
193 static_cast<const char*
>(::memchr(src,
'/', end - src));
201 const char* next_sep = src;
204 if (next_sep == end) {
210 src_next = next_sep + 1;
212 size_t component_len = next_sep - src;
214 if (component_len <= 2) {
215 if (component_len == 0) {
219 if (component_len == 1) {
221 }
else if (src[1] ==
'.') {
223 if (component_count > 0) {
243 ::memmove(dst, src, src_next - src);
245 dst += src_next - src;
251 size_t component_len = end - src;
253 if (component_len == 0)
256 if (component_len == 1)
258 if (component_len == 2 && src[1] ==
'.') {
260 if (component_count > 0) {
275 ::memmove(dst, src, component_len);
277 dst += component_len;
295 for (
char* c = start; c < start + *len; ++c) {
313 if (
'A' <= ch && ch <=
'Z')
return true;
314 if (
'a' <= ch && ch <=
'z')
return true;
315 if (
'0' <= ch && ch <=
'9')
return true;
340 for (
size_t i = 0; i < input.size(); ++i) {
347 for (
size_t i = 0; i < input.size(); ++i) {
357 result->append(input);
361 const char kQuote =
'\'';
362 const char kEscapeSequence[] =
"'\\'";
364 result->push_back(kQuote);
366 string::const_iterator span_begin = input.begin();
367 for (string::const_iterator it = input.begin(), end = input.end(); it != end;
370 result->append(span_begin, it);
371 result->append(kEscapeSequence);
375 result->append(span_begin, input.end());
376 result->push_back(kQuote);
383 result->append(input);
387 const char kQuote =
'"';
388 const char kBackslash =
'\\';
390 result->push_back(kQuote);
391 size_t consecutive_backslash_count = 0;
392 string::const_iterator span_begin = input.begin();
393 for (string::const_iterator it = input.begin(), end = input.end(); it != end;
397 ++consecutive_backslash_count;
400 result->append(span_begin, it);
401 result->append(consecutive_backslash_count + 1, kBackslash);
403 consecutive_backslash_count = 0;
406 consecutive_backslash_count = 0;
410 result->append(span_begin, input.end());
411 result->append(consecutive_backslash_count, kBackslash);
412 result->push_back(kQuote);
415 int ReadFile(
const string& path,
string* contents,
string* err) {
420 HANDLE f = ::CreateFileA(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
421 OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
422 if (f == INVALID_HANDLE_VALUE) {
423 err->assign(GetLastErrorString());
430 if (!::
ReadFile(f, buf,
sizeof(buf), &len, NULL)) {
431 err->assign(GetLastErrorString());
438 contents->append(buf, len);
443 FILE* f = fopen(path.c_str(),
"rb");
445 err->assign(strerror(errno));
449 #ifdef __USE_LARGEFILE64
451 if (fstat64(fileno(f), &st) < 0) {
454 if (fstat(fileno(f), &st) < 0) {
456 err->assign(strerror(errno));
462 contents->reserve(st.st_size + 1);
466 while (!feof(f) && (len = fread(buf, 1,
sizeof(buf), f)) > 0) {
467 contents->append(buf, len);
470 err->assign(strerror(errno));
482 int flags = fcntl(fd, F_GETFD);
484 perror(
"fcntl(F_GETFD)");
486 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
487 perror(
"fcntl(F_SETFD)");
490 HANDLE hd = (HANDLE) _get_osfhandle(fd);
491 if (! SetHandleInformation(hd, HANDLE_FLAG_INHERIT, 0)) {
492 fprintf(stderr,
"SetHandleInformation(): %s", GetLastErrorString().c_str());
499 const vector<const char*>& words) {
500 const bool kAllowReplacements =
true;
501 const int kMaxValidEditDistance = 3;
503 int min_distance = kMaxValidEditDistance + 1;
504 const char* result = NULL;
505 for (vector<const char*>::const_iterator i = words.begin();
506 i != words.end(); ++i) {
507 int distance =
EditDistance(*i, text, kAllowReplacements,
508 kMaxValidEditDistance);
509 if (distance < min_distance) {
510 min_distance = distance;
522 vector<const char*> words;
524 while ((word = va_arg(ap,
const char*)))
525 words.push_back(word);
531 string GetLastErrorString() {
532 DWORD err = GetLastError();
536 FORMAT_MESSAGE_ALLOCATE_BUFFER |
537 FORMAT_MESSAGE_FROM_SYSTEM |
538 FORMAT_MESSAGE_IGNORE_INSERTS,
541 MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
546 if (msg_buf ==
nullptr) {
547 char fallback_msg[128] = {0};
548 snprintf(fallback_msg,
sizeof(fallback_msg),
"GetLastError() = %lu", err);
552 string msg = msg_buf;
557 void Win32Fatal(
const char*
function,
const char* hint) {
559 Fatal(
"%s: %s (%s)",
function, GetLastErrorString().c_str(), hint);
561 Fatal(
"%s: %s",
function, GetLastErrorString().c_str());
568 return (c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z');
573 stripped.reserve(in.size());
575 for (
size_t i = 0; i < in.size(); ++i) {
576 if (in[i] !=
'\33') {
578 stripped.push_back(in[i]);
583 if (i + 1 >= in.size())
break;
584 if (in[i + 1] !=
'[')
continue;
594 #if defined(__linux__) || defined(__GLIBC__)
595 std::pair<int64_t, bool> readCount(
const std::string& path) {
596 std::ifstream file(path.c_str());
598 return std::make_pair(0,
false);
602 return std::make_pair(n,
true);
603 return std::make_pair(0,
false);
612 vector<StringPiece> options;
613 vector<StringPiece> optionalFields;
616 vector<StringPiece> superOptions;
617 bool parse(
const string& line) {
619 if (pieces.size() < 10)
621 size_t optionalStart = 0;
622 for (
size_t i = 6; i < pieces.size(); i++) {
623 if (pieces[i] ==
"-") {
624 optionalStart = i + 1;
628 if (optionalStart == 0)
630 if (optionalStart + 3 != pieces.size())
632 mountId = atoi(pieces[0].AsString().c_str());
633 parentId = atoi(pieces[1].AsString().c_str());
634 deviceId = pieces[2];
636 mountPoint = pieces[4];
639 vector<StringPiece>(&pieces[6], &pieces[optionalStart - 1]);
640 fsType = pieces[optionalStart];
641 mountSource = pieces[optionalStart + 1];
645 string translate(
string& path)
const {
647 if (path.compare(0, root.
len_, root.
str_, root.
len_) != 0) {
650 path.erase(0, root.
len_);
651 if (path ==
".." || (path.length() > 2 && path.compare(0, 3,
"../") == 0)) {
654 return mountPoint.
AsString() +
"/" + path;
658 struct CGroupSubSys {
661 vector<string> subsystems;
662 bool parse(
string& line) {
663 size_t first = line.find(
':');
664 if (first == string::npos)
667 size_t second = line.find(
':', first + 1);
668 if (second == string::npos)
671 id = atoi(line.c_str());
672 name = line.substr(second + 1);
673 vector<StringPiece> pieces =
675 for (
size_t i = 0; i < pieces.size(); i++) {
676 subsystems.push_back(pieces[i].AsString());
682 map<string, string> ParseMountInfo(map<string, CGroupSubSys>& subsystems) {
683 map<string, string> cgroups;
684 ifstream mountinfo(
"/proc/self/mountinfo");
685 if (!mountinfo.is_open())
687 while (!mountinfo.eof()) {
689 getline(mountinfo, line);
693 if (mp.fsType ==
"cgroup") {
694 for (
size_t i = 0; i < mp.superOptions.size(); i++) {
695 std::string opt = mp.superOptions[i].AsString();
696 auto subsys = subsystems.find(opt);
697 if (subsys == subsystems.end()) {
700 std::string newPath = mp.translate(subsys->second.name);
701 if (!newPath.empty()) {
702 cgroups.emplace(opt, newPath);
705 }
else if (mp.fsType ==
"cgroup2") {
707 auto subsys = std::find_if(subsystems.begin(), subsystems.end(),
708 [](
const auto& sys) {
709 return sys.first ==
"" && sys.second.id == 0;
711 if (subsys == subsystems.end()) {
714 std::string path = mp.mountPoint.AsString();
715 if (subsys->second.name !=
"/") {
717 path.append(subsys->second.name);
719 cgroups.emplace(
"cgroup2", path);
725 map<string, CGroupSubSys> ParseSelfCGroup() {
726 map<string, CGroupSubSys> cgroups;
727 ifstream cgroup(
"/proc/self/cgroup");
728 if (!cgroup.is_open())
731 while (!cgroup.eof()) {
732 getline(cgroup, line);
734 if (!subsys.parse(line))
736 for (
size_t i = 0; i < subsys.subsystems.size(); i++) {
737 cgroups.insert(make_pair(subsys.subsystems[i], subsys));
743 int ParseCgroupV1(std::string& path) {
744 std::pair<int64_t, bool> quota = readCount(path +
"/cpu.cfs_quota_us");
745 if (!quota.second || quota.first == -1)
747 std::pair<int64_t, bool> period = readCount(path +
"/cpu.cfs_period_us");
750 if (period.first == 0)
752 return quota.first / period.first;
755 int ParseCgroupV2(std::string& path) {
757 std::ifstream cpu_max(path +
"/cpu.max");
758 if (!cpu_max.is_open()) {
761 std::string max_line;
762 if (!std::getline(cpu_max, max_line) || max_line.empty()) {
766 size_t space_pos = max_line.find(
' ');
767 if (space_pos == string::npos) {
770 std::string quota_str = max_line.substr(0, space_pos);
771 std::string period_str = max_line.substr(space_pos + 1);
772 if (quota_str ==
"max") {
776 char* quota_end =
nullptr;
778 int64_t quota = strtoll(quota_str.c_str(), "a_end, 10);
780 if (errno == ERANGE || quota_end == quota_str.c_str() || *quota_end !=
'\0' ||
785 char* period_end =
nullptr;
787 int64_t period = strtoll(period_str.c_str(), &period_end, 10);
789 if (errno == ERANGE || period_end == period_str.c_str() ||
790 *period_end !=
'\0' || period <= 0) {
793 return quota / period;
796 int ParseCPUFromCGroup() {
797 auto subsystems = ParseSelfCGroup();
798 auto cgroups = ParseMountInfo(subsystems);
801 const auto cgroup2 = cgroups.find(
"cgroup2");
802 if (cgroup2 != cgroups.end()) {
803 return ParseCgroupV2(cgroup2->second);
806 const auto cpu = cgroups.find(
"cpu");
807 if (cpu != cgroups.end()) {
808 return ParseCgroupV1(cpu->second);
821 if (!GetLogicalProcessorInformationEx(RelationProcessorCore,
nullptr, &len)
822 && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
823 std::vector<char> buf(len);
825 if (GetLogicalProcessorInformationEx(RelationProcessorCore,
826 reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
>(
827 buf.data()), &len)) {
828 for (DWORD i = 0; i < len; ) {
829 auto info =
reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
>(
831 if (info->Relationship == RelationProcessorCore &&
832 info->Processor.GroupCount == 1) {
833 for (KAFFINITY core_mask = info->Processor.GroupMask[0].Mask;
834 core_mask; core_mask >>= 1) {
835 cores += (core_mask & 1);
847 cpuCount = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
849 JOBOBJECT_CPU_RATE_CONTROL_INFORMATION info;
852 if (QueryInformationJobObject(NULL, JobObjectCpuRateControlInformation, &info,
853 sizeof(info), NULL)) {
854 if (info.ControlFlags & (JOB_OBJECT_CPU_RATE_CONTROL_ENABLE |
855 JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP)) {
856 return cpuCount * info.CpuRate / 10000;
861 int cgroupCount = -1;
863 #if defined(__linux__) || defined(__GLIBC__)
864 cgroupCount = ParseCPUFromCGroup();
869 #if defined(__FreeBSD__)
872 if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1,
sizeof(mask),
874 return CPU_COUNT(&mask);
876 #elif defined(CPU_COUNT)
878 if (sched_getaffinity(getpid(),
sizeof(set), &set) == 0) {
879 schedCount = CPU_COUNT(&set);
882 if (cgroupCount >= 0 && schedCount >= 0)
return std::min(cgroupCount, schedCount);
883 if (cgroupCount < 0 && schedCount < 0)
884 return static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
885 return std::max(cgroupCount, schedCount);
889 #if defined(_WIN32) || defined(__CYGWIN__)
890 static double CalculateProcessorLoad(
uint64_t idle_ticks,
uint64_t total_ticks)
892 static uint64_t previous_idle_ticks = 0;
893 static uint64_t previous_total_ticks = 0;
894 static double previous_load = -0.0;
896 uint64_t idle_ticks_since_last_time = idle_ticks - previous_idle_ticks;
897 uint64_t total_ticks_since_last_time = total_ticks - previous_total_ticks;
899 bool first_call = (previous_total_ticks == 0);
900 bool ticks_not_updated_since_last_call = (total_ticks_since_last_time == 0);
903 if (first_call || ticks_not_updated_since_last_call) {
904 load = previous_load;
907 double idle_to_total_ratio =
908 ((double)idle_ticks_since_last_time) / total_ticks_since_last_time;
909 double load_since_last_call = 1.0 - idle_to_total_ratio;
912 if(previous_load > 0) {
913 load = 0.9 * previous_load + 0.1 * load_since_last_call;
915 load = load_since_last_call;
919 previous_load = load;
920 previous_total_ticks = total_ticks;
921 previous_idle_ticks = idle_ticks;
926 static uint64_t FileTimeToTickCount(
const FILETIME & ft)
934 FILETIME idle_time, kernel_time, user_time;
935 BOOL get_system_time_succeeded =
936 GetSystemTimes(&idle_time, &kernel_time, &user_time);
938 double posix_compatible_load;
939 if (get_system_time_succeeded) {
940 uint64_t idle_ticks = FileTimeToTickCount(idle_time);
944 FileTimeToTickCount(kernel_time) + FileTimeToTickCount(user_time);
946 double processor_load = CalculateProcessorLoad(idle_ticks, total_ticks);
950 posix_compatible_load = -0.0;
953 return posix_compatible_load;
955 #elif defined(__PASE__)
961 perfstat_cpu_total_t cpu_stats;
962 if (perfstat_cpu_total(NULL, &cpu_stats,
sizeof(cpu_stats), 1) < 0) {
967 return double(cpu_stats.loadavg[0]) / double(1 << SBITS);
969 #elif defined(__UCLIBC__) || (defined(__BIONIC__) && __ANDROID_API__ < 29)
972 if (sysinfo(&si) != 0)
974 return 1.0 / (1 << SI_LOAD_SHIFT) * si.loads[0];
976 #elif defined(__HAIKU__)
982 double loadavg[3] = { 0.0f, 0.0f, 0.0f };
983 if (getloadavg(loadavg, 3) < 0) {
994 char* success = NULL;
996 ret.resize(ret.size() + 1024);
998 success = getcwd(&ret[0], ret.size());
999 }
while (!success && errno == ERANGE);
1001 Fatal(
"cannot determine working directory: %s", strerror(errno));
1003 ret.resize(strlen(&ret[0]));
1007 bool Truncate(
const string& path,
size_t size,
string* err) {
1009 int fh = _sopen(path.c_str(), _O_RDWR | _O_CREAT, _SH_DENYNO,
1010 _S_IREAD | _S_IWRITE);
1011 int success = _chsize(fh, size);
1014 int success = truncate(path.c_str(), size);
1019 *err = strerror(errno);
1027 return _unlink(filename);
1029 return unlink(filename);
int EditDistance(const StringPiece &s1, const StringPiece &s2, bool allow_replacements, int max_edit_distance)
vector< StringPiece > SplitStringPiece(StringPiece input, char sep)
StringPiece represents a slice of a string whose memory is managed externally.
std::string AsString() const
Convert the slice into a full-fledged std::string, copying the data into a new string.
void GetWin32EscapedString(const string &input, string *result)
void Error(const char *msg, va_list ap)
static bool IsKnownShellSafeCharacter(char ch)
const char * SpellcheckString(const char *text,...)
Like SpellcheckStringV, but takes a NULL-terminated list.
static bool StringNeedsShellEscaping(const string &input)
int platformAwareUnlink(const char *filename)
static bool IsKnownWin32SafeCharacter(char ch)
bool Truncate(const string &path, size_t size, string *err)
void GetShellEscapedString(const string &input, string *result)
std::string GetWorkingDirectory()
a wrapper for getcwd()
void Warning(const char *msg, va_list ap)
void Info(const char *msg, va_list ap)
static bool IsPathSeparator(char c)
void SetCloseOnExec(int fd)
Mark a file descriptor to not be inherited on exec()s.
void CanonicalizePath(string *path, uint64_t *slash_bits)
string StripAnsiEscapeCodes(const string &in)
static bool StringNeedsWin32Escaping(const string &input)
const char * SpellcheckStringV(const string &text, const vector< const char * > &words)
void Fatal(const char *msg,...)
Log a fatal message and exit.
int ReadFile(const string &path, string *contents, string *err)
#define NINJA_FALLTHROUGH
unsigned long long uint64_t
signed long long int64_t
A 64-bit integer type.