Genex: Evaluate TARGET_OBJECTS as a normal expression.
This commit is contained in:
parent
8cd113ad1d
commit
bf98cc252f
|
@ -188,3 +188,6 @@ property is non-empty::
|
||||||
Content of ``...`` converted to upper case.
|
Content of ``...`` converted to upper case.
|
||||||
``$<MAKE_C_IDENTIFIER:...>``
|
``$<MAKE_C_IDENTIFIER:...>``
|
||||||
Content of ``...`` converted to a 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``.
|
||||||
|
|
|
@ -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)>`.
|
|
@ -15,6 +15,8 @@
|
||||||
#include "cmGeneratorExpressionParser.h"
|
#include "cmGeneratorExpressionParser.h"
|
||||||
#include "cmGeneratorExpressionDAGChecker.h"
|
#include "cmGeneratorExpressionDAGChecker.h"
|
||||||
#include "cmGeneratorExpression.h"
|
#include "cmGeneratorExpression.h"
|
||||||
|
#include "cmLocalGenerator.h"
|
||||||
|
#include "cmSourceFile.h"
|
||||||
|
|
||||||
#include <cmsys/String.h>
|
#include <cmsys/String.h>
|
||||||
|
|
||||||
|
@ -1239,6 +1241,67 @@ static const struct TargetNameNode : public cmGeneratorExpressionNode
|
||||||
|
|
||||||
} targetNameNode;
|
} targetNameNode;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
static const struct TargetObjectsNode : public cmGeneratorExpressionNode
|
||||||
|
{
|
||||||
|
TargetObjectsNode() {}
|
||||||
|
|
||||||
|
std::string Evaluate(const std::vector<std::string> ¶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<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[] = {
|
static const char* targetPolicyWhitelist[] = {
|
||||||
0
|
0
|
||||||
|
@ -1593,6 +1656,7 @@ cmGeneratorExpressionNode* GetNode(const std::string &identifier)
|
||||||
nodeMap["SEMICOLON"] = &semicolonNode;
|
nodeMap["SEMICOLON"] = &semicolonNode;
|
||||||
nodeMap["TARGET_PROPERTY"] = &targetPropertyNode;
|
nodeMap["TARGET_PROPERTY"] = &targetPropertyNode;
|
||||||
nodeMap["TARGET_NAME"] = &targetNameNode;
|
nodeMap["TARGET_NAME"] = &targetNameNode;
|
||||||
|
nodeMap["TARGET_OBJECTS"] = &targetObjectsNode;
|
||||||
nodeMap["TARGET_POLICY"] = &targetPolicyNode;
|
nodeMap["TARGET_POLICY"] = &targetPolicyNode;
|
||||||
nodeMap["BUILD_INTERFACE"] = &buildInterfaceNode;
|
nodeMap["BUILD_INTERFACE"] = &buildInterfaceNode;
|
||||||
nodeMap["INSTALL_INTERFACE"] = &installInterfaceNode;
|
nodeMap["INSTALL_INTERFACE"] = &installInterfaceNode;
|
||||||
|
|
|
@ -38,6 +38,18 @@ std::string const& cmSourceFile::GetExtension() const
|
||||||
return this->Extension;
|
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()
|
std::string cmSourceFile::GetLanguage()
|
||||||
{
|
{
|
||||||
|
|
|
@ -97,6 +97,9 @@ public:
|
||||||
*/
|
*/
|
||||||
bool Matches(cmSourceFileLocation const&);
|
bool Matches(cmSourceFileLocation const&);
|
||||||
|
|
||||||
|
void SetObjectLibrary(std::string const& objlib);
|
||||||
|
std::string GetObjectLibrary() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
cmSourceFileLocation Location;
|
cmSourceFileLocation Location;
|
||||||
cmPropertyMap Properties;
|
cmPropertyMap Properties;
|
||||||
|
@ -105,6 +108,7 @@ private:
|
||||||
std::string Language;
|
std::string Language;
|
||||||
std::string FullPath;
|
std::string FullPath;
|
||||||
bool FindFullPathFailed;
|
bool FindFullPathFailed;
|
||||||
|
std::string ObjectLibrary;
|
||||||
|
|
||||||
bool FindFullPath(std::string* error);
|
bool FindFullPath(std::string* error);
|
||||||
bool TryFullPath(const std::string& path, const std::string& ext);
|
bool TryFullPath(const std::string& path, const std::string& ext);
|
||||||
|
|
|
@ -258,3 +258,17 @@ 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)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
|
@ -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()
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
void objlib1()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
void objlib2()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -49,6 +49,7 @@ add_RunCMake_test(GeneratorToolset)
|
||||||
add_RunCMake_test(TargetPropertyGeneratorExpressions)
|
add_RunCMake_test(TargetPropertyGeneratorExpressions)
|
||||||
add_RunCMake_test(Languages)
|
add_RunCMake_test(Languages)
|
||||||
add_RunCMake_test(ObjectLibrary)
|
add_RunCMake_test(ObjectLibrary)
|
||||||
|
add_RunCMake_test(TargetObjects)
|
||||||
add_RunCMake_test(find_dependency)
|
add_RunCMake_test(find_dependency)
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
add_RunCMake_test(PositionIndependentCode)
|
add_RunCMake_test(PositionIndependentCode)
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8.4)
|
||||||
|
project(${RunCMake_TEST})
|
||||||
|
include(${RunCMake_TEST}.cmake)
|
|
@ -0,0 +1 @@
|
||||||
|
1
|
|
@ -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\)
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
file(GENERATE OUTPUT test_output CONTENT $<TARGET_OBJECTS:NoTarget>)
|
|
@ -0,0 +1 @@
|
||||||
|
1
|
|
@ -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\)
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
add_library(StaticLib empty.cpp)
|
||||||
|
|
||||||
|
file(GENERATE OUTPUT test_output CONTENT $<TARGET_OBJECTS:StaticLib>)
|
|
@ -0,0 +1,4 @@
|
||||||
|
include(RunCMake)
|
||||||
|
|
||||||
|
run_cmake(NoTarget)
|
||||||
|
run_cmake(NotObjlibTarget)
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifdef _WIN32
|
||||||
|
__declspec(dllexport)
|
||||||
|
#endif
|
||||||
|
int empty()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue