Add generator expression support to OUTPUT_DIRECTORY target properties

If {ARCHIVE,LIBRARY,RUNTIME}_OUTPUT_DIRECTORY is set with a genex then
do not add the per-config subdirectory on multi-config generators.
This will allow projects to use $<CONFIG> to place the per-config
part of the directory path somewhere other than the end.
This commit is contained in:
Robert Goulet 2015-08-11 15:19:03 -04:00 committed by Brad King
parent e36a05fd7f
commit d25819bc26
14 changed files with 98 additions and 7 deletions

View File

@ -11,3 +11,6 @@ per-configuration subdirectory to the specified directory. This
property is initialized by the value of the property is initialized by the value of the
:variable:`CMAKE_ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>` variable if :variable:`CMAKE_ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>` variable if
it is set when a target is created. it is set when a target is created.
Contents of ``ARCHIVE_OUTPUT_DIRECTORY_<CONFIG>`` may use
:manual:`generator expressions <cmake-generator-expressions(7)>`.

View File

@ -11,3 +11,6 @@ per-configuration subdirectory to the specified directory. This
property is initialized by the value of the property is initialized by the value of the
:variable:`CMAKE_LIBRARY_OUTPUT_DIRECTORY_<CONFIG>` variable if :variable:`CMAKE_LIBRARY_OUTPUT_DIRECTORY_<CONFIG>` variable if
it is set when a target is created. it is set when a target is created.
Contents of ``LIBRARY_OUTPUT_DIRECTORY_<CONFIG>`` may use
:manual:`generator expressions <cmake-generator-expressions(7)>`.

View File

@ -11,3 +11,6 @@ per-configuration subdirectory to the specified directory. This
property is initialized by the value of the property is initialized by the value of the
:variable:`CMAKE_RUNTIME_OUTPUT_DIRECTORY_<CONFIG>` variable if :variable:`CMAKE_RUNTIME_OUTPUT_DIRECTORY_<CONFIG>` variable if
it is set when a target is created. it is set when a target is created.
Contents of ``RUNTIME_OUTPUT_DIRECTORY_<CONFIG>`` may use
:manual:`generator expressions <cmake-generator-expressions(7)>`.

View File

@ -1,8 +1,11 @@
Output directory in which to build |XXX| target files. Output directory in which to build |XXX| target files.
This property specifies the directory into which |xxx| target files This property specifies the directory into which |xxx| target files
should be built. Multi-configuration generators (VS, Xcode) append a should be built. The property value may use
per-configuration subdirectory to the specified directory. :manual:`generator expressions <cmake-generator-expressions(7)>`.
Multi-configuration generators (VS, Xcode) append a per-configuration
subdirectory to the specified directory unless a generator expression
is used.
This property is initialized by the value of the variable This property is initialized by the value of the variable
|CMAKE_XXX_OUTPUT_DIRECTORY| if it is set when a target is created. |CMAKE_XXX_OUTPUT_DIRECTORY| if it is set when a target is created.

View File

@ -0,0 +1,7 @@
OUTPUT_DIRECTORY-genex
----------------------
* The :prop_tgt:`ARCHIVE_OUTPUT_DIRECTORY`,
:prop_tgt:`LIBRARY_OUTPUT_DIRECTORY`, and
:prop_tgt:`RUNTIME_OUTPUT_DIRECTORY` target properties learned to
support :manual:`generator expressions <cmake-generator-expressions(7)>`.

View File

