Explorar el Código

Genex: Evaluate TARGET_OBJECTS as a normal expression.

Stephen Kelly hace 11 años
padre
commit
bf98cc252f

+ 3 - 0
Help/manual/cmake-generator-expressions.7.rst

@@ -188,3 +188,6 @@ property is non-empty::
   Content of ``...`` converted to upper case.
 ``$<MAKE_C_IDENTIFIER:...>``
   Content of ``...`` converted to a C identifier.
+``$<TARGET_OBJECTS:objLib>``
+  List of objects resulting from build of ``objLib``. ``objLib`` must be an
+  object of type ``OBJECT_LIBRARY``.

+ 6 - 0
Help/release/dev/file-GENERATE-TARGET_OBJECTS.rst

@@ -0,0 +1,6 @@
+file-GENERATE-TARGET_OBJECTS
+----------------------------
+
+* The :command:`file(GENERATE)` subcommand learned to evaluate the
+  ``TARGET_OBJECTS``
+  :manual:`generator expression <cmake-generator-expressions(7)>`.

+ 64 - 0
Source/cmGeneratorExpressionEvaluator.cxx

@@ -15,6 +15,8 @@
 #include "cmGeneratorExpressionParser.h"
 #include "cmGeneratorExpressionDAGChecker.h"
 #include "cmGeneratorExpression.h"
+#include "cmLocalGenerator.h"
+#include "cmSourceFile.h"
 
 #include <cmsys/String.h>
 
@@ -1239,6 +1241,67 @@ static const struct TargetNameNode : public cmGeneratorExpressionNode
 
 } targetNameNode;
 
+//----------------------------------------------------------------------------
+static const struct TargetObjectsNode : public cmGeneratorExpressionNode
+{
+  TargetObjectsNode() {}
+
+  std::string Evaluate(const std::vector<std::string> &parameters,
+                       cmGeneratorExpressionContext *context,
+                       const GeneratorExpressionContent *content,
+                       cmGeneratorExpressionDAGChecker *) const
+  {
+    std::string tgtName = parameters.front();
+    cmGeneratorTarget* gt =
+                context->Makefile->FindGeneratorTargetToUse(tgtName.c_str());
+    if (!gt)
+      {
+      cmOStringStream e;
+      e << "Objects of target \"" << tgtName
+        << "\" referenced but no such target exists.";
+      reportError(context, content->GetOriginalExpression(), e.str());
+      return std::string();
+      }
+    if (gt->GetType() != cmTarget::OBJECT_LIBRARY)
+      {
+      cmOStringStream e;
+      e << "Objects of target \"" << tgtName
+        << "\" referenced but is not an OBJECT library.";
+      reportError(context, content->GetOriginalExpression(), e.str());
+      return std::string();
+      }
+
+    std::vector<cmSourceFile const*> objectSources;
+    gt->GetObjectSources(objectSources);
+    std::map<cmSourceFile const*, std::string> mapping;
+
+    for(std::vector<cmSourceFile const*>::const_iterator it
+        = objectSources.begin(); it != objectSources.end(); ++it)
+      {
+      mapping[*it];
+      }
+
+    gt->LocalGenerator->ComputeObjectFilenames(mapping, gt);
+
+    std::string obj_dir = gt->ObjectDirectory;
+    std::string result;
+    const char* sep = "";
+    for(std::map<cmSourceFile const*, std::string>::const_iterator it
+        = mapping.begin(); it != mapping.end(); ++it)
+      {
+      assert(!it->second.empty());
+      result += sep;
+      std::string objFile = obj_dir + it->second;
+      cmSourceFile* sf = context->Makefile->GetOrCreateSource(objFile, true);
+      sf->SetObjectLibrary(tgtName);
+      sf->SetProperty("EXTERNAL_OBJECT", "1");
+      result += objFile;
+      sep = ";";
+      }
+    return result;
+  }
+} targetObjectsNode;
+
 //----------------------------------------------------------------------------
 static const char* targetPolicyWhitelist[] = {
   0
@@ -1593,6 +1656,7 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
     nodeMap["SEMICOLON"] = &semicolonNode;
     nodeMap["TARGET_PROPERTY"] = &targetPropertyNode;
     nodeMap["TARGET_NAME"] = &targetNameNode;
+    nodeMap["TARGET_OBJECTS"] = &targetObjectsNode;
     nodeMap["TARGET_POLICY"] = &targetPolicyNode;
     nodeMap["BUILD_INTERFACE"] = &buildInterfaceNode;
     nodeMap["INSTALL_INTERFACE"] = &installInterfaceNode;

+ 12 - 0
Source/cmSourceFile.cxx

@@ -38,6 +38,18 @@ std::string const& cmSourceFile::GetExtension() const
   return this->Extension;
 }
 
