Quellcode durchsuchen

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 vor 8 Jahren
Ursprung
Commit
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
 ``$<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
 ==========================================
 

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

@@ -290,9 +290,7 @@ Available output expressions are:
   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``.  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:...>``
   Content of ``...`` converted to shell path style. For example, slashes are
   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;
     }
     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;
     lg->IssueMessage(cmake::FATAL_ERROR, e.str());
     return;

+ 25 - 7
Source/cmGeneratorExpressionNode.cxx

@@ -1243,20 +1243,38 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
       return std::string();
     }
     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;
     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();
          oi != objects.end(); ++oi) {
-      *oi = gt->ObjectDirectory + *oi;
+      *oi = obj_dir + *oi;
     }
 
     // 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)
 set(CMP0044_TYPE 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:
-  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

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

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