From 9eb06d0dde52203d3f8ac91ea9a1c5396a09f8af Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Tue, 31 Dec 2013 14:52:07 +0100 Subject: [PATCH] add_library: Disallow invalid signatures for INTERFACE_LIBRARY. Document the valid signatures. Add a test for the IMPORTED GLOBAL signature. --- Help/command/add_library.rst | 17 +++- Source/cmAddLibraryCommand.cxx | 88 ++++++++++++++++++ Tests/InterfaceLibrary/CMakeLists.txt | 2 +- Tests/InterfaceLibrary/libsdir/CMakeLists.txt | 2 + .../interface_library/RunCMakeTest.cmake | 1 + .../invalid_signature-result.txt | 1 + .../invalid_signature-stderr.txt | 89 +++++++++++++++++++ .../interface_library/invalid_signature.cmake | 20 +++++ 8 files changed, 215 insertions(+), 5 deletions(-) create mode 100644 Tests/RunCMake/interface_library/invalid_signature-result.txt create mode 100644 Tests/RunCMake/interface_library/invalid_signature-stderr.txt create mode 100644 Tests/RunCMake/interface_library/invalid_signature.cmake diff --git a/Help/command/add_library.rst b/Help/command/add_library.rst index 45f1102cb..2d69c89b1 100644 --- a/Help/command/add_library.rst +++ b/Help/command/add_library.rst @@ -109,12 +109,21 @@ The signature :: - add_library( INTERFACE) + add_library( INTERFACE [IMPORTED [GLOBAL]]) creates an interface target. An interface target does not directly create build output, though it may have properties set on it and it may be installed, exported and imported. Typically the INTERFACE_* properties are populated on the interface target using the -set_property(), target_link_libraries(), target_include_directories() -and target_compile_defintions() commands, and then it is used as an -argument to target_link_libraries() like any other target. +:command:`set_property`, :command:`target_link_libraries`, +:command:`target_include_directories` +and :command:`target_compile_defintions` commands, and then it is used as an +argument to :command:`target_link_libraries` like any other target. + +An ``INTERFACE`` :prop_tgt:`IMPORTED` target may also be created with this +signature. An :prop_tgt:`IMPORTED` library target references a library defined +outside the project. The target name has scope in the directory in which it is +created and below, but the ``GLOBAL`` option extends visibility. It may be +referenced like any target built within the project. :prop_tgt:`IMPORTED` +libraries are useful for convenient reference from commands like +:command:`target_link_libraries`. diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index 0f98f352c..262744560 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -49,47 +49,117 @@ bool cmAddLibraryCommand std::string libType = *s; if(libType == "STATIC") { + if (type == cmTarget::INTERFACE_LIBRARY) + { + cmOStringStream e; + e << "INTERFACE library specified with conflicting STATIC type."; + this->SetError(e.str().c_str()); + return false; + } ++s; type = cmTarget::STATIC_LIBRARY; haveSpecifiedType = true; } else if(libType == "SHARED") { + if (type == cmTarget::INTERFACE_LIBRARY) + { + cmOStringStream e; + e << "INTERFACE library specified with conflicting SHARED type."; + this->SetError(e.str().c_str()); + return false; + } ++s; type = cmTarget::SHARED_LIBRARY; haveSpecifiedType = true; } else if(libType == "MODULE") { + if (type == cmTarget::INTERFACE_LIBRARY) + { + cmOStringStream e; + e << "INTERFACE library specified with conflicting MODULE type."; + this->SetError(e.str().c_str()); + return false; + } ++s; type = cmTarget::MODULE_LIBRARY; haveSpecifiedType = true; } else if(libType == "OBJECT") { + if (type == cmTarget::INTERFACE_LIBRARY) + { + cmOStringStream e; + e << "INTERFACE library specified with conflicting OBJECT type."; + this->SetError(e.str().c_str()); + return false; + } ++s; type = cmTarget::OBJECT_LIBRARY; haveSpecifiedType = true; } else if(libType == "UNKNOWN") { + if (type == cmTarget::INTERFACE_LIBRARY) + { + cmOStringStream e; + e << "INTERFACE library specified with conflicting UNKNOWN type."; + this->SetError(e.str().c_str()); + return false; + } ++s; type = cmTarget::UNKNOWN_LIBRARY; haveSpecifiedType = true; } else if(libType == "ALIAS") { + if (type == cmTarget::INTERFACE_LIBRARY) + { + cmOStringStream e; + e << "INTERFACE library specified with conflicting ALIAS type."; + this->SetError(e.str().c_str()); + return false; + } ++s; isAlias = true; } else if(libType == "INTERFACE") { + if (haveSpecifiedType) + { + cmOStringStream e; + e << "INTERFACE library specified with conflicting/multiple types."; + this->SetError(e.str().c_str()); + return false; + } + if (isAlias) + { + cmOStringStream e; + e << "INTERFACE library specified with conflicting ALIAS type."; + this->SetError(e.str().c_str()); + return false; + } + if (excludeFromAll) + { + cmOStringStream e; + e << "INTERFACE library may not be used with EXCLUDE_FROM_ALL."; + this->SetError(e.str().c_str()); + return false; + } ++s; type = cmTarget::INTERFACE_LIBRARY; haveSpecifiedType = true; } else if(*s == "EXCLUDE_FROM_ALL") { + if (type == cmTarget::INTERFACE_LIBRARY) + { + cmOStringStream e; + e << "INTERFACE library may not be used with EXCLUDE_FROM_ALL."; + this->SetError(e.str().c_str()); + return false; + } ++s; excludeFromAll = true; } @@ -109,6 +179,24 @@ bool cmAddLibraryCommand } } + if (type == cmTarget::INTERFACE_LIBRARY) + { + if (s != args.end()) + { + cmOStringStream e; + e << "INTERFACE library requires no source arguments."; + this->SetError(e.str().c_str()); + return false; + } + if (importGlobal && !importTarget) + { + cmOStringStream e; + e << "INTERFACE library specified as GLOBAL, but not as IMPORTED."; + this->SetError(e.str().c_str()); + return false; + } + } + bool nameOk = cmGeneratorExpression::IsValidTargetName(libName) && !cmGlobalGenerator::IsReservedTarget(libName); diff --git a/Tests/InterfaceLibrary/CMakeLists.txt b/Tests/InterfaceLibrary/CMakeLists.txt index 396a84af9..b396eb633 100644 --- a/Tests/InterfaceLibrary/CMakeLists.txt +++ b/Tests/InterfaceLibrary/CMakeLists.txt @@ -14,7 +14,7 @@ target_link_libraries(InterfaceLibrary iface_nodepends headeriface) add_subdirectory(libsdir) add_executable(sharedlibtestexe sharedlibtestexe.cpp) -target_link_libraries(sharedlibtestexe shared_iface) +target_link_libraries(sharedlibtestexe shared_iface imported::iface) add_library(broken EXCLUDE_FROM_ALL broken.cpp) diff --git a/Tests/InterfaceLibrary/libsdir/CMakeLists.txt b/Tests/InterfaceLibrary/libsdir/CMakeLists.txt index 699964656..4e529dfb1 100644 --- a/Tests/InterfaceLibrary/libsdir/CMakeLists.txt +++ b/Tests/InterfaceLibrary/libsdir/CMakeLists.txt @@ -24,3 +24,5 @@ target_compile_definitions(shareddependlib add_library(shared_iface INTERFACE) target_link_libraries(shared_iface INTERFACE sharedlib) + +add_library(imported::iface INTERFACE IMPORTED GLOBAL) diff --git a/Tests/RunCMake/interface_library/RunCMakeTest.cmake b/Tests/RunCMake/interface_library/RunCMakeTest.cmake index d76600c35..9ca9a7714 100644 --- a/Tests/RunCMake/interface_library/RunCMakeTest.cmake +++ b/Tests/RunCMake/interface_library/RunCMakeTest.cmake @@ -4,5 +4,6 @@ run_cmake(invalid_name) run_cmake(target_commands) run_cmake(no_shared_libs) run_cmake(whitelist) +run_cmake(invalid_signature) run_cmake(genex_link) run_cmake(add_dependencies) diff --git a/Tests/RunCMake/interface_library/invalid_signature-result.txt b/Tests/RunCMake/interface_library/invalid_signature-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/interface_library/invalid_signature-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/interface_library/invalid_signature-stderr.txt b/Tests/RunCMake/interface_library/invalid_signature-stderr.txt new file mode 100644 index 000000000..701586a8d --- /dev/null +++ b/Tests/RunCMake/interface_library/invalid_signature-stderr.txt @@ -0,0 +1,89 @@ +CMake Error at invalid_signature.cmake:2 \(add_library\): + add_library INTERFACE library requires no source arguments. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:3 \(add_library\): + add_library INTERFACE library specified with conflicting/multiple types. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:4 \(add_library\): + add_library INTERFACE library specified with conflicting/multiple types. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:5 \(add_library\): + add_library INTERFACE library specified with conflicting/multiple types. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:6 \(add_library\): + add_library INTERFACE library specified with conflicting/multiple types. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:7 \(add_library\): + add_library INTERFACE library specified with conflicting/multiple types. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:8 \(add_library\): + add_library INTERFACE library specified with conflicting/multiple types. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:9 \(add_library\): + add_library INTERFACE library specified with conflicting STATIC type. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:10 \(add_library\): + add_library INTERFACE library specified with conflicting SHARED type. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:11 \(add_library\): + add_library INTERFACE library specified with conflicting MODULE type. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:12 \(add_library\): + add_library INTERFACE library specified with conflicting OBJECT type. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:13 \(add_library\): + add_library INTERFACE library specified with conflicting UNKNOWN type. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:14 \(add_library\): + add_library INTERFACE library specified with conflicting ALIAS type. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:15 \(add_library\): + add_library INTERFACE library specified with conflicting ALIAS type. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:16 \(add_library\): + add_library INTERFACE library specified with conflicting/multiple types. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:17 \(add_library\): + add_library INTERFACE library may not be used with EXCLUDE_FROM_ALL. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:18 \(add_library\): + add_library INTERFACE library may not be used with EXCLUDE_FROM_ALL. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) ++ +CMake Error at invalid_signature.cmake:20 \(add_library\): + add_library INTERFACE library requires no source arguments. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/interface_library/invalid_signature.cmake b/Tests/RunCMake/interface_library/invalid_signature.cmake new file mode 100644 index 000000000..67e326743 --- /dev/null +++ b/Tests/RunCMake/interface_library/invalid_signature.cmake @@ -0,0 +1,20 @@ + +add_library(iface1 INTERFACE empty.cpp) +add_library(iface3 STATIC INTERFACE) +add_library(iface4 STATIC INTERFACE empty.cpp) +add_library(iface5 SHARED INTERFACE) +add_library(iface6 MODULE INTERFACE) +add_library(iface7 OBJECT INTERFACE) +add_library(iface8 UNKNOWN INTERFACE) +add_library(iface9 INTERFACE STATIC) +add_library(iface10 INTERFACE SHARED) +add_library(iface11 INTERFACE MODULE) +add_library(iface12 INTERFACE OBJECT) +add_library(iface13 INTERFACE UNKNOWN) +add_library(iface14 INTERFACE ALIAS) +add_library(iface15 ALIAS INTERFACE) +add_library(iface16 INTERFACE INTERFACE) +add_library(iface17 INTERFACE EXCLUDE_FROM_ALL) +add_library(iface18 EXCLUDE_FROM_ALL INTERFACE) +add_library(iface19 GLOBAL INTERFACE) +add_library(iface20 INTERFACE GLOBAL)