+//----------------------------------------------------------------------------
+void cmSourceFile::SetObjectLibrary(std::string const& objlib)
+{
+  this->ObjectLibrary = objlib;
+}
+
+//----------------------------------------------------------------------------
+std::string cmSourceFile::GetObjectLibrary() const
+{
+  return this->ObjectLibrary;
+}
+
 //----------------------------------------------------------------------------
 std::string cmSourceFile::GetLanguage()
 {

+ 4 - 0
Source/cmSourceFile.h

@@ -97,6 +97,9 @@ public:
    */
   bool Matches(cmSourceFileLocation const&);
 
+  void SetObjectLibrary(std::string const& objlib);
+  std::string GetObjectLibrary() const;
+
 private:
   cmSourceFileLocation Location;
   cmPropertyMap Properties;
@@ -105,6 +108,7 @@ private:
   std::string Language;
   std::string FullPath;
   bool FindFullPathFailed;
+  std::string ObjectLibrary;
 
   bool FindFullPath(std::string* error);
   bool TryFullPath(const std::string& path, const std::string& ext);

+ 14 - 0
Tests/GeneratorExpression/CMakeLists.txt

@@ -258,3 +258,17 @@ set(CMP0044_TYPE NEW)
 add_subdirectory(CMP0044 ${CMAKE_BINARY_DIR}/CMP0044-NEW)
 set(CMP0044_TYPE OLD)
 add_subdirectory(CMP0044 ${CMAKE_BINARY_DIR}/CMP0044-OLD)
+
+add_library(objlib OBJECT objlib1.c objlib2.c)
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/objlib_files"
+  CONTENT "$<JOIN:$<TARGET_OBJECTS:objlib>,\n>\n"
+)
+add_custom_target(check_object_files ALL
+  COMMAND ${CMAKE_COMMAND}
+    "-DOBJLIB_LISTFILE=${CMAKE_CURRENT_BINARY_DIR}/objlib_files"
+    -DTEST_CONFIGURATION=${CMAKE_BUILD_TYPE}
+    -DEXPECTED_NUM_OBJECTFILES=2
+    -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake"
+  DEPENDS objlib
+)

+ 48 - 0
Tests/GeneratorExpression/check_object_files.cmake

