Browse Source

Add the target_include_directories command.

This is a convenience API to populate the corresponding properties.
Stephen Kelly 13 years ago
parent
commit
8a37ebec78

+ 3 - 0
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);

+ 74 - 0
Source/cmTargetIncludeDirectoriesCommand.cxx

@@ -0,0 +1,74 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2013 Stephen Kelly <[email protected]>
+
+  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);
+}

+ 95 - 0
Source/cmTargetIncludeDirectoriesCommand.h

@@ -0,0 +1,95 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2013 Stephen Kelly <[email protected]>
+
+  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

+ 144 - 0
Source/cmTargetPropCommandBase.cxx

@@ -0,0 +1,144 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2013 Stephen Kelly <[email protected]>
+
+  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());
+      }
+    }
+}

+ 57 - 0
Source/cmTargetPropCommandBase.h

@@ -0,0 +1,57 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2013 Stephen Kelly <[email protected]>
+
+  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

+ 50 - 0
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
+)

+ 27 - 0
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; }

+ 22 - 0
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; }

+ 1 - 0
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"