mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-22 16:07:49 +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;
|
bool useResponseFile = false;
|
||||||
if (cmdLineLimit < 0 ||
|
if (cmdLineLimit < 0 ||
|
||||||
(cmdLineLimit > 0 &&
|
(cmdLineLimit > 0 &&
|
||||||
(args.size() + buildstr.size() + assignments.size()) >
|
(args.size() + buildstr.size() + assignments.size() + 1000) >
|
||||||
static_cast<size_t>(cmdLineLimit))) {
|
static_cast<size_t>(cmdLineLimit))) {
|
||||||
variable_assignments.str(std::string());
|
variable_assignments.str(std::string());
|
||||||
cmGlobalNinjaGenerator::WriteVariable(variable_assignments, "RSP_FILE",
|
cmGlobalNinjaGenerator::WriteVariable(variable_assignments, "RSP_FILE",
|
||||||
|
@@ -30,10 +30,6 @@
|
|||||||
#include "cm_auto_ptr.hxx"
|
#include "cm_auto_ptr.hxx"
|
||||||
#include "cmake.h"
|
#include "cmake.h"
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target)
|
cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmGeneratorTarget* target)
|
||||||
: cmCommonTargetGenerator(target)
|
: cmCommonTargetGenerator(target)
|
||||||
, OSXBundleGenerator(CM_NULLPTR)
|
, OSXBundleGenerator(CM_NULLPTR)
|
||||||
@@ -1492,15 +1488,6 @@ void cmMakefileTargetGenerator::CreateLinkScript(
|
|||||||
makefile_depends.push_back(linkScriptName);
|
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(
|
bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects(
|
||||||
std::string const& l) const
|
std::string const& l) const
|
||||||
{
|
{
|
||||||
@@ -1514,7 +1501,7 @@ bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for a system limit.
|
// 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
|
// Compute the total length of our list of object files with room
|
||||||
// for argument separation and quoting. This does not convert paths
|
// for argument separation and quoting. This does not convert paths
|
||||||
// relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so the
|
// relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so the
|
||||||
|
@@ -5,11 +5,9 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <limits>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "cmAlgorithms.h"
|
#include "cmAlgorithms.h"
|
||||||
#include "cmCustomCommand.h"
|
#include "cmCustomCommand.h"
|
||||||
@@ -35,10 +33,6 @@
|
|||||||
#include "cm_auto_ptr.hxx"
|
#include "cm_auto_ptr.hxx"
|
||||||
#include "cmake.h"
|
#include "cmake.h"
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
|
cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
|
||||||
cmGeneratorTarget* target)
|
cmGeneratorTarget* target)
|
||||||
: cmNinjaTargetGenerator(target)
|
: cmNinjaTargetGenerator(target)
|
||||||
@@ -546,36 +540,6 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd()
|
|||||||
return std::vector<std::string>();
|
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()
|
void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
|
||||||
{
|
{
|
||||||
cmGeneratorTarget& genTarget = *this->GetGeneratorTarget();
|
cmGeneratorTarget& genTarget = *this->GetGeneratorTarget();
|
||||||
@@ -761,8 +725,9 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
|
|||||||
|
|
||||||
// Device linking currently doesn't support response files so
|
// Device linking currently doesn't support response files so
|
||||||
// do not check if the user has explicitly forced a response file.
|
// do not check if the user has explicitly forced a response file.
|
||||||
int const commandLineLengthLimit = calculateCommandLineLengthLimit(
|
int const commandLineLengthLimit =
|
||||||
globalGen.GetRuleCmdLength(this->LanguageLinkerDeviceRule()));
|
static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
|
||||||
|
globalGen.GetRuleCmdLength(this->LanguageLinkerDeviceRule());
|
||||||
|
|
||||||
const std::string rspfile =
|
const std::string rspfile =
|
||||||
std::string(cmake::GetCMakeFilesDirectoryPostSlash()) +
|
std::string(cmake::GetCMakeFilesDirectoryPostSlash()) +
|
||||||
@@ -1048,8 +1013,9 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
|
|||||||
!(this->TargetLinkLanguage == "RC" || this->TargetLinkLanguage == "CUDA");
|
!(this->TargetLinkLanguage == "RC" || this->TargetLinkLanguage == "CUDA");
|
||||||
int commandLineLengthLimit = -1;
|
int commandLineLengthLimit = -1;
|
||||||
if (!lang_supports_response || !this->ForceResponseFile()) {
|
if (!lang_supports_response || !this->ForceResponseFile()) {
|
||||||
commandLineLengthLimit = calculateCommandLineLengthLimit(
|
commandLineLengthLimit =
|
||||||
globalGen.GetRuleCmdLength(this->LanguageLinkerRule()));
|
static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
|
||||||
|
globalGen.GetRuleCmdLength(this->LanguageLinkerRule());
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string rspfile =
|
const std::string rspfile =
|
||||||
|
@@ -570,6 +570,46 @@ std::vector<std::string> cmSystemTools::ParseArguments(const char* command)
|
|||||||
return args;
|
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,
|
bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
|
||||||
std::string* captureStdOut,
|
std::string* captureStdOut,
|
||||||
std::string* captureStdErr, int* retVal,
|
std::string* captureStdErr, int* retVal,
|
||||||
|
@@ -253,6 +253,8 @@ public:
|
|||||||
static void ParseUnixCommandLine(const char* command,
|
static void ParseUnixCommandLine(const char* command,
|
||||||
std::vector<std::string>& args);
|
std::vector<std::string>& args);
|
||||||
|
|
||||||
|
static size_t CalculateCommandLineLengthLimit();
|
||||||
|
|
||||||
static void EnableMessages() { s_DisableMessages = false; }
|
static void EnableMessages() { s_DisableMessages = false; }
|
||||||
static void DisableMessages() { s_DisableMessages = true; }
|
static void DisableMessages() { s_DisableMessages = true; }
|
||||||
static void DisableRunCommandOutput() { s_DisableRunCommandOutput = true; }
|
static void DisableRunCommandOutput() { s_DisableRunCommandOutput = true; }
|
||||||
|
Reference in New Issue
Block a user