Merge topic 'INTERFACE_LIBRARY-build-targets'

b04f3b9 Create make rules for INTERFACE_LIBRARY targets.
dba4962 Makefile: Always create clean target command
This commit is contained in:
Brad King 2013-10-21 09:48:04 -04:00 committed by CMake Topic Stage
commit bf02e75079
11 changed files with 172 additions and 75 deletions

View File

@ -208,7 +208,15 @@ void cmComputeTargetDepends::CollectTargetDepends(int depender_index)
std::set<cmStdString> emitted; std::set<cmStdString> emitted;
{ {
std::vector<std::string> tlibs; std::vector<std::string> tlibs;
depender->GetDirectLinkLibraries(0, tlibs, depender); if (depender->GetType() == cmTarget::INTERFACE_LIBRARY)
{
// For INTERFACE_LIBRARY depend on the interface instead.
depender->GetInterfaceLinkLibraries(0, tlibs, depender);
}
else
{
depender->GetDirectLinkLibraries(0, tlibs, depender);
}
// A target should not depend on itself. // A target should not depend on itself.
emitted.insert(depender->GetName()); emitted.insert(depender->GetName());
for(std::vector<std::string>::const_iterator lib = tlibs.begin(); for(std::vector<std::string>::const_iterator lib = tlibs.begin();

View File

@ -435,6 +435,7 @@ cmGlobalUnixMakefileGenerator3
(l->second.GetType() == cmTarget::SHARED_LIBRARY) || (l->second.GetType() == cmTarget::SHARED_LIBRARY) ||
(l->second.GetType() == cmTarget::MODULE_LIBRARY) || (l->second.GetType() == cmTarget::MODULE_LIBRARY) ||
(l->second.GetType() == cmTarget::OBJECT_LIBRARY) || (l->second.GetType() == cmTarget::OBJECT_LIBRARY) ||
(l->second.GetType() == cmTarget::INTERFACE_LIBRARY) ||
(l->second.GetType() == cmTarget::UTILITY)) (l->second.GetType() == cmTarget::UTILITY))
{ {
// Add this to the list of depends rules in this directory. // Add this to the list of depends rules in this directory.
@ -612,6 +613,7 @@ cmGlobalUnixMakefileGenerator3
(t->second.GetType() == cmTarget::SHARED_LIBRARY) || (t->second.GetType() == cmTarget::SHARED_LIBRARY) ||
(t->second.GetType() == cmTarget::MODULE_LIBRARY) || (t->second.GetType() == cmTarget::MODULE_LIBRARY) ||
(t->second.GetType() == cmTarget::OBJECT_LIBRARY) || (t->second.GetType() == cmTarget::OBJECT_LIBRARY) ||
(t->second.GetType() == cmTarget::INTERFACE_LIBRARY) ||
(t->second.GetType() == cmTarget::UTILITY))) (t->second.GetType() == cmTarget::UTILITY)))
{ {
// Add a rule to build the target by name. // Add a rule to build the target by name.
@ -633,6 +635,10 @@ cmGlobalUnixMakefileGenerator3
t->second.GetName(), depends, commands, t->second.GetName(), depends, commands,
true); true);
if (t->second.GetType() == cmTarget::INTERFACE_LIBRARY)
{
continue;
}
// Add a fast rule to build the target // Add a fast rule to build the target
std::string localName = lg->GetRelativeTargetDirectory(t->second); std::string localName = lg->GetRelativeTargetDirectory(t->second);
std::string makefileName; std::string makefileName;
@ -699,6 +705,7 @@ cmGlobalUnixMakefileGenerator3
|| (t->second.GetType() == cmTarget::SHARED_LIBRARY) || (t->second.GetType() == cmTarget::SHARED_LIBRARY)
|| (t->second.GetType() == cmTarget::MODULE_LIBRARY) || (t->second.GetType() == cmTarget::MODULE_LIBRARY)
|| (t->second.GetType() == cmTarget::OBJECT_LIBRARY) || (t->second.GetType() == cmTarget::OBJECT_LIBRARY)
|| (t->second.GetType() == cmTarget::INTERFACE_LIBRARY)
|| (t->second.GetType() == cmTarget::UTILITY))) || (t->second.GetType() == cmTarget::UTILITY)))
{ {
std::string makefileName; std::string makefileName;
@ -715,53 +722,64 @@ cmGlobalUnixMakefileGenerator3
<< localName << "\n\n"; << localName << "\n\n";
commands.clear(); commands.clear();
makeTargetName = localName;
makeTargetName += "/depend";
commands.push_back(lg->GetRecursiveMakeCall
(makefileName.c_str(),makeTargetName.c_str()));
// add requires if we need it for this generator if(t->second.GetType() != cmTarget::INTERFACE_LIBRARY)
if (needRequiresStep)
{ {
makeTargetName = localName; makeTargetName = localName;
makeTargetName += "/requires"; makeTargetName += "/depend";
commands.push_back(lg->GetRecursiveMakeCall commands.push_back(lg->GetRecursiveMakeCall
(makefileName.c_str(),makeTargetName.c_str()));
}
makeTargetName = localName;
makeTargetName += "/build";
commands.push_back(lg->GetRecursiveMakeCall
(makefileName.c_str(),makeTargetName.c_str())); (makefileName.c_str(),makeTargetName.c_str()));
// Write the rule. // add requires if we need it for this generator
localName += "/all"; if (needRequiresStep)
depends.clear();
std::string progressDir =
lg->GetMakefile()->GetHomeOutputDirectory();
progressDir += cmake::GetCMakeFilesDirectory();
{
cmOStringStream progCmd;
progCmd << "$(CMAKE_COMMAND) -E cmake_progress_report ";
// all target counts
progCmd << lg->Convert(progressDir.c_str(),
cmLocalGenerator::FULL,
cmLocalGenerator::SHELL);
progCmd << " ";
std::vector<unsigned long>& progFiles =
this->ProgressMap[&t->second].Marks;
for (std::vector<unsigned long>::iterator i = progFiles.begin();
i != progFiles.end(); ++i)
{ {
progCmd << " " << *i; makeTargetName = localName;
makeTargetName += "/requires";
commands.push_back(lg->GetRecursiveMakeCall
(makefileName.c_str(),makeTargetName.c_str()));
} }
commands.push_back(progCmd.str()); makeTargetName = localName;
} makeTargetName += "/build";
progressDir = "Built target "; commands.push_back(lg->GetRecursiveMakeCall
progressDir += t->first; (makefileName.c_str(),makeTargetName.c_str()));
lg->AppendEcho(commands,progressDir.c_str());
// Write the rule.
localName += "/all";
depends.clear();
std::string progressDir =
lg->GetMakefile()->GetHomeOutputDirectory();
progressDir += cmake::GetCMakeFilesDirectory();
{
cmOStringStream progCmd;
progCmd << "$(CMAKE_COMMAND) -E cmake_progress_report ";
// all target counts
progCmd << lg->Convert(progressDir.c_str(),
cmLocalGenerator::FULL,
cmLocalGenerator::SHELL);
progCmd << " ";
std::vector<unsigned long>& progFiles =
this->ProgressMap[&t->second].Marks;
for (std::vector<unsigned long>::iterator i = progFiles.begin();
i != progFiles.end(); ++i)
{
progCmd << " " << *i;
}
commands.push_back(progCmd.str());
}
progressDir = "Built target ";
progressDir += t->first;
lg->AppendEcho(commands,progressDir.c_str());
}
else
{
depends.clear();
}
this->AppendGlobalTargetDepends(depends,t->second); this->AppendGlobalTargetDepends(depends,t->second);
if(depends.empty() && this->EmptyRuleHackDepends != "")
{
depends.push_back(this->EmptyRuleHackDepends);
}
lg->WriteMakeRule(ruleFileStream, "All Build rule for target.", lg->WriteMakeRule(ruleFileStream, "All Build rule for target.",
localName.c_str(), depends, commands, true); localName.c_str(), depends, commands, true);
@ -777,7 +795,7 @@ cmGlobalUnixMakefileGenerator3
// Write the rule. // Write the rule.
commands.clear(); commands.clear();
progressDir = lg->GetMakefile()->GetHomeOutputDirectory(); std::string progressDir = lg->GetMakefile()->GetHomeOutputDirectory();
progressDir += cmake::GetCMakeFilesDirectory(); progressDir += cmake::GetCMakeFilesDirectory();
{ {

View File

@ -381,6 +381,7 @@ void cmLocalUnixMakefileGenerator3
(t->second.GetType() == cmTarget::SHARED_LIBRARY) || (t->second.GetType() == cmTarget::SHARED_LIBRARY) ||
(t->second.GetType() == cmTarget::MODULE_LIBRARY) || (t->second.GetType() == cmTarget::MODULE_LIBRARY) ||
(t->second.GetType() == cmTarget::OBJECT_LIBRARY) || (t->second.GetType() == cmTarget::OBJECT_LIBRARY) ||
(t->second.GetType() == cmTarget::INTERFACE_LIBRARY) ||
(t->second.GetType() == cmTarget::UTILITY)) (t->second.GetType() == cmTarget::UTILITY))
{ {
emitted.insert(t->second.GetName()); emitted.insert(t->second.GetName());
@ -1158,27 +1159,25 @@ cmLocalUnixMakefileGenerator3
const std::vector<std::string>& files, const std::vector<std::string>& files,
cmTarget& target, const char* filename) cmTarget& target, const char* filename)
{ {
std::string cleanfile = this->Makefile->GetCurrentOutputDirectory();
cleanfile += "/";
cleanfile += this->GetTargetDirectory(target);
cleanfile += "/cmake_clean";
if(filename)
{
cleanfile += "_";
cleanfile += filename;
}
cleanfile += ".cmake";
std::string cleanfilePath = this->Convert(cleanfile.c_str(), FULL);
std::ofstream fout(cleanfilePath.c_str());
if(!fout)
{
cmSystemTools::Error("Could not create ", cleanfilePath.c_str());
}
if(!files.empty()) if(!files.empty())
{ {
std::string cleanfile = this->Makefile->GetCurrentOutputDirectory();
cleanfile += "/";
cleanfile += this->GetTargetDirectory(target);
cleanfile += "/cmake_clean";
if(filename)
{
cleanfile += "_";
cleanfile += filename;
}
cleanfile += ".cmake";
std::string cleanfilePath = this->Convert(cleanfile.c_str(), FULL);
std::ofstream fout(cleanfilePath.c_str());
if(!fout)
{
cmSystemTools::Error("Could not create ", cleanfilePath.c_str());
}
fout << "file(REMOVE_RECURSE\n"; fout << "file(REMOVE_RECURSE\n";
std::string remove = "$(CMAKE_COMMAND) -P ";
remove += this->Convert(cleanfile.c_str(), START_OUTPUT, SHELL);
for(std::vector<std::string>::const_iterator f = files.begin(); for(std::vector<std::string>::const_iterator f = files.begin();
f != files.end(); ++f) f != files.end(); ++f)
{ {
@ -1186,27 +1185,29 @@ cmLocalUnixMakefileGenerator3
fout << " " << this->EscapeForCMake(fc.c_str()) << "\n"; fout << " " << this->EscapeForCMake(fc.c_str()) << "\n";
} }
fout << ")\n"; fout << ")\n";
commands.push_back(remove); }
std::string remove = "$(CMAKE_COMMAND) -P ";
remove += this->Convert(cleanfile.c_str(), START_OUTPUT, SHELL);
commands.push_back(remove);
// For the main clean rule add per-language cleaning. // For the main clean rule add per-language cleaning.
if(!filename) if(!filename)
{
// Get the set of source languages in the target.
std::set<cmStdString> languages;
target.GetLanguages(languages);
fout << "\n"
<< "# Per-language clean rules from dependency scanning.\n"
<< "foreach(lang";
for(std::set<cmStdString>::const_iterator l = languages.begin();
l != languages.end(); ++l)
{ {
// Get the set of source languages in the target. fout << " " << *l;
std::set<cmStdString> languages;
target.GetLanguages(languages);
fout << "\n"
<< "# Per-language clean rules from dependency scanning.\n"
<< "foreach(lang";
for(std::set<cmStdString>::const_iterator l = languages.begin();
l != languages.end(); ++l)
{
fout << " " << *l;
}
fout << ")\n"
<< " include(" << this->GetTargetDirectory(target)
<< "/cmake_clean_${lang}.cmake OPTIONAL)\n"
<< "endforeach()\n";
} }
fout << ")\n"
<< " include(" << this->GetTargetDirectory(target)
<< "/cmake_clean_${lang}.cmake OPTIONAL)\n"
<< "endforeach()\n";
} }
} }

View File

@ -82,6 +82,9 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
case cmTarget::OBJECT_LIBRARY: case cmTarget::OBJECT_LIBRARY:
this->WriteObjectLibraryRules(); this->WriteObjectLibraryRules();
break; break;
case cmTarget::INTERFACE_LIBRARY:
// Nothing to do.
break;
default: default:
// If language is not known, this is an error. // If language is not known, this is an error.
cmSystemTools::Error("Unknown Library Type"); cmSystemTools::Error("Unknown Library Type");

View File

@ -75,6 +75,7 @@ cmMakefileTargetGenerator::New(cmTarget *tgt)
case cmTarget::SHARED_LIBRARY: case cmTarget::SHARED_LIBRARY:
case cmTarget::MODULE_LIBRARY: case cmTarget::MODULE_LIBRARY:
case cmTarget::OBJECT_LIBRARY: case cmTarget::OBJECT_LIBRARY:
case cmTarget::INTERFACE_LIBRARY:
result = new cmMakefileLibraryTargetGenerator(tgt); result = new cmMakefileLibraryTargetGenerator(tgt);
break; break;
case cmTarget::UTILITY: case cmTarget::UTILITY:

View File

@ -1111,6 +1111,29 @@ void cmTarget::GetDirectLinkLibraries(const char *config,
} }
} }
//----------------------------------------------------------------------------
void cmTarget::GetInterfaceLinkLibraries(const char *config,
std::vector<std::string> &libs, cmTarget *head)
{
const char *prop = this->GetProperty("INTERFACE_LINK_LIBRARIES");
if (prop)
{
cmListFileBacktrace lfbt;
cmGeneratorExpression ge(lfbt);
const cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop);
cmGeneratorExpressionDAGChecker dagChecker(lfbt,
this->GetName(),
"INTERFACE_LINK_LIBRARIES", 0, 0);
cmSystemTools::ExpandListArgument(cge->Evaluate(this->Makefile,
config,
false,
head,
&dagChecker),
libs);
}
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
std::string cmTarget::GetDebugGeneratorExpressions(const std::string &value, std::string cmTarget::GetDebugGeneratorExpressions(const std::string &value,
cmTarget::LinkLibraryType llt) cmTarget::LinkLibraryType llt)

