瀏覽代碼

Genex: Allow TARGET_OBJECTS to be used everywhere

Previously the `TARGET_OBJECTS` generator expression was limited
only to use in a buildsystem context so that Xcode's placeholders
in object file paths can be evaluated.  Lift this restriction so
that the expression can at least be used in most settings.

Co-Author: Brad King <[email protected]>
Robert Maynard 8 年之前
父節點
當前提交
93c89bc75c

+ 6 - 0
Help/manual/cmake-buildsystem.7.rst

@@ -136,6 +136,12 @@ indirectly by using an :ref:`Interface Library <Interface Libraries>`
 whose :prop_tgt:`INTERFACE_SOURCES` target property is set to name
 whose :prop_tgt:`INTERFACE_SOURCES` target property is set to name
 ``$<TARGET_OBJECTS:objlib>``.
 ``$<TARGET_OBJECTS:objlib>``.
 
 
+Although object libraries may not be used as the ``TARGET``
+in a use of the :command:`add_custom_command(TARGET)` command signature,
+the list of objects can be used by :command:`add_custom_command(OUTPUT)` or
+:command:`file(GENERATE)` by using ``$<TARGET_OBJECTS:objlib>``.
+
+
 Build Specification and Usage Requirements
 Build Specification and Usage Requirements
 ==========================================
 ==========================================
 
 

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

@@ -290,9 +290,7 @@ Available output expressions are:
   Content of ``...`` converted to a C identifier.
   Content of ``...`` converted to a C identifier.
 ``$<TARGET_OBJECTS:objLib>``
 ``$<TARGET_OBJECTS:objLib>``
   List of objects resulting from build of ``objLib``. ``objLib`` must be an
   List of objects resulting from build of ``objLib``. ``objLib`` must be an
-  object of type ``OBJECT_LIBRARY``.  This expression may only be used in
-  the sources of :command:`add_library` and :command:`add_executable`
-  commands.
+  object of type ``OBJECT_LIBRARY``.
 ``$<SHELL_PATH:...>``
 ``$<SHELL_PATH:...>``
   Content of ``...`` converted to shell path style. For example, slashes are
   Content of ``...`` converted to shell path style. For example, slashes are
   converted to backslashes in Windows shells and drive letters are converted
   converted to backslashes in Windows shells and drive letters are converted

+ 6 - 0
Help/release/dev/add_custom_command-TARGET_OBJECTS.rst

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

