Create make rules for INTERFACE_LIBRARY targets.
The result is that the depends of the target are created. So, add_library(somelib foo.cpp) add_library(anotherlib EXCLUDE_FROM_ALL foo.cpp) add_library(extra EXCLUDE_FROM_ALL foo.cpp) target_link_libraries(anotherlib extra) add_library(iface INTERFACE) target_link_libraries(iface INTERFACE anotherlib) Executing 'make iface' will result in the anotherlib and extra targets being made. Adding a regular executable to the INTERFACE of an INTERFACE_LIBRARY will not result in the executable being built with 'make iface' because of the logic in cmComputeTargetDepends::AddTargetDepend. So far, this is implemented only for the Makefile generator. Other generators will follow if this feature is possible for them. Make INTERFACE_LIBRARY targets part of the all target by default. Test this by building the all target and making the expected library EXCLUDE_FROM_ALL.
This commit is contained in:
parent
dba4962b86
commit
b04f3b9a2a
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
int main(int, char**)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
void testlib(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue