Defer check for sources within a target until generation.

The `add_library` and `add_executable` commands can now be called with
no source-files and won't generate a warning or error message, as long
as source-files will be added later via the `target_sources` command.
If during the generation step still no sources are associated with
targets created by such calls a useful error message will be generated
and generation fails.

Targets of type `INTERFACE_LIBRARY`, `UTILITY` or `GLOBAL_TARGET` are
excluded from this check because we do not need sources for these target
types during generation.

Fixes: #16872
This commit is contained in:
Deniz Bahadir 2017-10-19 14:31:10 +02:00 committed by Brad King
parent 6e4e7c6547
commit 4e7f67383f
24 changed files with 97 additions and 75 deletions

View File

@ -7,14 +7,15 @@ Add an executable to the project using the specified source files.
add_executable(<name> [WIN32] [MACOSX_BUNDLE] add_executable(<name> [WIN32] [MACOSX_BUNDLE]
[EXCLUDE_FROM_ALL] [EXCLUDE_FROM_ALL]
source1 [source2 ...]) [source1] [source2 ...])
Adds an executable target called ``<name>`` to be built from the source Adds an executable target called ``<name>`` to be built from the source
files listed in the command invocation. The ``<name>`` corresponds to the files listed in the command invocation. (The source files can be omitted
logical target name and must be globally unique within a project. The here if they are added later using :command:`target_sources`.) The
actual file name of the executable built is constructed based on ``<name>`` corresponds to the logical target name and must be globally
conventions of the native platform (such as ``<name>.exe`` or just unique within a project. The actual file name of the executable built is
``<name>``). constructed based on conventions of the native platform (such as
``<name>.exe`` or just ``<name>``).
By default the executable file will be created in the build tree By default the executable file will be created in the build tree
directory corresponding to the source tree directory in which the directory corresponding to the source tree directory in which the

View File

@ -14,13 +14,14 @@ Normal Libraries
add_library(<name> [STATIC | SHARED | MODULE] add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL] [EXCLUDE_FROM_ALL]
source1 [source2 ...]) [source1] [source2 ...])
Adds a library target called ``<name>`` to be built from the source files Adds a library target called ``<name>`` to be built from the source files
listed in the command invocation. The ``<name>`` corresponds to the listed in the command invocation. (The source files can be omitted here
logical target name and must be globally unique within a project. The if they are added later using :command:`target_sources`.) The ``<name>``
actual file name of the library built is constructed based on corresponds to the logical target name and must be globally unique within
conventions of the native platform (such as ``lib<name>.a`` or a project. The actual file name of the library built is constructed based
on conventions of the native platform (such as ``lib<name>.a`` or
``<name>.lib``). ``<name>.lib``).
``STATIC``, ``SHARED``, or ``MODULE`` may be given to specify the type of ``STATIC``, ``SHARED``, or ``MODULE`` may be given to specify the type of

View File

@ -0,0 +1,6 @@
defer-target-source-check
-------------------------
* :command:`add_library` and :command:`add_executable` commands can now be
called without any sources and will not complain as long as sources will
be added later via :command:`target_sources`.

View File

@ -18,7 +18,7 @@ class cmExecutionStatus;
bool cmAddExecutableCommand::InitialPass(std::vector<std::string> const& args, bool cmAddExecutableCommand::InitialPass(std::vector<std::string> const& args,
cmExecutionStatus&) cmExecutionStatus&)
{ {
if (args.size() < 2) { if (args.empty()) {
this->SetError("called with incorrect number of arguments"); this->SetError("called with incorrect number of arguments");
return false; return false;
} }
@ -191,12 +191,6 @@ bool cmAddExecutableCommand::InitialPass(std::vector<std::string> const& args,
} }
} }
if (s == args.end()) {
this->SetError(
"called with incorrect number of arguments, no sources provided");
return false;
}
std::vector<std::string> srclists(s, args.end()); std::vector<std::string> srclists(s, args.end());
cmTarget* tgt = cmTarget* tgt =
this->Makefile->AddExecutable(exename.c_str(), srclists, excludeFromAll); this->Makefile->AddExecutable(exename.c_str(), srclists, excludeFromAll);

View File

@ -362,14 +362,6 @@ bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args,
return true; return true;
} }
if (s == args.end()) {
std::string msg = "You have called ADD_LIBRARY for library ";
msg += args[0];
msg += " without any source files. This typically indicates a problem ";
msg += "with your CMakeLists.txt file";
cmSystemTools::Message(msg.c_str(), "Warning");
}
srclists.insert(srclists.end(), s, args.end()); srclists.insert(srclists.end(), s, args.end());
this->Makefile->AddLibrary(libName, type, srclists, excludeFromAll); this->Makefile->AddLibrary(libName, type, srclists, excludeFromAll);

