cmDepends: merge dependers of depend makefile

Since one depender has multiple dependees, depend makefile generated
same depender line by line, to reduce file size and refine make file
parse speed, merge same dependers to one. And add a testcase for
large depend.make which generated source file includes 20000 header
files and run build and incremental build

Signed-off-by: Wangkai <wangkai86@huawei.com>
Signed-off-by: Zhaoyingdong <zhaoyingdong@huawei.com>
This commit is contained in:
Kai Wang 2020-12-18 14:47:37 +08:00 committed by Brad King
parent da2474626b
commit b696f78073
11 changed files with 125 additions and 24 deletions

View File

@ -7,6 +7,7 @@
#include "cmsys/FStream.hxx"
#include "cmFileTime.h"
#include "cmGlobalUnixMakefileGenerator3.h"
#include "cmLocalUnixMakefileGenerator3.h"
#include "cmMakefile.h"
#include "cmProperty.h"
@ -215,16 +216,28 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources,
// directory. We must do the same here.
std::string obj_m = this->LocalGenerator->ConvertToMakefilePath(obj_i);
internalDepends << obj_i << '\n';
for (std::string const& dep : dependencies) {
makeDepends << obj_m << ": "
<< this->LocalGenerator->ConvertToMakefilePath(
this->LocalGenerator->MaybeConvertToRelativePath(binDir,
dep))
<< '\n';
internalDepends << ' ' << dep << '\n';
if (!dependencies.empty()) {
const auto& lineContinue = static_cast<cmGlobalUnixMakefileGenerator3*>(
this->LocalGenerator->GetGlobalGenerator())
->LineContinueDirective;
bool supportLongLineDepend = static_cast<cmGlobalUnixMakefileGenerator3*>(
this->LocalGenerator->GetGlobalGenerator())
->SupportsLongLineDependencies();
if (supportLongLineDepend) {
makeDepends << obj_m << ':';
}
for (std::string const& dep : dependencies) {
std::string dependee = this->LocalGenerator->ConvertToMakefilePath(
this->LocalGenerator->MaybeConvertToRelativePath(binDir, dep));
if (supportLongLineDepend) {
makeDepends << ' ' << lineContinue << ' ' << dependee;
} else {
makeDepends << obj_m << ": " << dependee << '\n';
}
internalDepends << ' ' << dep << '\n';
}
makeDepends << '\n';
}
makeDepends << '\n';
return true;
}

View File

