diff options
-rw-r--r-- | Source/cmCommands.cxx | 3 | ||||
-rw-r--r-- | Source/cmTargetIncludeDirectoriesCommand.cxx | 74 | ||||
-rw-r--r-- | Source/cmTargetIncludeDirectoriesCommand.h | 95 | ||||
-rw-r--r-- | Source/cmTargetPropCommandBase.cxx | 144 | ||||
-rw-r--r-- | Source/cmTargetPropCommandBase.h | 57 | ||||
-rw-r--r-- | Tests/CMakeCommands/target_include_directories/CMakeLists.txt | 50 | ||||
-rw-r--r-- | Tests/CMakeCommands/target_include_directories/consumer.cpp | 27 | ||||
-rw-r--r-- | Tests/CMakeCommands/target_include_directories/main.cpp | 22 | ||||
-rw-r--r-- | Tests/CMakeLists.txt | 1 |
9 files changed, 473 insertions, 0 deletions
diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index 49ed967..6b315ea 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -28,6 +28,8 @@ #include "cmRemoveDefinitionsCommand.cxx" #include "cmSourceGroupCommand.cxx" #include "cmSubdirDependsCommand.cxx" +#include "cmTargetIncludeDirectoriesCommand.cxx" +#include "cmTargetPropCommandBase.cxx" #include "cmUseMangledMesaCommand.cxx" #include "cmUtilitySourceCommand.cxx" #include "cmVariableRequiresCommand.cxx" @@ -66,6 +68,7 @@ void GetPredefinedCommands(std::list<cmCommand*>& commands.push_back(new cmRemoveDefinitionsCommand); commands.push_back(new cmSourceGroupCommand); commands.push_back(new cmSubdirDependsCommand); + commands.push_back(new cmTargetIncludeDirectoriesCommand); commands.push_back(new cmUseMangledMesaCommand); commands.push_back(new cmUtilitySourceCommand); commands.push_back(new cmVariableRequiresCommand); diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx new file mode 100644 index 0000000..18e2cba --- /dev/null +++ b/Source/cmTargetIncludeDirectoriesCommand.cxx @@ -0,0 +1,74 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 Stephen Kelly <steveire@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmTargetIncludeDirectoriesCommand.h" + +#include "cmMakefileIncludeDirectoriesEntry.h" + +//---------------------------------------------------------------------------- +bool cmTargetIncludeDirectoriesCommand +::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) +{ + return this->HandleArguments(args, "INCLUDE_DIRECTORIES", PROCESS_BEFORE); +} + +//---------------------------------------------------------------------------- +void cmTargetIncludeDirectoriesCommand +::HandleImportedTargetInvalidScope(const std::string &tgt, + const std::string &scope) +{ + cmOStringStream e; + e << "Cannot specify " << scope << " include directories for imported " + "target \"" << tgt << "\". Include directories can only be " + "specified for an imported target in the INTERFACE mode."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); +} + +//---------------------------------------------------------------------------- +void cmTargetIncludeDirectoriesCommand +::HandleMissingTarget(const std::string &name) +{ + cmOStringStream e; + e << "Cannot specify include directories for target \"" << name << "\" " + "which is not built by this project."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); +} + +//---------------------------------------------------------------------------- +bool cmTargetIncludeDirectoriesCommand +::HandleNonTargetArg(std::string &content, + const std::string &sep, + const std::string &entry, + const std::string &tgt) +{ + if (!cmSystemTools::FileIsFullPath(entry.c_str())) + { + cmOStringStream e; + e << "Cannot specify relative include directory \"" << entry << "\" for " + "target \"" << tgt << "\". Only absolute paths are permitted"; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; + } + + content += sep + entry; + return true; +} + +//---------------------------------------------------------------------------- +void cmTargetIncludeDirectoriesCommand +::HandleDirectContent(cmTarget *tgt, const std::string &content, + bool prepend) +{ + cmListFileBacktrace lfbt; + this->Makefile->GetBacktrace(lfbt); + cmMakefileIncludeDirectoriesEntry entry(content, lfbt); + tgt->InsertInclude(entry, prepend); +} diff --git a/Source/cmTargetIncludeDirectoriesCommand.h b/Source/cmTargetIncludeDirectoriesCommand.h new file mode 100644 index 0000000..c1957d6 --- /dev/null +++ b/Source/cmTargetIncludeDirectoriesCommand.h @@ -0,0 +1,95 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 Stephen Kelly <steveire@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmTargetIncludeDirectoriesCommand_h +#define cmTargetIncludeDirectoriesCommand_h + +#include "cmTargetPropCommandBase.h" + +//---------------------------------------------------------------------------- +class cmTargetIncludeDirectoriesCommand : public cmTargetPropCommandBase +{ +public: + /** + * This is a virtual constructor for the command. + */ + virtual cmCommand* Clone() + { + return new cmTargetIncludeDirectoriesCommand; + } + + /** + * This is called when the command is first encountered in + * the CMakeLists.txt file. + */ + virtual bool InitialPass(std::vector<std::string> const& args, + cmExecutionStatus &status); + + /** + * The name of the command as specified in CMakeList.txt. + */ + virtual const char* GetName() const { return "target_include_directories";} + + /** + * Succinct documentation. + */ + virtual const char* GetTerseDocumentation() const + { + return + "Add include directories to a target."; + } + + /** + * More documentation. + */ + virtual const char* GetFullDocumentation() const + { + return + " target_include_directories(<target> [BEFORE] " + "<INTERFACE|PUBLIC|PRIVATE> [items1...]\n" + " [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])\n" + "Specify include directories or targets to use when compiling a given " + "target. " + "The named <target> must have been created by a command such as " + "add_executable or add_library.\n" + "If BEFORE is specified, the content will be prepended to the property " + "instead of being appended.\n" + "The INTERFACE, PUBLIC and PRIVATE keywords are required to specify " + "the scope of the following arguments. PRIVATE and PUBLIC items will " + "populate the INCLUDE_DIRECTORIES property of <target>. PUBLIC and " + "INTERFACE items will populate the INTERFACE_INCLUDE_DIRECTORIES " + "property of <target>. " + "The non-scope arguments specify either include directories or targets " + "to use INTERFACE_INCLUDE_DIRECTORIES from. Any specified include " + "directories must be absolute paths, not relative paths. " + "Repeated calls for the same <target> append items in the order called." + "\n" + ; + } + + cmTypeMacro(cmTargetIncludeDirectoriesCommand, cmCommand); + +private: + virtual void HandleImportedTargetInvalidScope(const std::string &tgt, + const std::string &scope); + virtual void HandleMissingTarget(const std::string &name); + + virtual bool HandleNonTargetArg(std::string &content, + const std::string &sep, + const std::string &entry, + const std::string &tgt); + + virtual void HandleDirectContent(cmTarget *tgt, const std::string &content, + bool prepend); +}; + +#endif diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx new file mode 100644 index 0000000..69aaf17 --- /dev/null +++ b/Source/cmTargetPropCommandBase.cxx @@ -0,0 +1,144 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 Stephen Kelly <steveire@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmTargetPropCommandBase.h" + +#include "cmGlobalGenerator.h" + +//---------------------------------------------------------------------------- +bool cmTargetPropCommandBase +::HandleArguments(std::vector<std::string> const& args, const char *prop, + ArgumentFlags flags) +{ + if(args.size() < 3) + { + this->SetError("called with incorrect number of arguments"); + return false; + } + + // Lookup the target for which libraries are specified. + this->Target = + this->Makefile->GetCMakeInstance() + ->GetGlobalGenerator()->FindTarget(0, args[0].c_str()); + if(!this->Target) + { + this->Target = this->Makefile->FindTargetToUse(args[0].c_str()); + } + if(!this->Target) + { + this->HandleMissingTarget(args[0]); + return false; + } + + unsigned int argIndex = 1; + + bool prepend = false; + if ((flags & PROCESS_BEFORE) && args[argIndex] == "BEFORE") + { + if (args.size() < 4) + { + this->SetError("called with incorrect number of arguments"); + return false; + } + prepend = true; + ++argIndex; + } + + this->Property = prop; + + while (argIndex < args.size()) + { + if (!this->ProcessContentArgs(args, argIndex, prepend)) + { + return false; + } + } + return true; +} + +//---------------------------------------------------------------------------- +bool cmTargetPropCommandBase +::ProcessContentArgs(std::vector<std::string> const& args, + unsigned int &argIndex, bool prepend) +{ + const std::string scope = args[argIndex]; + + if(scope != "PUBLIC" + && scope != "PRIVATE" + && scope != "INTERFACE" ) + { + this->SetError("called with invalid arguments"); + return false; + } + + if(this->Target->IsImported() && scope != "INTERFACE") + { + this->HandleImportedTargetInvalidScope(args[0], scope); + return false; + } + + ++argIndex; + + std::string content; + + std::string sep; + for(unsigned int i=argIndex; i < args.size(); ++i, ++argIndex) + { + if(args[i] == "PUBLIC" + || args[i] == "PRIVATE" + || args[i] == "INTERFACE" ) + { + this->PopulateTargetProperies(scope, content, prepend); + return true; + } + if (this->Makefile->FindTargetToUse(args[i].c_str())) + { + content += sep + "$<TARGET_PROPERTY:" + args[i] + + ",INTERFACE_" + this->Property + ">"; + } + else if (!this->HandleNonTargetArg(content, sep, args[i], args[0])) + { + return false; + } + sep = ";"; + } + this->PopulateTargetProperies(scope, content, prepend); + return true; +} + +//---------------------------------------------------------------------------- +void cmTargetPropCommandBase +::PopulateTargetProperies(const std::string &scope, + const std::string &content, bool prepend) +{ + if (scope == "PRIVATE" || scope == "PUBLIC") + { + this->HandleDirectContent(this->Target, content, prepend); + } + if (scope == "INTERFACE" || scope == "PUBLIC") + { + if (prepend) + { + const std::string propName = std::string("INTERFACE_") + this->Property; + const char *propValue = this->Target->GetProperty(propName.c_str()); + const std::string totalContent = content + (propValue + ? std::string(";") + propValue + : std::string()); + this->Target->SetProperty(propName.c_str(), totalContent.c_str()); + } + else + { + this->Target->AppendProperty(("INTERFACE_" + this->Property).c_str(), + content.c_str()); + } + } +} diff --git a/Source/cmTargetPropCommandBase.h b/Source/cmTargetPropCommandBase.h new file mode 100644 index 0000000..90e3bbb --- /dev/null +++ b/Source/cmTargetPropCommandBase.h @@ -0,0 +1,57 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2013 Stephen Kelly <steveire@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmTargetPropCommandBase_h +#define cmTargetPropCommandBase_h + +#include "cmCommand.h" + +class cmTarget; + +//---------------------------------------------------------------------------- +class cmTargetPropCommandBase : public cmCommand +{ +public: + + enum ArgumentFlags { + NO_FLAGS = 0, + PROCESS_BEFORE = 1 + }; + + bool HandleArguments(std::vector<std::string> const& args, + const char *prop, ArgumentFlags flags = NO_FLAGS); + +private: + virtual void HandleImportedTargetInvalidScope(const std::string &tgt, + const std::string &scope) = 0; + virtual void HandleMissingTarget(const std::string &name) = 0; + + virtual bool HandleNonTargetArg(std::string &content, + const std::string &sep, + const std::string &entry, + const std::string &tgt) = 0; + + virtual void HandleDirectContent(cmTarget *tgt, + const std::string &content, + bool prepend) = 0; + + bool ProcessContentArgs(std::vector<std::string> const& args, + unsigned int &argIndex, bool prepend); + void PopulateTargetProperies(const std::string &scope, + const std::string &content, bool prepend); + +private: + cmTarget *Target; + std::string Property; +}; + +#endif diff --git a/Tests/CMakeCommands/target_include_directories/CMakeLists.txt b/Tests/CMakeCommands/target_include_directories/CMakeLists.txt new file mode 100644 index 0000000..a0f2ee0 --- /dev/null +++ b/Tests/CMakeCommands/target_include_directories/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 2.8) + +project(target_include_directories) + +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/privateinclude") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/privateinclude/privateinclude.h" "#define PRIVATEINCLUDE_DEFINE\n") + +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/publicinclude") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/publicinclude/publicinclude.h" "#define PUBLICINCLUDE_DEFINE\n") + +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/interfaceinclude") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/interfaceinclude/interfaceinclude.h" "#define INTERFACEINCLUDE_DEFINE\n") + +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/importedinterfaceinclude") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/importedinterfaceinclude/importedinterfaceinclude.h" "#define IMPORTEDINTERFACEINCLUDE_DEFINE\n") + +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/poison") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/poison/common.h" "#error Should not be included\n") + +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/cure") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cure/common.h" "#define CURE_DEFINE\n") + +add_executable(target_include_directories + "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" +) +target_include_directories(target_include_directories + PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/privateinclude" + PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/publicinclude" + INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/interfaceinclude" +) + +target_include_directories(target_include_directories + PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/poison" +) +target_include_directories(target_include_directories + BEFORE PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/cure" +) + +add_library(importedlib UNKNOWN IMPORTED) +target_include_directories(importedlib + INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/importedinterfaceinclude" +) + +add_executable(consumer + "${CMAKE_CURRENT_SOURCE_DIR}/consumer.cpp" +) + +target_include_directories(consumer + PRIVATE target_include_directories importedlib +) diff --git a/Tests/CMakeCommands/target_include_directories/consumer.cpp b/Tests/CMakeCommands/target_include_directories/consumer.cpp new file mode 100644 index 0000000..6fd61d5 --- /dev/null +++ b/Tests/CMakeCommands/target_include_directories/consumer.cpp @@ -0,0 +1,27 @@ + +#include "common.h" +#include "publicinclude.h" +#include "interfaceinclude.h" +#include "importedinterfaceinclude.h" + +#ifdef PRIVATEINCLUDE_DEFINE +#error Unexpected PRIVATEINCLUDE_DEFINE +#endif + +#ifndef PUBLICINCLUDE_DEFINE +#error Expected PUBLICINCLUDE_DEFINE +#endif + +#ifndef INTERFACEINCLUDE_DEFINE +#error Expected INTERFACEINCLUDE_DEFINE +#endif + +#ifndef IMPORTEDINTERFACEINCLUDE_DEFINE +#error Expected IMPORTEDINTERFACEINCLUDE_DEFINE +#endif + +#ifndef CURE_DEFINE +#error Expected CURE_DEFINE +#endif + +int main() { return 0; } diff --git a/Tests/CMakeCommands/target_include_directories/main.cpp b/Tests/CMakeCommands/target_include_directories/main.cpp new file mode 100644 index 0000000..8434b97 --- /dev/null +++ b/Tests/CMakeCommands/target_include_directories/main.cpp @@ -0,0 +1,22 @@ + +#include "common.h" +#include "privateinclude.h" +#include "publicinclude.h" + +#ifndef PRIVATEINCLUDE_DEFINE +#error Expected PRIVATEINCLUDE_DEFINE +#endif + +#ifndef PUBLICINCLUDE_DEFINE +#error Expected PUBLICINCLUDE_DEFINE +#endif + +#ifdef INTERFACEINCLUDE_DEFINE +#error Unexpected INTERFACEINCLUDE_DEFINE +#endif + +#ifndef CURE_DEFINE +#error Expected CURE_DEFINE +#endif + +int main() { return 0; } diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index ade6a01..2dced5f 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1930,6 +1930,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ ) ADD_TEST_MACRO(CMakeCommands.target_link_libraries target_link_libraries) + ADD_TEST_MACRO(CMakeCommands.target_include_directories target_include_directories) configure_file( "${CMake_SOURCE_DIR}/Tests/CTestTestCrash/test.cmake.in" |