From bf98cc252f18e761ed9a57d2f7a9304bfbb621de Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Wed, 26 Feb 2014 15:59:18 +0100 Subject: [PATCH] Genex: Evaluate TARGET_OBJECTS as a normal expression. --- Help/manual/cmake-generator-expressions.7.rst | 3 + .../dev/file-GENERATE-TARGET_OBJECTS.rst | 6 ++ Source/cmGeneratorExpressionEvaluator.cxx | 64 +++++++++++++++++++ Source/cmSourceFile.cxx | 12 ++++ Source/cmSourceFile.h | 4 ++ Tests/GeneratorExpression/CMakeLists.txt | 14 ++++ .../check_object_files.cmake | 48 ++++++++++++++ Tests/GeneratorExpression/objlib1.c | 5 ++ Tests/GeneratorExpression/objlib2.c | 5 ++ Tests/RunCMake/CMakeLists.txt | 1 + Tests/RunCMake/TargetObjects/CMakeLists.txt | 3 + .../TargetObjects/NoTarget-result.txt | 1 + .../TargetObjects/NoTarget-stderr.txt | 8 +++ Tests/RunCMake/TargetObjects/NoTarget.cmake | 2 + .../TargetObjects/NotObjlibTarget-result.txt | 1 + .../TargetObjects/NotObjlibTarget-stderr.txt | 8 +++ .../TargetObjects/NotObjlibTarget.cmake | 4 ++ .../RunCMake/TargetObjects/RunCMakeTest.cmake | 4 ++ Tests/RunCMake/TargetObjects/empty.cpp | 7 ++ 19 files changed, 200 insertions(+) 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 create mode 100644 Tests/RunCMake/TargetObjects/CMakeLists.txt create mode 100644 Tests/RunCMake/TargetObjects/NoTarget-result.txt create mode 100644 Tests/RunCMake/TargetObjects/NoTarget-stderr.txt create mode 100644 Tests/RunCMake/TargetObjects/NoTarget.cmake create mode 100644 Tests/RunCMake/TargetObjects/NotObjlibTarget-result.txt create mode 100644 Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt create mode 100644 Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake create mode 100644 Tests/RunCMake/TargetObjects/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/TargetObjects/empty.cpp diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index ac8c3f8288..17263d4468 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -188,3 +188,6 @@ property is non-empty:: Content of ``...`` converted to upper case. ``$`` Content of ``...`` converted to a C identifier. +``$`` + List of objects resulting from build of ``objLib``. ``objLib`` must be an + object of type ``OBJECT_LIBRARY``. 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 0000000000..853a803afb --- /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/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index 14b2a1a321..669694c00e 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -15,6 +15,8 @@ #include "cmGeneratorExpressionParser.h" #include "cmGeneratorExpressionDAGChecker.h" #include "cmGeneratorExpression.h" +#include "cmLocalGenerator.h" +#include "cmSourceFile.h" #include @@ -1239,6 +1241,67 @@ static const struct TargetNameNode : public cmGeneratorExpressionNode } targetNameNode; +//---------------------------------------------------------------------------- +static const struct TargetObjectsNode : public cmGeneratorExpressionNode +{ + TargetObjectsNode() {} + + std::string Evaluate(const std::vector ¶meters, + 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 objectSources; + gt->GetObjectSources(objectSources); + std::map mapping; + + for(std::vector::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::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; diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx index b9b62518ba..0ab30a2c7b 100644 --- a/Source/cmSourceFile.cxx +++ b/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() { diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h index 17c96ac097..755a2cfe8b 100644 --- a/Source/cmSourceFile.h +++ b/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); diff --git a/Tests/GeneratorExpression/CMakeLists.txt b/Tests/GeneratorExpression/CMakeLists.txt index a0e34ef268..66b175a95d 100644 --- a/Tests/GeneratorExpression/CMakeLists.txt +++ b/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 "$,\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 +) diff --git a/Tests/GeneratorExpression/check_object_files.cmake b/Tests/GeneratorExpression/check_object_files.cmake new file mode 100644 index 0000000000..889fe809fc --- /dev/null +++ b/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() diff --git a/Tests/GeneratorExpression/objlib1.c b/Tests/GeneratorExpression/objlib1.c new file mode 100644 index 0000000000..aa8de0a27b --- /dev/null +++ b/Tests/GeneratorExpression/objlib1.c @@ -0,0 +1,5 @@ + +void objlib1() +{ + +} diff --git a/Tests/GeneratorExpression/objlib2.c b/Tests/GeneratorExpression/objlib2.c new file mode 100644 index 0000000000..3c7307af7a --- /dev/null +++ b/Tests/GeneratorExpression/objlib2.c @@ -0,0 +1,5 @@ + +void objlib2() +{ + +} diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 7691f32b2c..31e7805037 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/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) diff --git a/Tests/RunCMake/TargetObjects/CMakeLists.txt b/Tests/RunCMake/TargetObjects/CMakeLists.txt new file mode 100644 index 0000000000..be9d4038db --- /dev/null +++ b/Tests/RunCMake/TargetObjects/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.4) +project(${RunCMake_TEST}) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/TargetObjects/NoTarget-result.txt b/Tests/RunCMake/TargetObjects/NoTarget-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/TargetObjects/NoTarget-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/TargetObjects/NoTarget-stderr.txt b/Tests/RunCMake/TargetObjects/NoTarget-stderr.txt new file mode 100644 index 0000000000..2c4f877e82 --- /dev/null +++ b/Tests/RunCMake/TargetObjects/NoTarget-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at NoTarget.cmake:2 \(file\): + Error evaluating generator expression: + + \$ + + Objects of target "NoTarget" referenced but no such target exists. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/TargetObjects/NoTarget.cmake b/Tests/RunCMake/TargetObjects/NoTarget.cmake new file mode 100644 index 0000000000..f203c2310b --- /dev/null +++ b/Tests/RunCMake/TargetObjects/NoTarget.cmake @@ -0,0 +1,2 @@ + +file(GENERATE OUTPUT test_output CONTENT $) diff --git a/Tests/RunCMake/TargetObjects/NotObjlibTarget-result.txt b/Tests/RunCMake/TargetObjects/NotObjlibTarget-result.txt new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/Tests/RunCMake/TargetObjects/NotObjlibTarget-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt b/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt new file mode 100644 index 0000000000..bb83934034 --- /dev/null +++ b/Tests/RunCMake/TargetObjects/NotObjlibTarget-stderr.txt @@ -0,0 +1,8 @@ +CMake Error at NotObjlibTarget.cmake:4 \(file\): + Error evaluating generator expression: + + \$ + + Objects of target "StaticLib" referenced but is not an OBJECT library. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake b/Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake new file mode 100644 index 0000000000..c7f8a71da4 --- /dev/null +++ b/Tests/RunCMake/TargetObjects/NotObjlibTarget.cmake @@ -0,0 +1,4 @@ + +add_library(StaticLib empty.cpp) + +file(GENERATE OUTPUT test_output CONTENT $) diff --git a/Tests/RunCMake/TargetObjects/RunCMakeTest.cmake b/Tests/RunCMake/TargetObjects/RunCMakeTest.cmake new file mode 100644 index 0000000000..30b9fee533 --- /dev/null +++ b/Tests/RunCMake/TargetObjects/RunCMakeTest.cmake @@ -0,0 +1,4 @@ +include(RunCMake) + +run_cmake(NoTarget) +run_cmake(NotObjlibTarget) diff --git a/Tests/RunCMake/TargetObjects/empty.cpp b/Tests/RunCMake/TargetObjects/empty.cpp new file mode 100644 index 0000000000..bfbbddeb90 --- /dev/null +++ b/Tests/RunCMake/TargetObjects/empty.cpp @@ -0,0 +1,7 @@ +#ifdef _WIN32 +__declspec(dllexport) +#endif +int empty() +{ + return 0; +}