install: Support generator expressions in FILES and PROGRAMS mode

Teach the install(FILES) and install(PROGRAMS) commands to evaluate
generator expressions in the list of files.

Extend the ExportImport test to cover installation cases involving
generator expressions.
This commit is contained in:
Brad King 2014-02-21 16:47:34 -05:00
parent f11f7b34a8
commit 6e89c8a5f1
12 changed files with 105 additions and 7 deletions

View File

@ -169,6 +169,12 @@ default permissions for the installed file also include ``OWNER_EXECUTE``,
programs that are not targets, such as shell scripts. Use the ``TARGETS``
form to install targets built within the project.
The list of ``files...`` given to ``FILES`` or ``PROGRAMS`` may use
"generator expressions" with the syntax ``$<...>``. See the
:manual:`cmake-generator-expressions(7)` manual for available expressions.
However, if any item begins in a generator expression it must evaluate
to a full path.
------------------------------------------------------------------------------
::

View File

@ -102,6 +102,10 @@ Commands
configuration because it will not be available.
Use :ref:`Alias Targets` instead. See policy :policy:`CMP0024`.
* The :command:`install(FILES)` command learned to support
:manual:`generator expressions <cmake-generator-expressions(7)>`
in the list of files.
* The :command:`project` command learned to set some version variables
to values specified by the new ``VERSION`` option or to empty strings.
See policy :policy:`CMP0048`.

View File