View File

@ -177,6 +177,9 @@ public:
void GetDirectLinkLibraries(const char *config, void GetDirectLinkLibraries(const char *config,
std::vector<std::string> &, std::vector<std::string> &,
cmTarget *head); cmTarget *head);
void GetInterfaceLinkLibraries(const char *config,
std::vector<std::string> &,
cmTarget *head);
/** Compute the link type to use for the given configuration. */ /** Compute the link type to use for the given configuration. */
LinkLibraryType ComputeLinkType(const char* config); LinkLibraryType ComputeLinkType(const char* config);

View File

@ -261,6 +261,23 @@ if(BUILD_TESTING)
PASS_REGULAR_EXPRESSION "(file is not of required architecture|does not match cputype|not the architecture being linked)") PASS_REGULAR_EXPRESSION "(file is not of required architecture|does not match cputype|not the architecture being linked)")
endif() endif()
if(CMAKE_TEST_GENERATOR MATCHES Make)
set(InterfaceBuildTargets_libname testlib)
if (CMAKE_TEST_GENERATOR MATCHES "Borland|Watcom")
set(InterfaceBuildTargets_libname testlib.lib)
endif()
add_test(InterfaceBuildTargets ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/InterfaceBuildTargets"
"${CMake_BINARY_DIR}/Tests/InterfaceBuildTargets"
--build-two-config
${build_generator_args}
--build-project InterfaceBuildTargets
--test-command ${CMAKE_CMAKE_COMMAND} -E touch_nocreate ${InterfaceBuildTargets_libname}
)
list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/InterfaceBuildTargets")
endif()
list(APPEND TEST_BUILD_DIRS ${CMake_TEST_INSTALL_PREFIX}) list(APPEND TEST_BUILD_DIRS ${CMake_TEST_INSTALL_PREFIX})
if(NOT QT4_FOUND) if(NOT QT4_FOUND)

View File

@ -0,0 +1,13 @@
project(InterfaceBuildTargets)
add_library(testlib EXCLUDE_FROM_ALL testlib.cxx)
set_property(TARGET testlib PROPERTY PREFIX "")
if(CMAKE_GENERATOR MATCHES "Borland|Watcom")
# These librarians add the .lib suffix anyway.
set_property(TARGET testlib PROPERTY SUFFIX ".lib")
else()
set_property(TARGET testlib PROPERTY SUFFIX "")
endif()
add_library(iface INTERFACE)
target_link_libraries(iface INTERFACE testlib)

View File

@ -0,0 +1,5 @@
int main(int, char**)
{
return 0;
}

View File

@ -0,0 +1,5 @@
void testlib(void)
{
}