@ -3520,7 +3520,10 @@ bool cmTarget::ComputeOutputDir(const std::string& config,
if(const char* config_outdir = this->GetProperty(configProp)) if(const char* config_outdir = this->GetProperty(configProp))
{ {
// Use the user-specified per-configuration output directory. // Use the user-specified per-configuration output directory.
out = config_outdir; cmGeneratorExpression ge;
cmsys::auto_ptr<cmCompiledGeneratorExpression> cge =
ge.Parse(config_outdir);
out = cge->Evaluate(this->Makefile, config);
// Skip per-configuration subdirectory. // Skip per-configuration subdirectory.
conf = ""; conf = "";
@ -3528,7 +3531,17 @@ bool cmTarget::ComputeOutputDir(const std::string& config,
else if(const char* outdir = this->GetProperty(propertyName)) else if(const char* outdir = this->GetProperty(propertyName))
{ {
// Use the user-specified output directory. // Use the user-specified output directory.
out = outdir; cmGeneratorExpression ge;
cmsys::auto_ptr<cmCompiledGeneratorExpression> cge =
ge.Parse(outdir);
out = cge->Evaluate(this->Makefile, config);
// Skip per-configuration subdirectory if the value contained a
// generator expression.
if (out != outdir)
{
conf = "";
}
} }
else if(this->GetType() == cmTarget::EXECUTABLE) else if(this->GetType() == cmTarget::EXECUTABLE)
{ {

View File

@ -105,6 +105,19 @@ target_link_libraries(testLib4
add_executable(testExe3 testExe3.c) add_executable(testExe3 testExe3.c)
set_property(TARGET testExe3 PROPERTY MACOSX_BUNDLE 1) set_property(TARGET testExe3 PROPERTY MACOSX_BUNDLE 1)
# Test <ARCHIVE|LIBRARY|RUNTIME>_OUTPUT_DIRECTORY[_<CONFIG>] properties with generator expressions
add_executable(testExe4 testExe4.c)
target_link_libraries(testExe4 testExe1lib)
set_property(TARGET testLib7 PROPERTY ARCHIVE_OUTPUT_DIRECTORY_DEBUG testLib7D-$<CONFIG>)
set_property(TARGET testLib7 PROPERTY ARCHIVE_OUTPUT_DIRECTORY_RELEASE testLib7R-$<CONFIG>)
set_property(TARGET testLib7 PROPERTY ARCHIVE_OUTPUT_DIRECTORY testLib7-$<CONFIG>)
set_property(TARGET testLib5 PROPERTY LIBRARY_OUTPUT_DIRECTORY_DEBUG testLib5D-$<CONFIG>)
set_property(TARGET testLib5 PROPERTY LIBRARY_OUTPUT_DIRECTORY_RELEASE testLib5R-$<CONFIG>)
set_property(TARGET testLib5 PROPERTY LIBRARY_OUTPUT_DIRECTORY testLib5-$<CONFIG>)
set_property(TARGET testExe4 PROPERTY RUNTIME_OUTPUT_DIRECTORY_DEBUG testExe4D-$<CONFIG>)
set_property(TARGET testExe4 PROPERTY RUNTIME_OUTPUT_DIRECTORY_RELEASE testExe4R-$<CONFIG>)
set_property(TARGET testExe4 PROPERTY RUNTIME_OUTPUT_DIRECTORY testExe4-$<CONFIG>)
# Test cyclic dependencies. # Test cyclic dependencies.
add_library(testLibCycleA STATIC add_library(testLibCycleA STATIC
testLibCycleA1.c testLibCycleA2.c testLibCycleA3.c) testLibCycleA1.c testLibCycleA2.c testLibCycleA3.c)
@ -450,7 +463,7 @@ install(FILES
# Install and export from install tree. # Install and export from install tree.
install( install(
TARGETS TARGETS
testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3 testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3 testExe4
testExe2lib testLib4lib testLib4libdbg testLib4libopt testExe2lib testLib4lib testLib4libdbg testLib4libopt
testLib6 testLib7 testLib6 testLib7
testLibCycleA testLibCycleB testLibCycleA testLibCycleB
@ -511,7 +524,7 @@ export(TARGETS testExe1 testLib1 testLib2 testLib3
NAMESPACE bld_ NAMESPACE bld_
FILE ExportBuildTree.cmake FILE ExportBuildTree.cmake
) )
export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe2lib export(TARGETS testExe2 testLib4 testLib5 testLib6 testLib7 testExe3 testExe4 testExe2lib
testLib4lib testLib4libdbg testLib4libopt testLib4lib testLib4libdbg testLib4libopt
testLibCycleA testLibCycleB testLibCycleA testLibCycleB
testLibPerConfigDest testLibPerConfigDest

View File

@ -0,0 +1,24 @@
#include <stdio.h>
int main(int argc, const char* argv[])
{
if(argc < 2)
{
fprintf(stderr, "Must specify output file.\n");
return 1;
}
{
FILE* f = fopen(argv[1], "w");
if(f)
{
fprintf(f, "int generated_by_testExe4() { return 0; }\n");
fclose(f);
}
else
{
fprintf(stderr, "Error writing to %s\n", argv[1]);
return 1;
}
}
return 0;
}

View File

@ -19,11 +19,17 @@ add_custom_command(
COMMAND exp_testExe3 ${Import_BINARY_DIR}/exp_generated3.c COMMAND exp_testExe3 ${Import_BINARY_DIR}/exp_generated3.c
DEPENDS exp_testExe3 DEPENDS exp_testExe3
) )
add_custom_command(
OUTPUT ${Import_BINARY_DIR}/exp_generated4.c
COMMAND exp_testExe4 ${Import_BINARY_DIR}/exp_generated4.c
DEPENDS exp_testExe4
)
add_executable(imp_testExe1 add_executable(imp_testExe1
imp_testExe1.c imp_testExe1.c
${Import_BINARY_DIR}/exp_generated.c ${Import_BINARY_DIR}/exp_generated.c
${Import_BINARY_DIR}/exp_generated3.c ${Import_BINARY_DIR}/exp_generated3.c
${Import_BINARY_DIR}/exp_generated4.c
) )
# Try linking to a library imported from the install tree. # Try linking to a library imported from the install tree.
@ -53,11 +59,17 @@ add_custom_command(
COMMAND bld_testExe3 ${Import_BINARY_DIR}/bld_generated3.c COMMAND bld_testExe3 ${Import_BINARY_DIR}/bld_generated3.c
DEPENDS bld_testExe3 DEPENDS bld_testExe3
) )
add_custom_command(
OUTPUT ${Import_BINARY_DIR}/bld_generated4.c
COMMAND bld_testExe4 ${Import_BINARY_DIR}/bld_generated4.c
DEPENDS bld_testExe4
)
add_executable(imp_testExe1b add_executable(imp_testExe1b
imp_testExe1.c imp_testExe1.c
${Import_BINARY_DIR}/bld_generated.c ${Import_BINARY_DIR}/bld_generated.c
${Import_BINARY_DIR}/bld_generated3.c ${Import_BINARY_DIR}/bld_generated3.c
${Import_BINARY_DIR}/bld_generated4.c
) )
# Try linking to a library imported from the build tree. # Try linking to a library imported from the build tree.

View File

@ -1,5 +1,6 @@
extern int generated_by_testExe1(); extern int generated_by_testExe1();
extern int generated_by_testExe3(); extern int generated_by_testExe3();
extern int generated_by_testExe4();
extern int testLib2(); extern int testLib2();
extern int testLib3(); extern int testLib3();
extern int testLib4(); extern int testLib4();
@ -24,5 +25,5 @@ int main()
return (testLib2() + generated_by_testExe1() + testLib3() + testLib4() return (testLib2() + generated_by_testExe1() + testLib3() + testLib4()
+ testLib5() + testLib6() + testLib7() + testLibCycleA1() + testLib5() + testLib6() + testLib7() + testLibCycleA1()
+ testLibPerConfigDest() + testLibPerConfigDest()
+ generated_by_testExe3() + testLib4lib() + testLib4libcfg()); + generated_by_testExe3() + generated_by_testExe4() + testLib4lib() + testLib4libcfg());
} }

View File

@ -25,6 +25,7 @@ run_cmake(COMPILE_LANGUAGE-add_executable)
run_cmake(COMPILE_LANGUAGE-add_library) run_cmake(COMPILE_LANGUAGE-add_library)
run_cmake(COMPILE_LANGUAGE-add_test) run_cmake(COMPILE_LANGUAGE-add_test)
run_cmake(COMPILE_LANGUAGE-unknown-lang) run_cmake(COMPILE_LANGUAGE-unknown-lang)
run_cmake(TARGET_FILE-recursion)
run_cmake(ImportedTarget-TARGET_PDB_FILE) run_cmake(ImportedTarget-TARGET_PDB_FILE)
if(LINKER_SUPPORTS_PDB) if(LINKER_SUPPORTS_PDB)

View File

@ -0,0 +1,4 @@
CMake Error at TARGET_FILE-recursion.cmake:[0-9]+ \(add_executable\):
Target 'empty1' OUTPUT_DIRECTORY depends on itself.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -0,0 +1,3 @@
enable_language(C)
add_executable(empty1 empty.c)
set_property(TARGET empty1 PROPERTY RUNTIME_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:empty1>)