@ -196,6 +196,9 @@ void cmDependsCompiler::WriteDependencies(
const auto& lineContinue = static_cast<cmGlobalUnixMakefileGenerator3*>(
this->LocalGenerator->GetGlobalGenerator())
->LineContinueDirective;
bool supportLongLineDepend = static_cast<cmGlobalUnixMakefileGenerator3*>(
this->LocalGenerator->GetGlobalGenerator())
->SupportsLongLineDependencies();
const auto& binDir = this->LocalGenerator->GetBinaryDirectory();
cmDepends::DependencyMap makeDependencies(dependencies);
std::unordered_set<cm::string_view> phonyTargets;
@ -213,13 +216,19 @@ void cmDependsCompiler::WriteDependencies(
});
bool first_dep = true;
makeDepends << target << ": ";
if (supportLongLineDepend) {
makeDepends << target << ": ";
}
for (const auto& dep : deps) {
if (first_dep) {
first_dep = false;
makeDepends << dep;
if (supportLongLineDepend) {
if (first_dep) {
first_dep = false;
makeDepends << dep;
} else {
makeDepends << ' ' << lineContinue << " " << dep;
}
} else {
makeDepends << ' ' << lineContinue << " " << dep;
makeDepends << target << ": " << dep << std::endl;
}
phonyTargets.emplace(dep.data(), dep.length());

View File

@ -12,6 +12,7 @@
#include "cmFortranParser.h" /* Interface to parser object. */
#include "cmGeneratedFileStream.h"
#include "cmGlobalUnixMakefileGenerator3.h"
#include "cmLocalUnixMakefileGenerator3.h"
#include "cmMakefile.h"
#include "cmOutputConverter.h"
@ -320,14 +321,28 @@ bool cmDependsFortran::WriteDependenciesReal(std::string const& obj,
std::string obj_i = this->MaybeConvertToRelativePath(binDir, obj);
std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i);
internalDepends << obj_i << "\n " << src << '\n';
for (std::string const& i : info.Includes) {
makeDepends << obj_m << ": "
<< cmSystemTools::ConvertToOutputPath(
this->MaybeConvertToRelativePath(binDir, i))
<< '\n';
internalDepends << ' ' << i << '\n';
if (!info.Includes.empty()) {
const auto& lineContinue = static_cast<cmGlobalUnixMakefileGenerator3*>(
this->LocalGenerator->GetGlobalGenerator())
->LineContinueDirective;
bool supportLongLineDepend = static_cast<cmGlobalUnixMakefileGenerator3*>(
this->LocalGenerator->GetGlobalGenerator())
->SupportsLongLineDependencies();
if (supportLongLineDepend) {
makeDepends << obj_m << ':';
}
for (std::string const& i : info.Includes) {
std::string dependee = cmSystemTools::ConvertToOutputPath(
this->MaybeConvertToRelativePath(binDir, i));
if (supportLongLineDepend) {
makeDepends << ' ' << lineContinue << ' ' << dependee;
} else {
makeDepends << obj_m << ": " << dependee << '\n';
}
internalDepends << ' ' << i << '\n';
}
makeDepends << '\n';
}
makeDepends << '\n';
// Write module requirements to the output stream.
for (std::string const& i : info.Requires) {

View File

@ -26,6 +26,15 @@ cmGlobalBorlandMakefileGenerator::cmGlobalBorlandMakefileGenerator(cmake* cm)
this->DefineWindowsNULL = true;
this->PassMakeflags = true;
this->UnixCD = false;
/*
* Borland Make does not support long line depend rule, as we have tested
* generate one source file includes 40000 header files, and generate
* depend.make in one line(use line continued tag), and error occured:
* ** Fatal CMakeFiles\main.dir\depend.make 1224: Rule line too long **
* we disable long line dependencies rule generation for Borland make
*/
this->ToolSupportsLongLineDependencies = false;
}
void cmGlobalBorlandMakefileGenerator::EnableLanguage(

View File

@ -139,6 +139,12 @@ public:
return this->ToolSupportsCompilerDependencies;
}
// Make tool supports long line dependencies
bool SupportsLongLineDependencies()
{
return this->ToolSupportsLongLineDependencies;
}
/** Get the command to use for a target that has no rule. This is
used for multiple output dependencies and for cmake_force. */
std::string GetEmptyRuleHackCommand() { return this->EmptyRuleHackCommand; }
@ -235,6 +241,10 @@ protected:
// generated by the compiler
bool ToolSupportsCompilerDependencies = true;
// some Make generator, such as Borland not support long line dependencies,
// we add SupportsLongLineDependencies to predicate.
bool ToolSupportsLongLineDependencies = true;
// Some make programs (Borland) do not keep a rule if there are no
// dependencies or commands. This is a problem for creating rules
// that might not do anything but might have other dependencies

View File

@ -67,7 +67,13 @@ else()
endif()
# Test escaping of special characters in include directory paths.
set(special_chars "~@&{}()!'")
set(special_chars "~@&{}()'")
if(NOT (CMAKE_GENERATOR STREQUAL "NMake Makefiles" AND
"x${CMAKE_C_COMPILER_ID}" STREQUAL "xMSVC" AND
"${CMAKE_C_COMPILER_VERSION}" VERSION_LESS 13.0))
# NMake from VS 6 mistakes '!' in a path after a line continuation for a directive.
string(APPEND special_chars "!")
endif()
if(NOT CMAKE_GENERATOR MATCHES "(Unix|MinGW|MSYS) Makefiles")
# when compiler is used for dependencies, special characters for make are not escaped
string(APPEND special_chars "%")

View File

@ -0,0 +1,13 @@
enable_language(C)
add_executable(main ${CMAKE_CURRENT_BINARY_DIR}/main.c)
file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/check-$<LOWER_CASE:$<CONFIG>>.cmake CONTENT "
set(check_pairs
\"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.c\"
\"$<TARGET_FILE:main>|${CMAKE_CURRENT_BINARY_DIR}/main.h\"
)
set(check_exes
\"$<TARGET_FILE:main>\"
)
")

View File

@ -0,0 +1,18 @@
file(TOUCH "${RunCMake_TEST_BINARY_DIR}/main.c")
foreach(i RANGE 1 20000)
file(WRITE "${RunCMake_TEST_BINARY_DIR}/temp_header_file_${i}.h"
"#define HEADER_${i} ${i}\n"
)
file(APPEND "${RunCMake_TEST_BINARY_DIR}/main.c"
"#include \"temp_header_file_${i}.h\"\n"
)
endforeach()
file(APPEND "${RunCMake_TEST_BINARY_DIR}/main.c"
"#include \"main.h\"\n"
)
file(APPEND "${RunCMake_TEST_BINARY_DIR}/main.c"
"int main(void) { return COUNT; }\n"
)
file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.h"
"#define COUNT 1\n"
)

View File

@ -0,0 +1,3 @@
file(WRITE "${RunCMake_TEST_BINARY_DIR}/main.h"
"#define COUNT 2\n"
)

View File

@ -143,3 +143,7 @@ if(RunCMake_GENERATOR MATCHES "Make|Ninja")
run_BuildDepends(CustomCommandDepfile)
set(run_BuildDepends_skip_step_3 1)
endif()
if(RunCMake_GENERATOR MATCHES "Make")
run_BuildDepends(MakeDependencies)
endif()

View File

@ -3,8 +3,9 @@ if(EXISTS "${depend_make}")
file(READ "${depend_make}" depend_make_content)
string(REGEX REPLACE "\n+$" "" depend_make_content "${depend_make_content}")
if(NOT depend_make_content MATCHES "
CMakeFiles/DepTarget.dir/test.c.o: .*/Tests/RunCMake/CommandLine/cmake_depends/test.c
CMakeFiles/DepTarget.dir/test.c.o: .*/Tests/RunCMake/CommandLine/cmake_depends/test.h$")
CMakeFiles/DepTarget.dir/test.c.o: \\\\
.*/Tests/RunCMake/CommandLine/cmake_depends/test.c \\\\
.*/Tests/RunCMake/CommandLine/cmake_depends/test.h$")
string(REPLACE "\n" "\n " depend_make_content " ${depend_make_content}")
set(RunCMake_TEST_FAILED "depend.make does not have expected content:\n${depend_make_content}")
endif()