diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index 130a033a8..0e61c9956 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -220,6 +220,16 @@ bool cmAddLibraryCommand ); return true; } + if(type == cmTarget::INTERFACE_LIBRARY) + { + if (!cmGeneratorExpression::IsValidTargetName(libName)) + { + cmOStringStream e; + e << "Invalid name for IMPORTED INTERFACE library target: " << libName; + this->SetError(e.str().c_str()); + return false; + } + } // Make sure the target does not already exist. if(this->Makefile->FindTargetToUse(libName.c_str())) diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index 086f27a58..6f3274ed9 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -99,6 +99,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector const& argv) { case cmTarget::SHARED_LIBRARY: case cmTarget::STATIC_LIBRARY: + case cmTarget::INTERFACE_LIBRARY: case cmTarget::UNKNOWN_LIBRARY: break; case cmTarget::EXECUTABLE: diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index cdc3316c4..243e5ce54 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -47,6 +47,10 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) } return false; } + if (te->GetType() == cmTarget::INTERFACE_LIBRARY) + { + this->GenerateRequiredCMakeVersion(os, "2.8.12.20131007"); // 2.8.13 + } } this->GenerateExpectedTargetsCode(os, expectedTargets); @@ -118,16 +122,22 @@ cmExportBuildFileGenerator // Collect import properties for this target. cmTarget* target = *tei; ImportPropertyMap properties; - this->SetImportLocationProperty(config, suffix, target, properties); + + if (target->GetType() != cmTarget::INTERFACE_LIBRARY) + { + this->SetImportLocationProperty(config, suffix, target, properties); + } if(!properties.empty()) { // Get the rest of the target details. - this->SetImportDetailProperties(config, suffix, - target, properties, missingTargets); - this->SetImportLinkInterface(config, suffix, - cmGeneratorExpression::BuildInterface, - target, properties, missingTargets); - + if (target->GetType() != cmTarget::INTERFACE_LIBRARY) + { + this->SetImportDetailProperties(config, suffix, + target, properties, missingTargets); + this->SetImportLinkInterface(config, suffix, + cmGeneratorExpression::BuildInterface, + target, properties, missingTargets); + } // TOOD: PUBLIC_HEADER_LOCATION // This should wait until the build feature propagation stuff diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index f059ceba6..be2ee3116 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -130,7 +130,8 @@ bool cmExportCommand if((target->GetType() == cmTarget::EXECUTABLE) || (target->GetType() == cmTarget::STATIC_LIBRARY) || (target->GetType() == cmTarget::SHARED_LIBRARY) || - (target->GetType() == cmTarget::MODULE_LIBRARY)) + (target->GetType() == cmTarget::MODULE_LIBRARY) || + (target->GetType() == cmTarget::INTERFACE_LIBRARY)) { targets.push_back(target); } diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index ef336ea47..8c841cbb3 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -378,11 +378,14 @@ void getCompatibleInterfaceProperties(cmTarget *target, if (!info) { - cmMakefile* mf = target->GetMakefile(); - cmOStringStream e; - e << "Exporting the target \"" << target->GetName() << "\" is not " - "allowed since its linker language cannot be determined"; - mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + if (target->GetType() != cmTarget::INTERFACE_LIBRARY) + { + cmMakefile* mf = target->GetMakefile(); + cmOStringStream e; + e << "Exporting the target \"" << target->GetName() << "\" is not " + "allowed since its linker language cannot be determined"; + mf->IssueMessage(cmake::FATAL_ERROR, e.str()); + } return; } @@ -887,6 +890,9 @@ cmExportFileGenerator case cmTarget::UNKNOWN_LIBRARY: os << "add_library(" << targetName << " UNKNOWN IMPORTED)\n"; break; + case cmTarget::INTERFACE_LIBRARY: + os << "add_library(" << targetName << " INTERFACE IMPORTED)\n"; + break; default: // should never happen break; } diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 2461ed6d9..8a00fa4e2 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -6164,7 +6164,8 @@ void cmTarget::ComputeImportInfo(std::string const& desired_config, const char* loc = 0; const char* imp = 0; std::string suffix; - if (!this->GetMappedConfig(desired_config, &loc, &imp, suffix)) + if (this->GetType() != INTERFACE_LIBRARY && + !this->GetMappedConfig(desired_config, &loc, &imp, suffix)) { return; } diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index 72ae78f57..62aa86cf8 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -426,3 +426,5 @@ export(TARGETS testExe2 testLib4 testLib5 testLib6 testExe3 testExe2lib NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake ) + +add_subdirectory(Interface) diff --git a/Tests/ExportImport/Export/Interface/CMakeLists.txt b/Tests/ExportImport/Export/Interface/CMakeLists.txt new file mode 100644 index 000000000..01e89ef6b --- /dev/null +++ b/Tests/ExportImport/Export/Interface/CMakeLists.txt @@ -0,0 +1,29 @@ + +add_library(headeronly INTERFACE) +set_property(TARGET headeronly PROPERTY INTERFACE_INCLUDE_DIRECTORIES + "$" + "$" +) +set_property(TARGET headeronly PROPERTY INTERFACE_COMPILE_DEFINITIONS "HEADERONLY_DEFINE") + +include(GenerateExportHeader) +add_library(sharedlib SHARED sharedlib.cpp) +generate_export_header(sharedlib) +set_property(TARGET sharedlib PROPERTY INCLUDE_DIRECTORIES + "${CMAKE_CURRENT_SOURCE_DIR}/sharedlib" + "${CMAKE_CURRENT_BINARY_DIR}" +) +set_property(TARGET sharedlib PROPERTY INTERFACE_INCLUDE_DIRECTORIES + "$" + "$/include/sharedlib>" +) + +set_property(TARGET sharedlib PROPERTY INTERFACE_COMPILE_DEFINITIONS "SHAREDLIB_DEFINE") + +add_library(sharediface INTERFACE) +target_link_libraries(sharediface INTERFACE sharedlib) + +export(TARGETS sharediface sharedlib headeronly + NAMESPACE bld_ + FILE ../ExportInterfaceBuildTree.cmake +) diff --git a/Tests/ExportImport/Export/Interface/headeronly/headeronly.h b/Tests/ExportImport/Export/Interface/headeronly/headeronly.h new file mode 100644 index 000000000..3673c2187 --- /dev/null +++ b/Tests/ExportImport/Export/Interface/headeronly/headeronly.h @@ -0,0 +1,7 @@ + +enum { one }; + +struct HeaderOnly +{ + int foo() const { return 0; } +}; diff --git a/Tests/ExportImport/Export/Interface/sharedlib.cpp b/Tests/ExportImport/Export/Interface/sharedlib.cpp new file mode 100644 index 000000000..88ca7130f --- /dev/null +++ b/Tests/ExportImport/Export/Interface/sharedlib.cpp @@ -0,0 +1,7 @@ + +#include "sharedlib.h" + +int SharedLibObject::foo() const +{ + return 0; +} diff --git a/Tests/ExportImport/Export/Interface/sharedlib/sharedlib.h b/Tests/ExportImport/Export/Interface/sharedlib/sharedlib.h new file mode 100644 index 000000000..aad9ef3f4 --- /dev/null +++ b/Tests/ExportImport/Export/Interface/sharedlib/sharedlib.h @@ -0,0 +1,7 @@ + +#include "sharedlib_export.h" + +struct SHAREDLIB_EXPORT SharedLibObject +{ + int foo() const; +}; diff --git a/Tests/ExportImport/Import/CMakeLists.txt b/Tests/ExportImport/Import/CMakeLists.txt index 9c2d5977c..5e809a27d 100644 --- a/Tests/ExportImport/Import/CMakeLists.txt +++ b/Tests/ExportImport/Import/CMakeLists.txt @@ -19,3 +19,6 @@ add_executable(imp_testTransExe1b imp_testTransExe1.c) target_link_libraries(imp_testTransExe1b imp_lib1b) add_subdirectory(try_compile) + +# Test package INTERFACE controls +add_subdirectory(Interface) diff --git a/Tests/ExportImport/Import/Interface/CMakeLists.txt b/Tests/ExportImport/Import/Interface/CMakeLists.txt new file mode 100644 index 000000000..c8c840198 --- /dev/null +++ b/Tests/ExportImport/Import/Interface/CMakeLists.txt @@ -0,0 +1,42 @@ + +# Import targets from the exported build tree. +include(${Import_BINARY_DIR}/../Export/ExportInterfaceBuildTree.cmake) + +add_library(define_iface INTERFACE) +set_property(TARGET define_iface PROPERTY + INTERFACE_COMPILE_DEFINITIONS DEFINE_IFACE_DEFINE) + +add_executable(headeronlytest_bld headeronlytest.cpp) +target_link_libraries(headeronlytest_bld bld_headeronly) + +set_property(TARGET bld_sharediface APPEND PROPERTY INTERFACE_LINK_LIBRARIES define_iface) + +add_executable(interfacetest_bld interfacetest.cpp) +target_link_libraries(interfacetest_bld bld_sharediface) + +include(CheckCXXSourceCompiles) + +macro(do_try_compile prefix) + + set(CMAKE_REQUIRED_LIBRARIES ${prefix}headeronly) + check_cxx_source_compiles( + " + #include \"headeronly.h\" + + #ifndef HEADERONLY_DEFINE + #error Expected HEADERONLY_DEFINE + #endif + + int main(int,char**) + { + HeaderOnly ho; + return ho.foo(); + } + " ${prefix}IFACE_TRY_COMPILE) + + if(NOT ${prefix}IFACE_TRY_COMPILE) + message(SEND_ERROR "${prefix} try_compile with IMPORTED INTERFACE target failed!\n\n${OUTPUT}") + endif() +endmacro() + +do_try_compile(bld_) diff --git a/Tests/ExportImport/Import/Interface/headeronlytest.cpp b/Tests/ExportImport/Import/Interface/headeronlytest.cpp new file mode 100644 index 000000000..20674a725 --- /dev/null +++ b/Tests/ExportImport/Import/Interface/headeronlytest.cpp @@ -0,0 +1,17 @@ + +#include "headeronly.h" + +#ifndef HEADERONLY_DEFINE +#error Expected HEADERONLY_DEFINE +#endif + +#ifdef SHAREDLIB_DEFINE +#error Unexpected SHAREDLIB_DEFINE +#endif + + +int main(int,char**) +{ + HeaderOnly ho; + return ho.foo(); +} diff --git a/Tests/ExportImport/Import/Interface/interfacetest.cpp b/Tests/ExportImport/Import/Interface/interfacetest.cpp new file mode 100644 index 000000000..786458d19 --- /dev/null +++ b/Tests/ExportImport/Import/Interface/interfacetest.cpp @@ -0,0 +1,20 @@ + +#include "sharedlib.h" + +#ifndef SHAREDLIB_DEFINE +#error Expected SHAREDLIB_DEFINE +#endif + +#ifdef HEADERONLY_DEFINE +#error Unexpected HEADERONLY_DEFINE +#endif + +#ifndef DEFINE_IFACE_DEFINE +#error Expected DEFINE_IFACE_DEFINE +#endif + +int main(int,char**) +{ + SharedLibObject slo; + return slo.foo(); +} diff --git a/Tests/RunCMake/interface_library/invalid_name-stderr.txt b/Tests/RunCMake/interface_library/invalid_name-stderr.txt index c66e0800a..e14fcdedb 100644 --- a/Tests/RunCMake/interface_library/invalid_name-stderr.txt +++ b/Tests/RunCMake/interface_library/invalid_name-stderr.txt @@ -7,3 +7,9 @@ CMake Error at invalid_name.cmake:4 \(add_library\): add_library Invalid name for INTERFACE library target: iface::target Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_name.cmake:6 \(add_library\): + add_library Invalid name for IMPORTED INTERFACE library target: + if\$target_imported +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/interface_library/invalid_name.cmake b/Tests/RunCMake/interface_library/invalid_name.cmake index 51a109d32..9a965aa8a 100644 --- a/Tests/RunCMake/interface_library/invalid_name.cmake +++ b/Tests/RunCMake/interface_library/invalid_name.cmake @@ -2,3 +2,5 @@ add_library(if$ace INTERFACE) add_library(iface::target INTERFACE) + +add_library(if$target_imported INTERFACE IMPORTED)