From 6e89c8a5f1d5aa9bffa95be2b1add8d2c4e55026 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 21 Feb 2014 16:47:34 -0500 Subject: [PATCH] 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. --- Help/command/install.rst | 6 +++ Help/release/3.0.0.rst | 4 ++ Source/cmInstallCommand.cxx | 5 +- Source/cmInstallFilesCommand.cxx | 3 +- Source/cmInstallFilesGenerator.cxx | 51 +++++++++++++++++-- Source/cmInstallFilesGenerator.h | 5 ++ Source/cmInstallProgramsCommand.cxx | 3 +- Tests/ExportImport/Export/CMakeLists.txt | 16 ++++++ Tests/ExportImport/Export/testLib1file1.txt | 1 + Tests/ExportImport/Export/testLib1file2.txt | 1 + Tests/ExportImport/Import/A/CMakeLists.txt | 6 +++ .../Import/A/check_testLib1_genex.cmake | 11 ++++ 12 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 Tests/ExportImport/Export/testLib1file1.txt create mode 100644 Tests/ExportImport/Export/testLib1file2.txt create mode 100644 Tests/ExportImport/Import/A/check_testLib1_genex.cmake diff --git a/Help/command/install.rst b/Help/command/install.rst index ebc95d7bb..47108f0ce 100644 --- a/Help/command/install.rst +++ b/Help/command/install.rst @@ -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. + ------------------------------------------------------------------------------ :: diff --git a/Help/release/3.0.0.rst b/Help/release/3.0.0.rst index 105d6519d..677c7a893 100644 --- a/Help/release/3.0.0.rst +++ b/Help/release/3.0.0.rst @@ -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 ` + 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`. diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index f4fbb8a65..0878aae59 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -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."; diff --git a/Source/cmInstallFilesCommand.cxx b/Source/cmInstallFilesCommand.cxx index 32e463b28..488d4863b 100644 --- a/Source/cmInstallFilesCommand.cxx +++ b/Source/cmInstallFilesCommand.cxx @@ -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; diff --git a/Source/cmInstallFilesGenerator.cxx b/Source/cmInstallFilesGenerator.cxx index 506dcbf46..ec15044c7 100644 --- a/Source/cmInstallFilesGenerator.cxx +++ b/Source/cmInstallFilesGenerator.cxx @@ -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::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 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 files; + cmListFileBacktrace lfbt; + cmGeneratorExpression ge(lfbt); + for(std::vector::const_iterator i = this->Files.begin(); + i != this->Files.end(); ++i) + { + cmsys::auto_ptr cge = ge.Parse(*i); + cmSystemTools::ExpandListArgument(cge->Evaluate(this->Makefile, config), + files); + } + this->AddFilesInstallRule(os, indent, files); +} diff --git a/Source/cmInstallFilesGenerator.h b/Source/cmInstallFilesGenerator.h index 02b005e5a..9dea296d2 100644 --- a/Source/cmInstallFilesGenerator.h +++ b/Source/cmInstallFilesGenerator.h @@ -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 const& files); cmMakefile* Makefile; std::vector Files; diff --git a/Source/cmInstallProgramsCommand.cxx b/Source/cmInstallProgramsCommand.cxx index 9f2945f16..54d903ae6 100644 --- a/Source/cmInstallProgramsCommand.cxx +++ b/Source/cmInstallProgramsCommand.cxx @@ -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; diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt index 0e2828eb8..febdfe6bc 100644 --- a/Tests/ExportImport/Export/CMakeLists.txt +++ b/Tests/ExportImport/Export/CMakeLists.txt @@ -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 $ + $.genex + ) +install(FILES $.genex + DESTINATION lib + ) +set_property(TARGET testLib1 PROPERTY MY_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/testLib1file1.txt + ${CMAKE_CURRENT_SOURCE_DIR}/testLib1file2.txt + ) +install(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) diff --git a/Tests/ExportImport/Export/testLib1file1.txt b/Tests/ExportImport/Export/testLib1file1.txt new file mode 100644 index 000000000..73601df59 --- /dev/null +++ b/Tests/ExportImport/Export/testLib1file1.txt @@ -0,0 +1 @@ +testLib1file1 diff --git a/Tests/ExportImport/Export/testLib1file2.txt b/Tests/ExportImport/Export/testLib1file2.txt new file mode 100644 index 000000000..4874ed109 --- /dev/null +++ b/Tests/ExportImport/Export/testLib1file2.txt @@ -0,0 +1 @@ +testLib1file2 diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt index ebe4af2ff..eb0bbf8b4 100644 --- a/Tests/ExportImport/Import/A/CMakeLists.txt +++ b/Tests/ExportImport/Import/A/CMakeLists.txt @@ -68,6 +68,12 @@ target_link_libraries(imp_testExe1b bld_testLibCycleA ) +add_custom_target(check_testLib1_genex ALL + COMMAND ${CMAKE_COMMAND} -DtestLib1=$ + -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) diff --git a/Tests/ExportImport/Import/A/check_testLib1_genex.cmake b/Tests/ExportImport/Import/A/check_testLib1_genex.cmake new file mode 100644 index 000000000..7c0265248 --- /dev/null +++ b/Tests/ExportImport/Import/A/check_testLib1_genex.cmake @@ -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()