@ -1355,7 +1355,8 @@ bool cmInstallCommand::MakeFilesFullPath(const char* modeName,
++fileIt)
{
std::string file = (*fileIt);
if(!cmSystemTools::FileIsFullPath(file.c_str()))
std::string::size_type gpos = cmGeneratorExpression::Find(file);
if(gpos != 0 && !cmSystemTools::FileIsFullPath(file.c_str()))
{
file = this->Makefile->GetCurrentDirectory();
file += "/";
@ -1363,7 +1364,7 @@ bool cmInstallCommand::MakeFilesFullPath(const char* modeName,
}
// Make sure the file is not a directory.
if(cmSystemTools::FileIsDirectory(file.c_str()))
if(gpos == file.npos && cmSystemTools::FileIsDirectory(file.c_str()))
{
cmOStringStream e;
e << modeName << " given directory \"" << (*fileIt) << "\" to install.";

View File

@ -148,7 +148,8 @@ void cmInstallFilesCommand::CreateInstallGenerator() const
*/
std::string cmInstallFilesCommand::FindInstallSource(const char* name) const
{
if(cmSystemTools::FileIsFullPath(name))
if(cmSystemTools::FileIsFullPath(name) ||
cmGeneratorExpression::Find(name) == 0)
{
// This is a full path.
return name;

View File

@ -11,6 +11,9 @@
============================================================================*/
#include "cmInstallFilesGenerator.h"
#include "cmGeneratorExpression.h"
#include "cmSystemTools.h"
//----------------------------------------------------------------------------
cmInstallFilesGenerator
::cmInstallFilesGenerator(cmMakefile* mf,
@ -27,6 +30,15 @@ cmInstallFilesGenerator
FilePermissions(file_permissions),
Rename(rename), Optional(optional)
{
// We need per-config actions if any files have generator expressions.
for(std::vector<std::string>::const_iterator i = files.begin();
!this->ActionsPerConfig && i != files.end(); ++i)
{
if(cmGeneratorExpression::Find(*i) != std::string::npos)
{
this->ActionsPerConfig = true;
}
}
}
//----------------------------------------------------------------------------
@ -36,8 +48,9 @@ cmInstallFilesGenerator
}
//----------------------------------------------------------------------------
void cmInstallFilesGenerator::GenerateScriptActions(std::ostream& os,
Indent const& indent)
void cmInstallFilesGenerator::AddFilesInstallRule(
std::ostream& os, Indent const& indent,
std::vector<std::string> const& files)
{
// Write code to install the files.
const char* no_dir_permissions = 0;
@ -45,8 +58,40 @@ void cmInstallFilesGenerator::GenerateScriptActions(std::ostream& os,
(this->Programs
? cmInstallType_PROGRAMS
: cmInstallType_FILES),
this->Files,
files,
this->Optional,
this->FilePermissions.c_str(), no_dir_permissions,
this->Rename.c_str(), 0, indent);
}
//----------------------------------------------------------------------------
void cmInstallFilesGenerator::GenerateScriptActions(std::ostream& os,
Indent const& indent)
{
if(this->ActionsPerConfig)
{
this->cmInstallGenerator::GenerateScriptActions(os, indent);
}
else
{
this->AddFilesInstallRule(os, indent, this->Files);
}
}
//----------------------------------------------------------------------------
void cmInstallFilesGenerator::GenerateScriptForConfig(std::ostream& os,
const char* config,
Indent const& indent)
{
std::vector<std::string> files;
cmListFileBacktrace lfbt;
cmGeneratorExpression ge(lfbt);
for(std::vector<std::string>::const_iterator i = this->Files.begin();
i != this->Files.end(); ++i)
{
cmsys::auto_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*i);
cmSystemTools::ExpandListArgument(cge->Evaluate(this->Makefile, config),
files);
}
this->AddFilesInstallRule(os, indent, files);
}

View File

@ -34,6 +34,11 @@ public:
protected:
virtual void GenerateScriptActions(std::ostream& os, Indent const& indent);
virtual void GenerateScriptForConfig(std::ostream& os,
const char* config,
Indent const& indent);
void AddFilesInstallRule(std::ostream& os, Indent const& indent,
std::vector<std::string> const& files);
cmMakefile* Makefile;
std::vector<std::string> Files;

View File

@ -109,7 +109,8 @@ void cmInstallProgramsCommand::FinalPass()
std::string cmInstallProgramsCommand
::FindInstallSource(const char* name) const
{
if(cmSystemTools::FileIsFullPath(name))
if(cmSystemTools::FileIsFullPath(name) ||
cmGeneratorExpression::Find(name) == 0)
{
// This is a full path.
return name;

View File

@ -23,6 +23,22 @@ add_library(testLib1 STATIC testLib1.c)
add_library(testLib2 STATIC testLib2.c)
target_link_libraries(testLib2 testLib1)
# Test install(FILES) with generator expressions referencing testLib1.
add_custom_command(TARGET testLib1 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:testLib1>
$<TARGET_FILE:testLib1>.genex
)
install(FILES $<TARGET_FILE:testLib1>.genex
DESTINATION lib
)
set_property(TARGET testLib1 PROPERTY MY_FILES
${CMAKE_CURRENT_SOURCE_DIR}/testLib1file1.txt
${CMAKE_CURRENT_SOURCE_DIR}/testLib1file2.txt
)
install(FILES $<TARGET_PROPERTY:testLib1,MY_FILES>
DESTINATION doc
)
# Test library with empty link interface. Link it to an implementation
# dependency that itself links to dependencies publicly.
add_library(testLib3ImpDep SHARED testLib3ImpDep.c)

View File

@ -0,0 +1 @@
testLib1file1

View File

@ -0,0 +1 @@
testLib1file2

View File

@ -68,6 +68,12 @@ target_link_libraries(imp_testExe1b
bld_testLibCycleA
)
add_custom_target(check_testLib1_genex ALL
COMMAND ${CMAKE_COMMAND} -DtestLib1=$<TARGET_FILE:exp_testLib1>
-Dprefix=${CMAKE_INSTALL_PREFIX}
-P ${CMAKE_CURRENT_SOURCE_DIR}/check_testLib1_genex.cmake
)
add_executable(cmp0022OLD_test cmp0022OLD_test_vs6_1.cpp)
target_link_libraries(cmp0022OLD_test bld_cmp0022OLD)
add_executable(cmp0022NEW_test cmp0022NEW_test_vs6_1.cpp)

View File

@ -0,0 +1,11 @@
foreach(f
"${testLib1}.genex"
"${prefix}/doc/testLib1file1.txt"
"${prefix}/doc/testLib1file2.txt"
)
if(EXISTS "${f}")
message(STATUS "'${f}' exists!")
else()
message(FATAL_ERROR "Missing file:\n ${f}")
endif()
endforeach()