1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-21 14:40:48 +08:00

Ninja,Makefile: Unify command line limit logic

Move the logic to cmSystemTools to be shared among the generators.
Revise the implementation and add comments justifying each possible
source for a limit.
This commit is contained in:
Christian Pfeiffer
2017-04-18 23:06:39 +02:00
committed by Brad King
parent ddd2b02455
commit bbb5c3efe2
5 changed files with 50 additions and 55 deletions

View File

@@ -246,7 +246,7 @@ void cmGlobalNinjaGenerator::WriteBuild(
bool useResponseFile = false;
if (cmdLineLimit < 0 ||
(cmdLineLimit > 0 &&
(args.size() + buildstr.size() + assignments.size()) >
(args.size() + buildstr.size() + assignments.size() + 1000) >
static_cast<size_t>(cmdLineLimit))) {
variable_assignments.str(std::string());
cmGlobalNinjaGenerator::WriteVariable(variable_assignments, "RSP_FILE",

View File

@@ -30,10 +30,6 @@
#include "cm_auto_ptr.hxx"
#include "cmake.h"
#ifndef _WIN32
#include <unistd.h>
#endif
cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target)
: cmCommonTargetGenerator(target)
, OSXBundleGenerator(CM_NULLPTR)
@@ -1492,15 +1488,6 @@ void cmMakefileTargetGenerator::CreateLinkScript(
makefile_depends.push_back(linkScriptName);
}
static size_t calculateCommandLineLengthLimit()
{
#if defined(_SC_ARG_MAX)
return ((size_t)sysconf(_SC_ARG_MAX)) - 1000;
#else
return 0;
#endif
}
bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects(
std::string const& l) const
{
@@ -1514,7 +1501,7 @@ bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects(
}
// Check for a system limit.
if (size_t const limit = calculateCommandLineLengthLimit()) {
if (size_t const limit = cmSystemTools::CalculateCommandLineLengthLimit()) {
// Compute the total length of our list of object files with room
// for argument separation and quoting. This does not convert paths
// relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so the

View File

@@ -5,11 +5,9 @@
#include <algorithm>
#include <assert.h>
#include <iterator>
#include <limits>
#include <map>
#include <set>
#include <sstream>
#include <stddef.h>
#include "cmAlgorithms.h"
#include "cmCustomCommand.h"
@@ -35,10 +33,6 @@
#include "cm_auto_ptr.hxx"
#include "cmake.h"
#ifndef _WIN32
#include <unistd.h>
#endif
cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
cmGeneratorTarget* target)
: cmNinjaTargetGenerator(target)
@@ -546,36 +540,6 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd()
return std::vector<std::string>();
}
static int calculateCommandLineLengthLimit(int linkRuleLength)
{
static int const limits[] = {
#ifdef _WIN32
8000,
#endif
#if defined(__linux)
// #define MAX_ARG_STRLEN (PAGE_SIZE * 32) in Linux's binfmts.h
((int)sysconf(_SC_PAGESIZE) * 32) - 1000,
#endif
std::numeric_limits<int>::max()
};
size_t const arrSz = cmArraySize(limits);
int sz = *std::min_element(limits, limits + arrSz);
#if defined(_SC_ARG_MAX)
// for instance ARG_MAX is 2096152 on Ubuntu or 262144 on Mac
int const szArgMax = static_cast<int>(sysconf(_SC_ARG_MAX));
// a return value of -1 signifies an unrestricted value
if (szArgMax != -1) {
sz = std::min(sz, szArgMax - 1000);
}
#endif
if (sz == std::numeric_limits<int>::max()) {
return 0;
}
return sz - linkRuleLength;
}
void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
{
cmGeneratorTarget& genTarget = *this->GetGeneratorTarget();
@@ -761,8 +725,9 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
// Device linking currently doesn't support response files so
// do not check if the user has explicitly forced a response file.
int const commandLineLengthLimit = calculateCommandLineLengthLimit(
globalGen.GetRuleCmdLength(this->LanguageLinkerDeviceRule()));
int const commandLineLengthLimit =
static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
globalGen.GetRuleCmdLength(this->LanguageLinkerDeviceRule());
const std::string rspfile =
std::string(cmake::GetCMakeFilesDirectoryPostSlash()) +
@@ -1048,8 +1013,9 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
!(this->TargetLinkLanguage == "RC" || this->TargetLinkLanguage == "CUDA");
int commandLineLengthLimit = -1;
if (!lang_supports_response || !this->ForceResponseFile()) {
commandLineLengthLimit = calculateCommandLineLengthLimit(
globalGen.GetRuleCmdLength(this->LanguageLinkerRule()));
commandLineLengthLimit =
static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
globalGen.GetRuleCmdLength(this->LanguageLinkerRule());
}
const std::string rspfile =

View File

@@ -570,6 +570,46 @@ std::vector<std::string> cmSystemTools::ParseArguments(const char* command)
return args;
}
size_t cmSystemTools::CalculateCommandLineLengthLimit()
{
size_t sz =
#ifdef _WIN32
// There's a maximum of 65536 bytes and thus 32768 WCHARs on Windows
// However, cmd.exe itself can only handle 8191 WCHARs and Ninja for
// example uses it to spawn processes.
size_t(8191);
#elif defined(__linux)
// MAX_ARG_STRLEN is the maximum length of a string permissible for
// the execve() syscall on Linux. It's defined as (PAGE_SIZE * 32)
// in Linux's binfmts.h
static_cast<size_t>(sysconf(_SC_PAGESIZE) * 32);
#else
size_t(0);
#endif
#if defined(_SC_ARG_MAX)
// ARG_MAX is the maximum size of the command and environment
// that can be passed to the exec functions on UNIX.
// The value in limits.h does not need to be present and may
// depend upon runtime memory constraints, hence sysconf()
// should be used to query it.
long szArgMax = sysconf(_SC_ARG_MAX);
// A return value of -1 signifies an undetermined limit, but
// it does not imply an infinite limit, and thus is ignored.
if (szArgMax != -1) {
// We estimate the size of the environment block to be 1000.
// This isn't accurate at all, but leaves some headroom.
szArgMax = szArgMax < 1000 ? 0 : szArgMax - 1000;
#if defined(_WIN32) || defined(__linux)
sz = std::min(sz, static_cast<size_t>(szArgMax));
#else
sz = static_cast<size_t>(szArgMax);
#endif
}
#endif
return sz;
}
bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
std::string* captureStdOut,
std::string* captureStdErr, int* retVal,

View File

@@ -253,6 +253,8 @@ public:
static void ParseUnixCommandLine(const char* command,
std::vector<std::string>& args);
static size_t CalculateCommandLineLengthLimit();
static void EnableMessages() { s_DisableMessages = false; }
static void DisableMessages() { s_DisableMessages = true; }
static void DisableRunCommandOutput() { s_DisableRunCommandOutput = true; }