View File

@ -261,6 +261,43 @@ void cmGlobalGenerator::ForceLinkerLanguages()
{ {
} }
bool cmGlobalGenerator::CheckTargetsForMissingSources() const
{
bool failed = false;
for (cmLocalGenerator* localGen : this->LocalGenerators) {
const std::vector<cmGeneratorTarget*>& targets =
localGen->GetGeneratorTargets();
for (cmGeneratorTarget* target : targets) {
if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET ||
target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY ||
target->GetType() == cmStateEnums::TargetType::UTILITY) {
continue;
}
std::vector<std::string> configs;
target->Makefile->GetConfigurations(configs);
std::vector<cmSourceFile*> srcs;
if (configs.empty()) {
target->GetSourceFiles(srcs, "");
} else {
for (std::vector<std::string>::const_iterator ci = configs.begin();
ci != configs.end() && srcs.empty(); ++ci) {
target->GetSourceFiles(srcs, *ci);
}
}
if (srcs.empty()) {
std::ostringstream e;
e << "No SOURCES given to target: " << target->GetName();
this->GetCMakeInstance()->IssueMessage(cmake::FATAL_ERROR, e.str(),
target->GetBacktrace());
failed = true;
}
}
}
return failed;
}
bool cmGlobalGenerator::IsExportedTargetsFile( bool cmGlobalGenerator::IsExportedTargetsFile(
const std::string& filename) const const std::string& filename) const
{ {
@ -1292,6 +1329,11 @@ bool cmGlobalGenerator::Compute()
localGen->TraceDependencies(); localGen->TraceDependencies();
} }
// Make sure that all (non-imported) targets have source files added!
if (this->CheckTargetsForMissingSources()) {
return false;
}
this->ForceLinkerLanguages(); this->ForceLinkerLanguages();
// Compute the manifest of main targets generated. // Compute the manifest of main targets generated.

View File

@ -539,6 +539,8 @@ private:
virtual void ForceLinkerLanguages(); virtual void ForceLinkerLanguages();
bool CheckTargetsForMissingSources() const;
void CreateLocalGenerators(); void CreateLocalGenerators();
void CheckCompilerIdCompatibility(cmMakefile* mf, void CheckCompilerIdCompatibility(cmMakefile* mf,

View File

@ -1,4 +1,4 @@
^CMake Error at NoSources.cmake:[0-9]+ \(add_executable\): ^CMake Error at NoSources.cmake:[0-9]+ \(add_executable\):
add_executable called with incorrect number of arguments No SOURCES given to target: TestExeWithoutSources
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$ CMakeLists.txt:[0-9]+ \(include\)$

View File

@ -1,11 +1,4 @@
^CMake Error at NoSourcesButLinkObjects.cmake:[0-9]+ \(add_executable\): ^CMake Error at NoSourcesButLinkObjects.cmake:[0-9]+ \(add_executable\):
add_executable called with incorrect number of arguments No SOURCES given to target: TestExeWithoutSources
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)
CMake Error at NoSourcesButLinkObjects.cmake:[0-9]+ \(target_link_libraries\):
Cannot specify link libraries for target \"TestExeWithoutSources\" which is
not built by this project.
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$ CMakeLists.txt:[0-9]+ \(include\)$

View File

@ -1,11 +0,0 @@
^CMake Error at OnlyObjectSources.cmake:[0-9]+ \(add_executable\):
add_executable called with incorrect number of arguments
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)
CMake Error at OnlyObjectSources.cmake:[0-9]+ \(target_sources\):
Cannot specify sources for target \"TestExeWithoutSources\" which is not
built by this project.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$

View File

