mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-21 06:10:16 +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:

committed by
Brad King

parent
ddd2b02455
commit
bbb5c3efe2
@@ -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",
|
||||
|
@@ -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
|
||||
|
@@ -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 =
|
||||
|
@@ -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,
|
||||
|
@@ -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; }
|
||||
|
Reference in New Issue
Block a user