Skip to content

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
    • Help
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
CMake
CMake
  • Project
    • Project
    • Details
    • Activity
    • Releases
    • Cycle Analytics
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Charts
  • Issues 2,205
    • Issues 2,205
    • List
    • Board
    • Labels
    • Milestones
  • Merge Requests 13
    • Merge Requests 13
  • External Wiki
    • External Wiki
  • Members
    • Members
  • Collapse sidebar
  • Activity
  • Graph
  • Charts
  • Create a new issue
  • Commits
  • Issue Boards
  • CMake
  • CMakeCMake
  • Issues
  • #18902

Closed
Open
Opened Feb 10, 2019 by Sebastian Lipponer@sebastianlipponer
  • Report abuse
  • New issue
Report abuse New issue

Ninja: Command line length dependent response file usage.

From the code it seems like the Ninja generator should be able to decide for each rule individually to use response files depending on whether the command line length limit is hit.

Linker rules are handled in cmNinjaNormalTargetGenerator::WriteLinkStatement(). Line 1000 calculates the command line rest length:

  if (!lang_supports_response || !this->ForceResponseFile()) {
    commandLineLengthLimit =
      static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
      globalGen.GetRuleCmdLength(this->LanguageLinkerRule());
  }

However, GetRuleCmdLength() will always return zero at this point because the rule has not yet been added to the GlobalGenerator using cmGlobalNinjaGenerator::AddRule(). This happens later as part of cmNinjaNormalTargetGenerator::WriteLinkRule() in Line 1028.

Nevertheless, the decision logic in cmGlobalNinjaGenerator::WriteBuild() in Line 213 seems to rely on the real command line limit anyway.

  if (cmdLineLimit < 0 ||
      (cmdLineLimit > 0 &&
       (arguments.size() + buildstr.size() + assignments.size() + 1000) >
         static_cast<size_t>(cmdLineLimit))) {
    variable_assignments.str(std::string());
    cmGlobalNinjaGenerator::WriteVariable(variable_assignments, "RSP_FILE",
                                          rspfile, "", 1);
    assignments += variable_assignments.str();
    useResponseFile = true;
  }

The build statements are handled in cmNinjaTargetGenerator::WriteObjectBuildStatement(). From Line 916 it becomes apparent that the response file usage for compile rules is only supported if forced via CMAKE_NINJA_FORCE_RESPONSE_FILE.

  int const commandLineLengthLimit =
    ((lang_supports_response && this->ForceResponseFile())) ? -1 : 0;

I actually replaced this with

 int commandLineLengthLimit = 0;
 if (lang_supports_response) {
   commandLineLengthLimit = (this->ForceResponseFile()) ?
     -1 : static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit());
 }

which seems to work as expected.

However, the generated rules need also to make use of the $RSP_FILE variable using rspfile and rspfile_content. This happens in cmNinjaTargetGenerator::WriteCompileRule(). In Line 469 the earlier decision logic is present again:

  if (lang_supports_response && this->ForceResponseFile()) {
    std::string const responseFlagVar =
      "CMAKE_" + lang + "_RESPONSE_FILE_FLAG";
    responseFlag = this->Makefile->GetSafeDefinition(responseFlagVar);
    if (responseFlag.empty()) {
      responseFlag = "@";
    }
  }

The compile rules are generated before the build statements. However, we do not know the command line length until the build statements are generated. This suggests to change the generation order, i.e. generate the build statements before the compile rules.

Any suggestion on how to fix this?

Edited Feb 10, 2019 by Sebastian Lipponer
Assignee
Assign to
None
Milestone
None
Assign milestone
Time tracking
None
Due date
No due date
0
Labels
None
Assign labels
  • View project labels
Reference: cmake/cmake#18902