From 93c89bc75ceee599ba7c08b8fe1ac5104942054f Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Mon, 23 Jan 2017 14:13:49 -0500 Subject: 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 --- Help/manual/cmake-buildsystem.7.rst | 6 ++++ Help/manual/cmake-generator-expressions.7.rst | 4 +-- .../dev/add_custom_command-TARGET_OBJECTS.rst | 6 ++++ Help/release/dev/file-GENERATE-TARGET_OBJECTS.rst | 6 ++++ Source/cmGeneratorExpressionEvaluationFile.cxx | 6 ++-- Source/cmGeneratorExpressionNode.cxx | 32 +++++++++++++++++----- Tests/GeneratorExpression/CMakeLists.txt | 16 +++++++++++ Tests/GeneratorExpression/check_object_files.cmake | 26 ++++++++++++++++++ Tests/GeneratorExpression/objlib1.c | 4 +++ Tests/GeneratorExpression/objlib2.c | 4 +++ .../File_Generate/OutputConflict-stderr.txt | 5 ++-- .../File_Generate/OutputNameMatchesObjects.cmake | 1 + 12 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 Help/release/dev/add_custom_command-TARGET_OBJECTS.rst create mode 100644 Help/release/dev/file-GENERATE-TARGET_OBJECTS.rst create mode 100644 Tests/GeneratorExpression/check_object_files.cmake create mode 100644 Tests/GeneratorExpression/objlib1.c create mode 100644 Tests/GeneratorExpression/objlib2.c diff --git a/Help/manual/cmake-buildsystem.7.rst b/Help/manual/cmake-buildsystem.7.rst index 2e6a803..65d87bf 100644 --- a/Help/manual/cmake-buildsystem.7.rst +++ b/Help/manual/cmake-buildsystem.7.rst @@ -136,6 +136,12 @@ indirectly by using an :ref:`Interface Library ` whose :prop_tgt:`INTERFACE_SOURCES` target property is set to name ``$``. +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 ``$``. + + Build Specification and Usage Requirements ========================================== diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index 3eac45f..bddb174 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -290,9 +290,7 @@ Available output expressions are: Content of ``...`` converted to a C identifier. ``$`` 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``. ``$`` Content of ``...`` converted to shell path style. For example, slashes are converted to backslashes in Windows shells and drive letters are converted diff --git a/Help/release/dev/add_custom_command-TARGET_OBJECTS.rst b/Help/release/dev/add_custom_command-TARGET_OBJECTS.rst new file mode 100644 index 0000000..c4a9ee8 --- /dev/null +++ b/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 `. diff --git a/Help/release/dev/file-GENERATE-TARGET_OBJECTS.rst b/Help/release/dev/file-GENERATE-TARGET_OBJECTS.rst new file mode 100644 index 0000000..853a803 --- /dev/null +++ b/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 `. diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx index dc54488..1526454 100644 --- a/Source/cmGeneratorExpressionEvaluationFile.cxx +++ b/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; diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 65949a3..1215737 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/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 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::iterator oi = objects.begin(); oi != objects.end(); ++oi) { - *oi = gt->ObjectDirectory + *oi; + *oi = obj_dir + *oi; } // Create the cmSourceFile instances in the referencing directory. diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt index adc87cd..8ac3419 100644 --- a/Tests/GeneratorExpression/CMakeLists.txt +++ b/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_$" + CONTENT "$,\n>\n" + ) + + add_custom_target(check_object_files ALL + COMMAND ${CMAKE_COMMAND} + "-DOBJLIB_LISTFILE=${CMAKE_CURRENT_BINARY_DIR}/objlib_files_$" + -DEXPECTED_NUM_OBJECTFILES=2 + -P "${CMAKE_CURRENT_SOURCE_DIR}/check_object_files.cmake" + DEPENDS objlib + ) +endif() diff --git a/Tests/GeneratorExpression/check_object_files.cmake b/Tests/GeneratorExpression/check_object_files.cmake new file mode 100644 index 0000000..cfccd29 --- /dev/null +++ b/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() diff --git a/Tests/GeneratorExpression/objlib1.c b/Tests/GeneratorExpression/objlib1.c new file mode 100644 index 0000000..98a95a4 --- /dev/null +++ b/Tests/GeneratorExpression/objlib1.c @@ -0,0 +1,4 @@ + +void objlib1() +{ +} diff --git a/Tests/GeneratorExpression/objlib2.c b/Tests/GeneratorExpression/objlib2.c new file mode 100644 index 0000000..b2c1050 --- /dev/null +++ b/Tests/GeneratorExpression/objlib2.c @@ -0,0 +1,4 @@ + +void objlib2() +{ +} diff --git a/Tests/RunCMake/File_Generate/OutputConflict-stderr.txt b/Tests/RunCMake/File_Generate/OutputConflict-stderr.txt index 0abb7df..a242180 100644 --- a/Tests/RunCMake/File_Generate/OutputConflict-stderr.txt +++ b/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 diff --git a/Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake b/Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake index d807450..daa7c49 100644 --- a/Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake +++ b/Tests/RunCMake/File_Generate/OutputNameMatchesObjects.cmake @@ -1,3 +1,4 @@ +enable_language(CXX) file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$>somefile.cpp" -- cgit v0.12