Browse Source

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.
Robert Goulet 10 years ago
parent
commit
d25819bc26

+ 3 - 0
Help/prop_tgt/ARCHIVE_OUTPUT_DIRECTORY_CONFIG.rst

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

+ 3 - 0
Help/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG.rst

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

+ 3 - 0
Help/prop_tgt/RUNTIME_OUTPUT_DIRECTORY_CONFIG.rst

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

+ 5 - 2
Help/prop_tgt/XXX_OUTPUT_DIRECTORY.txt

@@ -1,8 +1,11 @@
 Output directory in which to build |XXX| target files.
 
 This property specifies the directory into which |xxx| target files
-should be built.  Multi-configuration generators (VS, Xcode) append a
-per-configuration subdirectory to the specified directory.
+should be built.  The property value may use
+: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
 |CMAKE_XXX_OUTPUT_DIRECTORY| if it is set when a target is created.

+ 7 - 0
Help/release/dev/OUTPUT_DIRECTORY-genex.rst

@@ -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)>`.

+ 15 - 2
Source/cmTarget.cxx

@@ -3520,7 +3520,10 @@ bool cmTarget::ComputeOutputDir(const std::string& config,
   if(const char* config_outdir = this->GetProperty(configProp))
     {
     // 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.
     conf = "";
@@ -3528,7 +3531,17 @@ bool cmTarget::ComputeOutputDir(const std::string& config,
   else if(const char* outdir = this->GetProperty(propertyName))
     {
     // 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)
     {

+ 15 - 2
Tests/ExportImport/Export/CMakeLists.txt

@@ -105,6 +105,19 @@ target_link_libraries(testLib4
 add_executable(testExe3 testExe3.c)
 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.
 add_library(testLibCycleA STATIC
   testLibCycleA1.c testLibCycleA2.c testLibCycleA3.c)
@@ -450,7 +463,7 @@ install(FILES
 # Install and export from install tree.
 install(
   TARGETS
-  testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3
+  testExe1 testLib1 testLib2 testExe2 testLib3 testLib4 testExe3 testExe4
   testExe2lib testLib4lib testLib4libdbg testLib4libopt
   testLib6 testLib7
   testLibCycleA testLibCycleB
@@ -511,7 +524,7 @@ export(TARGETS testExe1 testLib1 testLib2 testLib3
   NAMESPACE bld_
   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
   testLibCycleA testLibCycleB
   testLibPerConfigDest

+ 24 - 0
Tests/ExportImport/Export/testExe4.c

@@ -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;
+}

+ 12 - 0
Tests/ExportImport/Import/A/CMakeLists.txt

@@ -19,11 +19,17 @@ add_custom_command(
   COMMAND exp_testExe3 ${Import_BINARY_DIR}/exp_generated3.c
   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
   imp_testExe1.c
   ${Import_BINARY_DIR}/exp_generated.c
   ${Import_BINARY_DIR}/exp_generated3.c
+  ${Import_BINARY_DIR}/exp_generated4.c
   )
 
 # 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
   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
   imp_testExe1.c
   ${Import_BINARY_DIR}/bld_generated.c
   ${Import_BINARY_DIR}/bld_generated3.c
+  ${Import_BINARY_DIR}/bld_generated4.c
   )
 
 # Try linking to a library imported from the build tree.

+ 2 - 1
Tests/ExportImport/Import/A/imp_testExe1.c

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

+ 1 - 0
Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake

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

+ 1 - 0
Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion-stderr.txt

@@ -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\)

+ 3 - 0
Tests/RunCMake/GeneratorExpression/TARGET_FILE-recursion.cmake

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