+ 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)>`.

+ 4 - 2
Source/cmGeneratorExpressionEvaluationFile.cxx

@@ -64,8 +64,10 @@ void cmGeneratorExpressionEvaluationFile::Generate(
       return;
       return;
     }
     }
     std::ostringstream e;
     std::ostringstream e;
-    e << "Evaluation file to be written multiple times for different "
-         "configurations or languages with different content:\n  "
+    e << "Evaluation file to be written multiple times with different "
+         "content. "
+         "This is generally caused by the content evaluating the "
+         "configuration type, language, or location of object files:\n "
       << outputFileName;
       << outputFileName;
     lg->IssueMessage(cmake::FATAL_ERROR, e.str());
     lg->IssueMessage(cmake::FATAL_ERROR, e.str());
     return;
     return;

+ 25 - 7
Source/cmGeneratorExpressionNode.cxx

@@ -1243,20 +1243,38 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
       return std::string();
       return std::string();
     }
     }
     if (!context->EvaluateForBuildsystem) {
     if (!context->EvaluateForBuildsystem) {
-      std::ostringstream e;
-      e << "The evaluation of the TARGET_OBJECTS generator expression "
-           "is only suitable for consumption by CMake.  It is not suitable "
-           "for writing out elsewhere.";
-      reportError(context, content->GetOriginalExpression(), e.str());
-      return std::string();
+      cmGlobalGenerator* gg = context->LG->GetGlobalGenerator();
+      std::string reason;
+      if (!gg->HasKnownObjectFileLocation(&reason)) {
+        std::ostringstream e;
+        e << "The evaluation of the TARGET_OBJECTS generator expression "
+             "is only suitable for consumption by CMake (limited"
+          << reason << ").  "
+                       "It is not suitable for writing out elsewhere.";
+        reportError(context, content->GetOriginalExpression(), e.str());
+        return std::string();
+      }
     }
     }
 
 
     std::vector<std::string> objects;
     std::vector<std::string> objects;
     gt->GetTargetObjectNames(context->Config, objects);
     gt->GetTargetObjectNames(context->Config, objects);
 
 
+    std::string obj_dir;
+    if (context->EvaluateForBuildsystem) {
+      // Use object file directory with buildsystem placeholder.
+      obj_dir = gt->ObjectDirectory;
+      // Here we assume that the set of object files produced
+      // by an object library does not vary with configuration
+      // and do not set HadContextSensitiveCondition to true.
+    } else {
+      // Use object file directory with per-config location.
+      obj_dir = gt->GetObjectDirectory(context->Config);
+      context->HadContextSensitiveCondition = true;
+    }
+
     for (std::vector<std::string>::iterator oi = objects.begin();
     for (std::vector<std::string>::iterator oi = objects.begin();
          oi != objects.end(); ++oi) {
          oi != objects.end(); ++oi) {
-      *oi = gt->ObjectDirectory + *oi;
+      *oi = obj_dir + *oi;
     }
     }
 
 
     // Create the cmSourceFile instances in the referencing directory.
     // Create the cmSourceFile instances in the referencing directory.

+ 16 - 0
Tests/GeneratorExpression/CMakeLists.txt

@@ -292,3 +292,19 @@ set(CMP0044_TYPE NEW)
 add_subdirectory(CMP0044 ${CMAKE_BINARY_DIR}/CMP0044-NEW)
 add_subdirectory(CMP0044 ${CMAKE_BINARY_DIR}/CMP0044-NEW)
 set(CMP0044_TYPE OLD)
 set(CMP0044_TYPE OLD)
 add_subdirectory(CMP0044 ${CMAKE_BINARY_DIR}/CMP0044-OLD)
 add_subdirectory(CMP0044 ${CMAKE_BINARY_DIR}/CMP0044-OLD)
+
+if(NOT CMAKE_GENERATOR STREQUAL Xcode OR NOT CMAKE_OSX_ARCHITECTURES MATCHES "[;$]")
+  add_library(objlib OBJECT objlib1.c objlib2.c)
+  file(GENERATE
+    OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/objlib_files_$<CONFIGURATION>"
+    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_$<CONFIGURATION>"
+      -DEXPECTED_NUM_OBJECTFILES=2
+      -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake"
+    DEPENDS objlib
+  )
+endif()

+ 26 - 0
Tests/GeneratorExpression/check_object_files.cmake

@@ -0,0 +1,26 @@
+
+if (NOT EXISTS ${OBJLIB_LISTFILE})
+  message(SEND_ERROR "Object listing file \"${OBJLIB_LISTFILE}\" not found!")
+endif()
+
+file(STRINGS ${OBJLIB_LISTFILE} objlib_files ENCODING UTF-8)
+
+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(attempts)
+      list(REMOVE_DUPLICATES attempts)
+      set(tried "  Tried ${attempts}")
+    endif()
+    message(SEND_ERROR "File \"${objlib_file}\" does not exist!${tried}")
+  endif()
+endforeach()

+ 4 - 0
Tests/GeneratorExpression/objlib1.c

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

+ 4 - 0
Tests/GeneratorExpression/objlib2.c

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

+ 3 - 2
Tests/RunCMake/File_Generate/OutputConflict-stderr.txt

@@ -1,5 +1,6 @@
 CMake Error in CMakeLists.txt:
 CMake Error in CMakeLists.txt:
-  Evaluation file to be written multiple times for different configurations
-  or languages with different content:
+  Evaluation file to be written multiple times with different content.  This
+  is generally caused by the content evaluating the configuration type,
+  language, or location of object files:
 
 
   .*output.txt
   .*output.txt

+ 1 - 0
Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake

@@ -1,3 +1,4 @@
+enable_language(CXX)
 
 
 file(GENERATE
 file(GENERATE
   OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<BOOL:$<TARGET_OBJECTS:foo>>somefile.cpp"
   OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<BOOL:$<TARGET_OBJECTS:foo>>somefile.cpp"