@ -1,3 +1,4 @@
^You have called ADD_LIBRARY for library TestModuleLibWithoutSources without any source files. This typically indicates a problem with your CMakeLists.txt file( ^CMake Error at MODULEwithNoSources.cmake:[0-9]+ \(add_library\):
CMake Error: CMake can not determine linker language for target: TestModuleLibWithoutSources)+( No SOURCES given to target: TestModuleLibWithoutSources
CMake Error: Cannot determine link language for target \"TestModuleLibWithoutSources\".)?$ Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$

View File

@ -1,3 +1,4 @@
^You have called ADD_LIBRARY for library TestModuleLibWithoutSources without any source files. This typically indicates a problem with your CMakeLists.txt file( ^CMake Error at MODULEwithNoSourcesButLinkObjects.cmake:[0-9]+ \(add_library\):
CMake Error: CMake can not determine linker language for target: TestModuleLibWithoutSources)+( No SOURCES given to target: TestModuleLibWithoutSources
CMake Error: Cannot determine link language for target \"TestModuleLibWithoutSources\".)*$ Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$

View File

@ -1 +0,0 @@
^You have called ADD_LIBRARY for library TestModuleLibWithoutSources without any source files. This typically indicates a problem with your CMakeLists.txt file$

View File

@ -1,2 +1,4 @@
^You have called ADD_LIBRARY for library TestObjectLibWithoutSources without any source files. This typically indicates a problem with your CMakeLists.txt file( ^CMake Error at OBJECTwithNoSources.cmake:[0-9]+ \(add_library\):
CMake Error: CMake can not determine linker language for target: TestObjectLibWithoutSources)*$ No SOURCES given to target: TestObjectLibWithoutSources
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$

View File

@ -1,5 +1,4 @@
^You have called ADD_LIBRARY for library TestObjectLibWithoutSources without any source files. This typically indicates a problem with your CMakeLists.txt file ^CMake Error at OBJECTwithNoSourcesButLinkObjects.cmake:[0-9]+ \(target_link_libraries\):
CMake Error at OBJECTwithNoSourcesButLinkObjects.cmake:[0-9]+ \(target_link_libraries\):
Object library target \"TestObjectLibWithoutSources\" may not link to Object library target \"TestObjectLibWithoutSources\" may not link to
anything. anything.
Call Stack \(most recent call first\): Call Stack \(most recent call first\):

View File

@ -1,5 +1,4 @@
^You have called ADD_LIBRARY for library TestObjectLibWithoutSources without any source files. This typically indicates a problem with your CMakeLists.txt file ^CMake Error at OBJECTwithOnlyObjectSources.cmake:[0-9]+ \(add_library\):
CMake Error at OBJECTwithOnlyObjectSources.cmake:[0-9]+ \(add_library\):
OBJECT library \"TestObjectLibWithoutSources\" contains: OBJECT library \"TestObjectLibWithoutSources\" contains:
[^ [^

View File

@ -1,3 +1,4 @@
^You have called ADD_LIBRARY for library TestSharedLibWithoutSources without any source files. This typically indicates a problem with your CMakeLists.txt file( ^CMake Error at SHAREDwithNoSources.cmake:[0-9]+ \(add_library\):
CMake Error: CMake can not determine linker language for target: TestSharedLibWithoutSources)+( No SOURCES given to target: TestSharedLibWithoutSources
CMake Error: Cannot determine link language for target \"TestSharedLibWithoutSources\".)*$ Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$

View File

@ -1,3 +1,4 @@
^You have called ADD_LIBRARY for library TestSharedLibWithoutSources without any source files. This typically indicates a problem with your CMakeLists.txt file( ^CMake Error at SHAREDwithNoSourcesButLinkObjects.cmake:[0-9]+ \(add_library\):
CMake Error: CMake can not determine linker language for target: TestSharedLibWithoutSources)+( No SOURCES given to target: TestSharedLibWithoutSources
CMake Error: Cannot determine link language for target \"TestSharedLibWithoutSources\".)*$ Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$

View File

@ -1 +0,0 @@
^You have called ADD_LIBRARY for library TestSharedLibWithoutSources without any source files. This typically indicates a problem with your CMakeLists.txt file$

View File

@ -1,3 +1,4 @@
^You have called ADD_LIBRARY for library TestStaticLibWithoutSources without any source files. This typically indicates a problem with your CMakeLists.txt file( ^CMake Error at STATICwithNoSources.cmake:[0-9]+ \(add_library\):
CMake Error: Cannot determine link language for target \"TestStaticLibWithoutSources\".)?( No SOURCES given to target: TestStaticLibWithoutSources
CMake Error: CMake can not determine linker language for target: TestStaticLibWithoutSources)+$ Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$

View File

@ -1,3 +1,4 @@
^You have called ADD_LIBRARY for library TestStaticLibWithoutSources without any source files. This typically indicates a problem with your CMakeLists.txt file( ^CMake Error at STATICwithNoSourcesButLinkObjects.cmake:[0-9]+ \(add_library\):
CMake Error: Cannot determine link language for target \"TestStaticLibWithoutSources\".)?( No SOURCES given to target: TestStaticLibWithoutSources
CMake Error: CMake can not determine linker language for target: TestStaticLibWithoutSources)+$ Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$

View File

@ -1 +0,0 @@
^You have called ADD_LIBRARY for library TestStaticLibWithoutSources without any source files. This typically indicates a problem with your CMakeLists.txt file$