install: Allow generator expressions in TARGETS DESTINATION (#14317)

This will allow per-config destinations for targets in EXPORT sets.
Using multiple install(TARGETS) with separate CONFIGURATIONS is
rejected as a target appearing more than once in an export set.
Now instead one can write

 install(TARGETS foo EXPORT exp DESTINATION lib/$<CONFIG>)

to get a single logical membership of the target in the export set
while still having a per-config destination.
This commit is contained in:
Brad King 2015-02-11 14:02:45 -05:00
parent 7607c3d16a
commit f30022eb07
14 changed files with 48 additions and 8 deletions

View File

@ -159,6 +159,10 @@ file itself, call ``install(EXPORT)``, documented below.
Installing a target with the :prop_tgt:`EXCLUDE_FROM_ALL` target property Installing a target with the :prop_tgt:`EXCLUDE_FROM_ALL` target property
set to ``TRUE`` has undefined behavior. set to ``TRUE`` has undefined behavior.
The install destination given to the target install ``DESTINATION`` may
use "generator expressions" with the syntax ``$<...>``. See the
:manual:`cmake-generator-expressions(7)` manual for available expressions.
Installing Files Installing Files
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^

View File

@ -0,0 +1,5 @@
install-DESTINATION-genex
-------------------------
* The :command:`install(TARGETS)` command learned to support
generator expressions in the ``DESTINATION`` value.

View File

@ -398,7 +398,7 @@ cmExportInstallFileGenerator
cmTarget* target = itgen->GetTarget(); cmTarget* target = itgen->GetTarget();
// Construct the installed location of the target. // Construct the installed location of the target.
std::string dest = itgen->GetDestination(); std::string dest = itgen->GetDestination(config);
std::string value; std::string value;
if(!cmSystemTools::FileIsFullPath(dest.c_str())) if(!cmSystemTools::FileIsFullPath(dest.c_str()))
{ {

View File

@ -12,6 +12,7 @@
#include "cmInstallTargetGenerator.h" #include "cmInstallTargetGenerator.h"
#include "cmComputeLinkInformation.h" #include "cmComputeLinkInformation.h"
#include "cmGeneratorExpression.h"
#include "cmGlobalGenerator.h" #include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h" #include "cmLocalGenerator.h"
#include "cmMakefile.h" #include "cmMakefile.h"
@ -78,7 +79,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
fromDirConfig += "/"; fromDirConfig += "/";
} }
std::string toDir = std::string toDir =
this->ConvertToAbsoluteDestination(this->Destination); this->ConvertToAbsoluteDestination(this->GetDestination(config));
toDir += "/"; toDir += "/";
// Compute the list of files to install for this target. // Compute the list of files to install for this target.
@ -323,7 +324,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
const char* no_dir_permissions = 0; const char* no_dir_permissions = 0;
const char* no_rename = 0; const char* no_rename = 0;
bool optional = this->Optional || this->ImportLibrary; bool optional = this->Optional || this->ImportLibrary;
this->AddInstallRule(os, this->Destination, this->AddInstallRule(os, this->GetDestination(config),
type, filesFrom, optional, type, filesFrom, optional,
this->FilePermissions.c_str(), no_dir_permissions, this->FilePermissions.c_str(), no_dir_permissions,
no_rename, literal_args.c_str(), no_rename, literal_args.c_str(),
@ -334,6 +335,15 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
&cmInstallTargetGenerator::PostReplacementTweaks); &cmInstallTargetGenerator::PostReplacementTweaks);
} }
//----------------------------------------------------------------------------
std::string
cmInstallTargetGenerator::GetDestination(std::string const& config) const
{
cmGeneratorExpression ge;
return ge.Parse(this->Destination)
->Evaluate(this->Target->GetMakefile(), config);
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
std::string std::string
cmInstallTargetGenerator::GetInstallFilename(const std::string& config) const cmInstallTargetGenerator::GetInstallFilename(const std::string& config) const

View File

@ -60,8 +60,7 @@ public:
cmTarget* GetTarget() const { return this->Target; } cmTarget* GetTarget() const { return this->Target; }
bool IsImportLibrary() const { return this->ImportLibrary; } bool IsImportLibrary() const { return this->ImportLibrary; }
std::string const& GetDestination() const std::string GetDestination(std::string const& config) const;
{ return this->Destination; }
protected: protected:
virtual void GenerateScript(std::ostream& os); virtual void GenerateScript(std::ostream& os);

View File

@ -68,6 +68,11 @@ add_library(testLib5 SHARED testLib5.c)
add_library(testLib6 STATIC testLib6.cxx testLib6c.c) add_library(testLib6 STATIC testLib6.cxx testLib6c.c)
add_library(testLibPerConfigDest STATIC testLibPerConfigDest.c)
install(TARGETS testLibPerConfigDest EXPORT exp
DESTINATION lib/$<$<BOOL:$<CONFIG>>:$<CONFIG>>$<$<NOT:$<BOOL:$<CONFIG>>>:NoConfig>
)
# Work-around: Visual Studio 6 does not support per-target object files. # Work-around: Visual Studio 6 does not support per-target object files.
set(VS6) set(VS6)
if("${CMAKE_GENERATOR}" MATCHES "Visual Studio 6") if("${CMAKE_GENERATOR}" MATCHES "Visual Studio 6")
@ -446,9 +451,9 @@ install(
cmp0022NEW cmp0022OLD cmp0022NEW cmp0022OLD
systemlib systemlib
EXPORT exp EXPORT exp
RUNTIME DESTINATION bin RUNTIME DESTINATION $<1:bin>
LIBRARY DESTINATION lib NAMELINK_SKIP LIBRARY DESTINATION $<1:lib> NAMELINK_SKIP
ARCHIVE DESTINATION lib ARCHIVE DESTINATION $<1:lib>
FRAMEWORK DESTINATION Frameworks FRAMEWORK DESTINATION Frameworks
BUNDLE DESTINATION Applications BUNDLE DESTINATION Applications
) )
@ -503,6 +508,7 @@ export(TARGETS testExe1 testLib1 testLib2 testLib3
export(TARGETS testExe2 testLib4 testLib5 testLib6 testExe3 testExe2lib export(TARGETS testExe2 testLib4 testLib5 testLib6 testExe3 testExe2lib
testLib4lib testLib4libdbg testLib4libopt testLib4lib testLib4libdbg testLib4libopt
testLibCycleA testLibCycleB testLibCycleA testLibCycleB
testLibPerConfigDest
NAMESPACE bld_ NAMESPACE bld_
APPEND FILE ExportBuildTree.cmake APPEND FILE ExportBuildTree.cmake
) )

View File

@ -0,0 +1 @@
int testLibPerConfigDest(void) { return 0; }

View File

@ -34,6 +34,7 @@ target_link_libraries(imp_testExe1
exp_testLib5 exp_testLib5
exp_testLib6 exp_testLib6
exp_testLibCycleA exp_testLibCycleA
exp_testLibPerConfigDest
) )
# Try building a plugin to an executable imported from the install tree. # Try building a plugin to an executable imported from the install tree.
@ -66,6 +67,7 @@ target_link_libraries(imp_testExe1b
bld_testLib5 bld_testLib5
bld_testLib6 bld_testLib6
bld_testLibCycleA bld_testLibCycleA
bld_testLibPerConfigDest
) )
add_custom_target(check_testLib1_genex ALL add_custom_target(check_testLib1_genex ALL

View File

@ -7,6 +7,7 @@ extern int testLib4lib();
extern int testLib5(); extern int testLib5();
extern int testLib6(); extern int testLib6();
extern int testLibCycleA1(); extern int testLibCycleA1();
extern int testLibPerConfigDest();
/* Switch a symbol between debug and optimized builds to make sure the /* Switch a symbol between debug and optimized builds to make sure the
proper library is found from the testLib4 link interface. */ proper library is found from the testLib4 link interface. */
@ -21,5 +22,6 @@ int main()
{ {
return (testLib2() + generated_by_testExe1() + testLib3() + testLib4() return (testLib2() + generated_by_testExe1() + testLib3() + testLib4()
+ testLib5() + testLib6() + testLibCycleA1() + testLib5() + testLib6() + testLibCycleA1()
+ testLibPerConfigDest()
+ generated_by_testExe3() + testLib4lib() + testLib4libcfg()); + generated_by_testExe3() + testLib4lib() + testLib4libcfg());
} }

View File

@ -6,3 +6,4 @@ run_cmake(DIRECTORY-message-lazy)
run_cmake(SkipInstallRulesWarning) run_cmake(SkipInstallRulesWarning)
run_cmake(SkipInstallRulesNoWarning1) run_cmake(SkipInstallRulesNoWarning1)
run_cmake(SkipInstallRulesNoWarning2) run_cmake(SkipInstallRulesNoWarning2)
run_cmake(TARGETS-DESTINATION-bad)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,6 @@
CMake Error:
Error evaluating generator expression:
\$<NOTAGENEX>
Expression did not evaluate to a known generator expression

View File

@ -0,0 +1,3 @@
enable_language(C)
add_library(empty empty.c)
install(TARGETS empty DESTINATION $<NOTAGENEX>)

View File