@@ -0,0 +1,48 @@
+
+if (NOT EXISTS ${OBJLIB_LISTFILE})
+  message(SEND_ERROR "Object listing file \"${OBJLIB_LISTFILE}\" not found!")
+endif()
+
+file(STRINGS ${OBJLIB_LISTFILE} objlib_files)
+
+list(LENGTH objlib_files num_objectfiles)
+if (NOT EXPECTED_NUM_OBJECTFILES EQUAL num_objectfiles)
+  message(SEND_ERROR "Unexpected number of entries in object list file (${num_objectfiles} instead of ${EXPECTED_NUM_OBJECTFILES})")
+endif()
+
+foreach(objlib_file ${objlib_files})
+  set(file_exists False)
+  if (EXISTS ${objlib_file})
+    set(file_exists True)
+  endif()
+
+  if (NOT file_exists)
+    if (objlib_file MATCHES ".(CURRENT_ARCH)")
+      string(REPLACE "$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)" "*" config_file "${objlib_file}")
+      string(REPLACE "$(PROJECT_NAME)" "GeneratorExpression" config_file "${config_file}")
+      string(REPLACE "$(CURRENT_ARCH)" "*" config_file "${config_file}")
+      file(GLOB_RECURSE files "${config_file}")
+      list(LENGTH files num_files)
+      if (NOT files)
+        message(SEND_ERROR "Got no files for expression ${config_file}")
+      endif()
+      set(file_exists True)
+    else()
+      foreach(config_macro "$(Configuration)" "$(OutDir)" "$(IntDir)")
+        string(REPLACE "${config_macro}" "${TEST_CONFIGURATION}" config_file "${objlib_file}")
+        list(APPEND attempts ${config_file})
+        if (EXISTS ${config_file})
+          set(file_exists True)
+        endif()
+      endforeach()
+    endif()
+  endif()
+
+  if (NOT file_exists)
+    if(attempts)
+      list(REMOVE_DUPLICATES attempts)
+      set(tried "  Tried ${attempts}")
+    endif()
+    message(SEND_ERROR "File \"${objlib_file}\" does not exist!${tried}")
+  endif()
+endforeach()

+ 5 - 0
Tests/GeneratorExpression/objlib1.c

@@ -0,0 +1,5 @@
+
+void objlib1()
+{
+
+}

+ 5 - 0
Tests/GeneratorExpression/objlib2.c

@@ -0,0 +1,5 @@
+
+void objlib2()
+{
+
+}

+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -49,6 +49,7 @@ add_RunCMake_test(GeneratorToolset)
 add_RunCMake_test(TargetPropertyGeneratorExpressions)
 add_RunCMake_test(Languages)
 add_RunCMake_test(ObjectLibrary)
+add_RunCMake_test(TargetObjects)
 add_RunCMake_test(find_dependency)
 if(NOT WIN32)
   add_RunCMake_test(PositionIndependentCode)

+ 3 - 0
Tests/RunCMake/TargetObjects/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.4)
+project(${RunCMake_TEST})
+include(${RunCMake_TEST}.cmake)

+ 1 - 0
Tests/RunCMake/TargetObjects/NoTarget-result.txt

@@ -0,0 +1 @@
+1

+ 8 - 0
Tests/RunCMake/TargetObjects/NoTarget-stderr.txt

@@ -0,0 +1,8 @@
+CMake Error at NoTarget.cmake:2 \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_OBJECTS:NoTarget>
+
+  Objects of target "NoTarget" referenced but no such target exists.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 2 - 0
Tests/RunCMake/TargetObjects/NoTarget.cmake

@@ -0,0 +1,2 @@
+
+file(GENERATE OUTPUT test_output CONTENT $<TARGET_OBJECTS:NoTarget>)

+ 1 - 0
Tests/RunCMake/TargetObjects/NotObjlibTarget-result.txt

@@ -0,0 +1 @@
+1

+ 8 - 0
Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt

@@ -0,0 +1,8 @@
+CMake Error at NotObjlibTarget.cmake:4 \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_OBJECTS:StaticLib>
+
+  Objects of target "StaticLib" referenced but is not an OBJECT library.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:3 \(include\)

+ 4 - 0
Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake

@@ -0,0 +1,4 @@
+
+add_library(StaticLib empty.cpp)
+
+file(GENERATE OUTPUT test_output CONTENT $<TARGET_OBJECTS:StaticLib>)

+ 4 - 0
Tests/RunCMake/TargetObjects/RunCMakeTest.cmake

@@ -0,0 +1,4 @@
+include(RunCMake)
+
+run_cmake(NoTarget)
+run_cmake(NotObjlibTarget)

+ 7 - 0
Tests/RunCMake/TargetObjects/empty.cpp

@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int empty()
+{
+  return 0;
+}