Quellcode durchsuchen

Merge topic 'QtAutogen_Contain'

c8a4147a QtAutogen: Release notes for the Contain branch
e1f571a9 QtAutogen: CMake-Qt documentation update
e324d704 QtAutogen: AUTOMOC documentation update
c2211703 QtAutogen: Tests: Don't use std::auto_ptr
2da0875f QtAutogen: Tests: Update ui_ include lookup directory
5961db41 QtAutogen: Tests: Increase minimum required CMake version
6d0a8af3 QtAutogen: Tests: Don't use std::auto_ptr
67310252 QtAutogen: Tests: Don't include CMAKE_CURRENT_BINARY_DIR
43d77e1d QtAutogen: Don't use std::i/ofstream::is_open()
98665c35 QtAutogen: Rename and sort variables
df74f3ff QtAutogen: Generate rcc output file names in one place only
bafbeaf1 QtAutogen: Add rcc output files to autogen target byproducts
8f437f3c QtAutogen: Add moc compilation file to autogen target byproducts
360c3427 QtAutogen: Reconfigure when .qrc file changes
b5409d04 QtAutogen: Rename autogen target to *_autogen from *_automoc
d9996aab QtAutogen: Inline single use variable definitions
...
Brad King vor 9 Jahren
Ursprung
Commit
0478314e13

+ 14 - 9
Help/manual/cmake-qt.7.rst

@@ -22,12 +22,11 @@ Qt 4 and Qt 5 may be used together in the same
 
 .. code-block:: cmake
 
-  cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
+  cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR)
 
   project(Qt4And5)
 
   set(CMAKE_AUTOMOC ON)
-  set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
   find_package(Qt5 COMPONENTS Widgets DBus REQUIRED)
   add_executable(publisher publisher.cpp)
@@ -73,9 +72,12 @@ The ``moc`` command line will consume the :prop_tgt:`COMPILE_DEFINITIONS` and
 :prop_tgt:`INCLUDE_DIRECTORIES` target properties from the target it is being
 invoked for, and for the appropriate build configuration.
 
-Generated ``moc_*.cpp`` and ``*.moc`` files are placed in the build directory
-so it is convenient to set the :variable:`CMAKE_INCLUDE_CURRENT_DIR`
-variable.  The :prop_tgt:`AUTOMOC` target property may be pre-set for all
+The generated ``moc_*.cpp`` and ``*.moc`` files are placed in the
+``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/include`` directory which is
+automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`.
+(This differs from CMake 3.7 and below; see their documentation for details.)
+
+The :prop_tgt:`AUTOMOC` target property may be pre-set for all
 following targets by setting the :variable:`CMAKE_AUTOMOC` variable.  The
 :prop_tgt:`AUTOMOC_MOC_OPTIONS` target property may be populated to set
 options to pass to ``moc``. The :variable:`CMAKE_AUTOMOC_MOC_OPTIONS`
@@ -94,10 +96,13 @@ If a preprocessor ``#include`` directive is found which matches
 ``ui_<basename>.h``, and a ``<basename>.ui`` file exists, then ``uic`` will
 be executed to generate the appropriate file.
 
-Generated ``ui_*.h`` files are placed in the build directory so it is
-convenient to set the :variable:`CMAKE_INCLUDE_CURRENT_DIR` variable.  The
-:prop_tgt:`AUTOUIC` target property may be pre-set for all following targets
-by setting the :variable:`CMAKE_AUTOUIC` variable.  The
+The generated generated ``ui_*.h`` files are placed in the
+``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/include`` directory which is
+automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`.
+(This differs from CMake 3.7 and below; see their documentation for details.)
+
+The :prop_tgt:`AUTOUIC` target property may be pre-set for all following
+targets by setting the :variable:`CMAKE_AUTOUIC` variable.  The
 :prop_tgt:`AUTOUIC_OPTIONS` target property may be populated to set options
 to pass to ``uic``.  The :variable:`CMAKE_AUTOUIC_OPTIONS` variable may be
 populated to pre-set the options for all following targets.  The

+ 1 - 1
Help/prop_gbl/AUTOGEN_TARGETS_FOLDER.rst

@@ -1,7 +1,7 @@
 AUTOGEN_TARGETS_FOLDER
 ----------------------
 
-Name of :prop_tgt:`FOLDER` for ``*_automoc`` targets that are added automatically by
+Name of :prop_tgt:`FOLDER` for ``*_autogen`` targets that are added automatically by
 CMake for targets for which :prop_tgt:`AUTOMOC` is enabled.
 
 If not set, CMake uses the :prop_tgt:`FOLDER` property of the parent target as a

+ 1 - 1
Help/prop_gbl/AUTOMOC_TARGETS_FOLDER.rst

@@ -1,7 +1,7 @@
 AUTOMOC_TARGETS_FOLDER
 ----------------------
 
-Name of :prop_tgt:`FOLDER` for ``*_automoc`` targets that are added automatically by
+Name of :prop_tgt:`FOLDER` for ``*_autogen`` targets that are added automatically by
 CMake for targets for which :prop_tgt:`AUTOMOC` is enabled.
 
 This property is obsolete.  Use :prop_gbl:`AUTOGEN_TARGETS_FOLDER` instead.

+ 4 - 4
Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst

@@ -1,16 +1,16 @@
 AUTOGEN_TARGET_DEPENDS
 ----------------------
 
-Target dependencies of the corresponding ``_automoc`` target.
+Target dependencies of the corresponding ``_autogen`` target.
 
 Targets which have their :prop_tgt:`AUTOMOC` target ``ON`` have a
-corresponding ``_automoc`` target which is used to autogenerate generate moc
-files.  As this ``_automoc`` target is created at generate-time, it is not
+corresponding ``_autogen`` target which is used to autogenerate generate moc
+files.  As this ``_autogen`` target is created at generate-time, it is not
 possible to define dependencies of it, such as to create inputs for the ``moc``
 executable.
 
 The ``AUTOGEN_TARGET_DEPENDS`` target property can be set instead to a list of
-dependencies for the ``_automoc`` target.  The buildsystem will be generated to
+dependencies for the ``_autogen`` target.  The buildsystem will be generated to
 depend on its contents.
 
 See the :manual:`cmake-qt(7)` manual for more information on using CMake

+ 7 - 6
Help/prop_tgt/AUTOMOC.rst

@@ -15,11 +15,12 @@ source files at build time and invoke moc accordingly.
   the ``Q_OBJECT`` class declaration is expected in the header, and
   ``moc`` is run on the header file.  A ``moc_foo.cpp`` file will be
   generated from the source's header into the
-  :variable:`CMAKE_CURRENT_BINARY_DIR` directory.  This allows the
-  compiler to find the included ``moc_foo.cpp`` file regardless of the
-  location the original source.  However, if multiple source files
-  in different directories do this then their generated moc files would
-  collide.  In this case a diagnostic will be issued.
+  ``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/include``
+  directory which is automatically added to the target's
+  :prop_tgt:`INCLUDE_DIRECTORIES`.  This allows the compiler to find the
+  included ``moc_foo.cpp`` file regardless of the location the original source.
+  However, if multiple source files in different directories do this then their
+  generated moc files would collide.  In this case a diagnostic will be issued.
 
 * If an ``#include`` statement like ``#include "foo.moc"`` is found,
   then a ``Q_OBJECT`` is expected in the current source file and ``moc``
@@ -30,7 +31,7 @@ source files at build time and invoke moc accordingly.
   alternative extensions, such as ``hpp``, ``hxx`` etc when searching
   for headers.  The resulting moc files, which are not included as shown
   above in any of the source files are included in a generated
-  ``<targetname>_automoc.cpp`` file, which is compiled as part of the
+  ``moc_compilation.cpp`` file, which is compiled as part of the
   target.
 
 This property is initialized by the value of the :variable:`CMAKE_AUTOMOC`

+ 10 - 0
Help/release/dev/QtAutogen_Contain.rst

@@ -0,0 +1,10 @@
+QtAutogen_Contain
+-----------------
+
+* When using AUTOMOC or AUTOUIC, generated
+  ``moc_*``, ``*.moc`` and ``ui_*`` are placed in the
+  ``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/include`` directory which
+  is automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`.
+  It is therefore not necessary anymore to have
+  :variable:`CMAKE_CURRENT_BINARY_DIR` in the target's
+  :prop_tgt:`INCLUDE_DIRECTORIES`.

+ 5 - 5
Modules/AutogenInfo.cmake.in

@@ -1,12 +1,11 @@
 set(AM_SOURCES @_cpp_files@ )
-set(AM_RCC_SOURCES @_rcc_files@ )
-set(AM_RCC_INPUTS @_qt_rcc_inputs@)
 set(AM_SKIP_MOC @_skip_moc@ )
 set(AM_SKIP_UIC @_skip_uic@ )
 set(AM_HEADERS @_moc_headers@ )
 set(AM_MOC_COMPILE_DEFINITIONS @_moc_compile_defs@)
 set(AM_MOC_INCLUDES @_moc_incs@)
 set(AM_MOC_OPTIONS @_moc_options@)
+set(AM_MOC_RELAXED_MODE "@_moc_relaxed_mode@")
 set(AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE "@CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE@")
 set(AM_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@/")
 set(AM_CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@/")
@@ -18,9 +17,10 @@ set(AM_CMAKE_CURRENT_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@/")
 set(AM_QT_VERSION_MAJOR "@_target_qt_version@")
 set(AM_TARGET_NAME @_moc_target_name@)
 set(AM_ORIGIN_TARGET_NAME @_origin_target_name@)
-set(AM_RELAXED_MODE "@_moc_relaxed_mode@")
 set(AM_UIC_TARGET_OPTIONS @_uic_target_options@)
 set(AM_UIC_OPTIONS_FILES @_qt_uic_options_files@)
 set(AM_UIC_OPTIONS_OPTIONS @_qt_uic_options_options@)
-set(AM_RCC_OPTIONS_FILES @_qt_rcc_options_files@)
-set(AM_RCC_OPTIONS_OPTIONS @_qt_rcc_options_options@)
+set(AM_RCC_SOURCES @_rcc_files@ )
+set(AM_RCC_INPUTS @_rcc_inputs@)
+set(AM_RCC_OPTIONS_FILES @_rcc_options_files@)
+set(AM_RCC_OPTIONS_OPTIONS @_rcc_options_options@)

+ 2 - 2
Source/CMakeLists.txt

@@ -243,8 +243,8 @@ set(SRCS
   cmFileLockPool.h
   cmFileLockResult.cxx
   cmFileLockResult.h
-  cmFilePathUuid.cxx
-  cmFilePathUuid.h
+  cmFilePathChecksum.cxx
+  cmFilePathChecksum.h
   cmFileTimeComparison.cxx
   cmFileTimeComparison.h
   cmFortranLexer.cxx

+ 88 - 0
Source/cmFilePathChecksum.cxx

@@ -0,0 +1,88 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmFilePathChecksum.h"
+
+#include "cmBase32.h"
+#include "cmCryptoHash.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+#include <vector>
+
+cmFilePathChecksum::cmFilePathChecksum()
+{
+}
+
+cmFilePathChecksum::cmFilePathChecksum(const std::string& currentSrcDir,
+                                       const std::string& currentBinDir,
+                                       const std::string& projectSrcDir,
+                                       const std::string& projectBinDir)
+{
+  setupParentDirs(currentSrcDir, currentBinDir, projectSrcDir, projectBinDir);
+}
+
+cmFilePathChecksum::cmFilePathChecksum(cmMakefile* makefile)
+{
+  setupParentDirs(makefile->GetCurrentSourceDirectory(),
+                  makefile->GetCurrentBinaryDirectory(),
+                  makefile->GetHomeDirectory(),
+                  makefile->GetHomeOutputDirectory());
+}
+
+void cmFilePathChecksum::setupParentDirs(const std::string& currentSrcDir,
+                                         const std::string& currentBinDir,
+                                         const std::string& projectSrcDir,
+                                         const std::string& projectBinDir)
+{
+  parentDirs[0].first = cmsys::SystemTools::GetRealPath(currentSrcDir);
+  parentDirs[1].first = cmsys::SystemTools::GetRealPath(currentBinDir);
+  parentDirs[2].first = cmsys::SystemTools::GetRealPath(projectSrcDir);
+  parentDirs[3].first = cmsys::SystemTools::GetRealPath(projectBinDir);
+
+  parentDirs[0].second = "CurrentSource";
+  parentDirs[1].second = "CurrentBinary";
+  parentDirs[2].second = "ProjectSource";
+  parentDirs[3].second = "ProjectBinary";
+}
+
+std::string cmFilePathChecksum::get(const std::string& filePath)
+{
+  std::string relPath;
+  std::string relSeed;
+  {
+    const std::string fileReal = cmsys::SystemTools::GetRealPath(filePath);
+    std::string parentDir;
+    // Find closest project parent directory
+    for (size_t ii = 0; ii != numParentDirs; ++ii) {
+      const std::string& pDir = parentDirs[ii].first;
+      if (!pDir.empty() &&
+          cmsys::SystemTools::IsSubDirectory(fileReal, pDir)) {
+        relSeed = parentDirs[ii].second;
+        parentDir = pDir;
+        break;
+      }
+    }
+    // Use file system root as fallback parent directory
+    if (parentDir.empty()) {
+      relSeed = "FileSystemRoot";
+      cmsys::SystemTools::SplitPathRootComponent(fileReal, &parentDir);
+    }
+    // Calculate relative path from project parent directory
+    relPath = cmsys::SystemTools::RelativePath(
+      parentDir, cmsys::SystemTools::GetParentDirectory(fileReal));
+  }
+
+  // Calculate the file ( seed + relative path ) binary checksum
+  std::vector<unsigned char> hashBytes =
+    cmCryptoHash(cmCryptoHash::AlgoSHA256).ByteHashString(relSeed + relPath);
+
+  // Convert binary checksum to string
+  return cmBase32Encoder().encodeString(&hashBytes[0], hashBytes.size(),
+                                        false);
+}
+
+std::string cmFilePathChecksum::getPart(const std::string& filePath,
+                                        size_t length)
+{
+  return get(filePath).substr(0, length);
+}

+ 65 - 0
Source/cmFilePathChecksum.h

@@ -0,0 +1,65 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmFilePathChecksum_h
+#define cmFilePathChecksum_h
+
+#include <cmConfigure.h> // IWYU pragma: keep
+
+#include <stddef.h>
+#include <string>
+#include <utility>
+
+class cmMakefile;
+
+/** \class cmFilePathChecksum
+ * @brief Generates a checksum for the parent directory of a file
+ *
+ * The checksum is calculated from the relative file path to the
+ * closest known project directory. This guarantees reproducibility
+ * when source and build directory differ e.g. for different project
+ * build directories.
+ */
+class cmFilePathChecksum
+{
+public:
+  /// Maximum number of characters to use from the path checksum
+  static const size_t partLengthDefault = 10;
+
+  /// @brief Parent directories are empty
+  cmFilePathChecksum();
+
+  /// @brief Initilizes the parent directories manually
+  cmFilePathChecksum(const std::string& currentSrcDir,
+                     const std::string& currentBinDir,
+                     const std::string& projectSrcDir,
+                     const std::string& projectBinDir);
+
+  /// @brief Initilizes the parent directories from a makefile
+  cmFilePathChecksum(cmMakefile* makefile);
+
+  /// @brief Allows parent directories setup after construction
+  ///
+  void setupParentDirs(const std::string& currentSrcDir,
+                       const std::string& currentBinDir,
+                       const std::string& projectSrcDir,
+                       const std::string& projectBinDir);
+
+  /* @brief Calculates the path checksum for the parent directory of a file
+   *
+   */
+  std::string get(const std::string& filePath);
+
+  /* @brief Same as get() but returns only the first length characters
+   *
+   */
+  std::string getPart(const std::string& filePath,
+                      size_t length = partLengthDefault);
+
+private:
+  /// Size of the parent directory list
+  static const size_t numParentDirs = 4;
+  /// List of (directory name, seed name) pairs
+  std::pair<std::string, std::string> parentDirs[numParentDirs];
+};
+
+#endif

+ 0 - 118
Source/cmFilePathUuid.cxx

@@ -1,118 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#include "cmFilePathUuid.h"
-
-#include "cmBase32.h"
-#include "cmCryptoHash.h"
-#include "cmMakefile.h"
-#include "cmSystemTools.h"
-
-#include <vector>
-
-cmFilePathUuid::cmFilePathUuid(cmMakefile* makefile)
-{
-  initParentDirs(makefile->GetCurrentSourceDirectory(),
-                 makefile->GetCurrentBinaryDirectory(),
-                 makefile->GetHomeDirectory(),
-                 makefile->GetHomeOutputDirectory());
-}
-
-cmFilePathUuid::cmFilePathUuid(const std::string& currentSrcDir,
-                               const std::string& currentBinDir,
-                               const std::string& projectSrcDir,
-                               const std::string& projectBinDir)
-{
-  initParentDirs(currentSrcDir, currentBinDir, projectSrcDir, projectBinDir);
-}
-
-void cmFilePathUuid::initParentDirs(const std::string& currentSrcDir,
-                                    const std::string& currentBinDir,
-                                    const std::string& projectSrcDir,
-                                    const std::string& projectBinDir)
-{
-  parentDirs[0].first = cmsys::SystemTools::GetRealPath(currentSrcDir);
-  parentDirs[1].first = cmsys::SystemTools::GetRealPath(currentBinDir);
-  parentDirs[2].first = cmsys::SystemTools::GetRealPath(projectSrcDir);
-  parentDirs[3].first = cmsys::SystemTools::GetRealPath(projectBinDir);
-
-  parentDirs[0].second = "CurrentSource";
-  parentDirs[1].second = "CurrentBinary";
-  parentDirs[2].second = "ProjectSource";
-  parentDirs[3].second = "ProjectBinary";
-}
-
-std::string cmFilePathUuid::get(const std::string& filePath,
-                                const char* outputPrefix,
-                                const char* outputSuffix)
-{
-  std::string sourceFilename = cmsys::SystemTools::GetFilenameName(filePath);
-  std::string sourceBasename =
-    cmsys::SystemTools::GetFilenameWithoutLastExtension(sourceFilename);
-
-  // Acquire checksum string
-  std::string checksum;
-  {
-    std::string sourceRelPath;
-    std::string sourceRelSeed;
-    GetRelPathSeed(filePath, sourceRelPath, sourceRelSeed);
-    checksum = GetChecksumString(sourceFilename, sourceRelPath, sourceRelSeed);
-  }
-
-  // Compose the file name
-  std::string uuid;
-  if (outputPrefix) {
-    uuid += outputPrefix;
-  }
-  uuid += sourceBasename.substr(0, partLengthName);
-  uuid += "_";
-  uuid += checksum.substr(0, partLengthCheckSum);
-  if (outputSuffix) {
-    uuid += outputSuffix;
-  }
-  return uuid;
-}
-
-void cmFilePathUuid::GetRelPathSeed(const std::string& filePath,
-                                    std::string& sourceRelPath,
-                                    std::string& sourceRelSeed)
-{
-  const std::string sourceNameReal = cmsys::SystemTools::GetRealPath(filePath);
-  std::string parentDirectory;
-  // Find closest project parent directory
-  for (size_t ii = 0; ii != numParentDirs; ++ii) {
-    const std::string& pDir = parentDirs[ii].first;
-    if (!pDir.empty() &&
-        cmsys::SystemTools::IsSubDirectory(sourceNameReal, pDir)) {
-      sourceRelSeed = parentDirs[ii].second;
-      parentDirectory = pDir;
-      break;
-    }
-  }
-  // Check if the file path is below a known project directory
-  if (parentDirectory.empty()) {
-    // Use file syste root as fallback parent directory
-    sourceRelSeed = "FileSystemRoot";
-    cmsys::SystemTools::SplitPathRootComponent(sourceNameReal,
-                                               &parentDirectory);
-  }
-  sourceRelPath = cmsys::SystemTools::RelativePath(
-    parentDirectory, cmsys::SystemTools::GetParentDirectory(sourceNameReal));
-}
-
-std::string cmFilePathUuid::GetChecksumString(
-  const std::string& sourceFilename, const std::string& sourceRelPath,
-  const std::string& sourceRelSeed)
-{
-  std::string checksumBase32;
-  {
-    // Calculate the file ( seed + relative path + name ) checksum
-    std::vector<unsigned char> hashBytes =
-      cmCryptoHash(cmCryptoHash::AlgoSHA256)
-        .ByteHashString(sourceRelSeed + sourceRelPath + sourceFilename);
-
-    checksumBase32 =
-      cmBase32Encoder().encodeString(&hashBytes[0], hashBytes.size(), false);
-  }
-
-  return checksumBase32;
-}

+ 0 - 69
Source/cmFilePathUuid.h

@@ -1,69 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
-   file Copyright.txt or https://cmake.org/licensing for details.  */
-#ifndef cmFilePathUuid_h
-#define cmFilePathUuid_h
-
-#include <cmConfigure.h> // IWYU pragma: keep
-
-#include <stddef.h>
-#include <string>
-#include <utility>
-
-class cmMakefile;
-
-/** \class cmFilePathUuid
- * @brief Generates a unique pathless file name with a checksum component
- *        calculated from the file path.
- *
- * The checksum is calculated from the relative file path to the
- * closest known project directory. This guarantees reproducibility
- * when source and build directory differ e.g. for different project
- * build directories.
- */
-class cmFilePathUuid
-{
-public:
-  /// Maximum number of characters to use from the file name
-  static const size_t partLengthName = 14;
-  /// Maximum number of characters to use from the path checksum
-  static const size_t partLengthCheckSum = 14;
-
-  /// @brief Initilizes the parent directories from a makefile
-  cmFilePathUuid(cmMakefile* makefile);
-
-  /// @brief Initilizes the parent directories manually
-  cmFilePathUuid(const std::string& currentSrcDir,
-                 const std::string& currentBinDir,
-                 const std::string& projectSrcDir,
-                 const std::string& projectBinDir);
-
-  /* @brief Calculates and returns the uuid for a file path
-   *
-   * @arg outputPrefix optional string to prepend to the result
-   * @arg outputSuffix optional string to append to the result
-   */
-  std::string get(const std::string& filePath,
-                  const char* outputPrefix = CM_NULLPTR,
-                  const char* outputSuffix = CM_NULLPTR);
-
-private:
-  void initParentDirs(const std::string& currentSrcDir,
-                      const std::string& currentBinDir,
-                      const std::string& projectSrcDir,
-                      const std::string& projectBinDir);
-
-  /// Returns the relative path and the parent directory key string (seed)
-  void GetRelPathSeed(const std::string& filePath, std::string& sourceRelPath,
-                      std::string& sourceRelSeed);
-
-  std::string GetChecksumString(const std::string& sourceFilename,
-                                const std::string& sourceRelPath,
-                                const std::string& sourceRelSeed);
-
-  /// Size of the parent directory list
-  static const size_t numParentDirs = 4;
-  /// List of (directory name, seed name) pairs
-  std::pair<std::string, std::string> parentDirs[numParentDirs];
-};
-
-#endif

+ 15 - 0
Source/cmGeneratorTarget.cxx

@@ -533,6 +533,21 @@ void cmGeneratorTarget::AddTracedSources(std::vector<std::string> const& srcs)
   }
 }
 
+void cmGeneratorTarget::AddIncludeDirectory(const std::string& src,
+                                            bool before)
+{
+  this->Target->InsertInclude(src, this->Makefile->GetBacktrace(), before);
+  cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+  cmGeneratorExpression ge(lfbt);
+  CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(src);
+  cge->SetEvaluateForBuildsystem(true);
+  // Insert before begin/end
+  std::vector<TargetPropertyEntry*>::iterator pos = before
+    ? this->IncludeDirectoriesEntries.begin()
+    : this->IncludeDirectoriesEntries.end();
+  this->IncludeDirectoriesEntries.insert(pos, new TargetPropertyEntry(cge));
+}
+
 std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends(
   cmSourceFile const* sf) const
 {

+ 6 - 0
Source/cmGeneratorTarget.h

@@ -395,6 +395,12 @@ public:
   void AddSource(const std::string& src);
   void AddTracedSources(std::vector<std::string> const& srcs);
 
+  /**
+   * Adds an entry to the INCLUDE_DIRECTORIES list.
+   * If before is true the entry is pushed at the front.
+   */
+  void AddIncludeDirectory(const std::string& src, bool before = false);
+
   /**
    * Flags for a given source file as used in this target. Typically assigned
    * via SET_TARGET_PROPERTIES when the property is a list of source files.

+ 212 - 229
Source/cmQtAutoGeneratorInitializer.cxx

@@ -4,7 +4,7 @@
 
 #include "cmAlgorithms.h"
 #include "cmCustomCommandLines.h"
-#include "cmFilePathUuid.h"
+#include "cmFilePathChecksum.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
 #include "cmLocalGenerator.h"
@@ -35,14 +35,34 @@
 #include <utility>
 #include <vector>
 
+static void utilCopyTargetProperty(cmTarget* destinationTarget,
+                                   cmTarget* sourceTarget,
+                                   const std::string& propertyName)
+{
+  const char* propertyValue = sourceTarget->GetProperty(propertyName);
+  if (propertyValue) {
+    destinationTarget->SetProperty(propertyName, propertyValue);
+  }
+}
+
+static std::string utilStripCR(std::string const& line)
+{
+  // Strip CR characters rcc may have printed (possibly more than one!).
+  std::string::size_type cr = line.find('\r');
+  if (cr != line.npos) {
+    return line.substr(0, cr);
+  }
+  return line;
+}
+
 static std::string GetAutogenTargetName(cmGeneratorTarget const* target)
 {
   std::string autogenTargetName = target->GetName();
-  autogenTargetName += "_automoc";
+  autogenTargetName += "_autogen";
   return autogenTargetName;
 }
 
-static std::string GetAutogenTargetDir(cmGeneratorTarget const* target)
+static std::string GetAutogenTargetFilesDir(cmGeneratorTarget const* target)
 {
   cmMakefile* makefile = target->Target->GetMakefile();
   std::string targetDir = makefile->GetCurrentBinaryDirectory();
@@ -59,10 +79,25 @@ static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target)
   std::string targetDir = makefile->GetCurrentBinaryDirectory();
   targetDir += "/";
   targetDir += GetAutogenTargetName(target);
-  targetDir += ".dir/";
+  targetDir += "/";
   return targetDir;
 }
 
+static std::string GetQtMajorVersion(cmGeneratorTarget const* target)
+{
+  cmMakefile* makefile = target->Target->GetMakefile();
+  std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR");
+  if (qtMajorVersion.empty()) {
+    qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR");
+  }
+  const char* targetQtVersion =
+    target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", "");
+  if (targetQtVersion != CM_NULLPTR) {
+    qtMajorVersion = targetQtVersion;
+  }
+  return qtMajorVersion;
+}
+
 static void SetupSourceFiles(cmGeneratorTarget const* target,
                              std::vector<std::string>& skipMoc,
                              std::vector<std::string>& mocSources,
@@ -74,41 +109,20 @@ static void SetupSourceFiles(cmGeneratorTarget const* target,
   std::vector<cmSourceFile*> srcFiles;
   target->GetConfigCommonSourceFiles(srcFiles);
 
-  std::vector<std::string> newRccFiles;
-
-  cmFilePathUuid fpathUuid(makefile);
+  cmFilePathChecksum fpathCheckSum(makefile);
   for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
        fileIt != srcFiles.end(); ++fileIt) {
     cmSourceFile* sf = *fileIt;
-    std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath());
-    bool skipFileForMoc =
-      cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC"));
-    bool generated = cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"));
+    const std::string absFile =
+      cmsys::SystemTools::GetRealPath(sf->GetFullPath());
+    const std::string ext = sf->GetExtension();
 
     if (cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOUIC"))) {
       skipUic.push_back(absFile);
     }
 
-    std::string ext = sf->GetExtension();
-
-    if (target->GetPropertyAsBool("AUTORCC")) {
-      if (ext == "qrc" &&
-          !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) {
-
-        std::string rcc_output_file = GetAutogenTargetBuildDir(target);
-        // Create output directory
-        cmSystemTools::MakeDirectory(rcc_output_file.c_str());
-        rcc_output_file += fpathUuid.get(absFile, "qrc_", ".cpp");
-
-        makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
-                                 rcc_output_file.c_str(), false);
-        makefile->GetOrCreateSource(rcc_output_file, true);
-        newRccFiles.push_back(rcc_output_file);
-      }
-    }
-
-    if (!generated) {
-      if (skipFileForMoc) {
+    if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) {
+      if (cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC"))) {
         skipMoc.push_back(absFile);
       } else {
         cmSystemTools::FileFormat fileType =
@@ -121,11 +135,6 @@ static void SetupSourceFiles(cmGeneratorTarget const* target,
       }
     }
   }
-
-  for (std::vector<std::string>::const_iterator fileIt = newRccFiles.begin();
-       fileIt != newRccFiles.end(); ++fileIt) {
-    const_cast<cmGeneratorTarget*>(target)->AddSource(*fileIt);
-  }
 }
 
 static void GetCompileDefinitionsAndDirectories(
@@ -146,7 +155,7 @@ static void GetCompileDefinitionsAndDirectories(
   defs += cmJoin(defines, ";");
 }
 
-static void SetupAutoMocTarget(
+static void MocSetupAutoTarget(
   cmGeneratorTarget const* target, const std::string& autogenTargetName,
   std::vector<std::string> const& skipMoc,
   std::vector<std::string> const& mocHeaders,
@@ -229,7 +238,7 @@ static void SetupAutoMocTarget(
   }
 }
 
-static void GetUicOpts(cmGeneratorTarget const* target,
+static void UicGetOpts(cmGeneratorTarget const* target,
                        const std::string& config, std::string& optString)
 {
   std::vector<std::string> opts;
@@ -237,7 +246,7 @@ static void GetUicOpts(cmGeneratorTarget const* target,
   optString = cmJoin(opts, ";");
 }
 
-static void SetupAutoUicTarget(
+static void UicSetupAutoTarget(
   cmGeneratorTarget const* target, std::vector<std::string> const& skipUic,
   std::map<std::string, std::string>& configUicOptions)
 {
@@ -259,7 +268,7 @@ static void SetupAutoUicTarget(
   std::string _uic_opts;
   std::vector<std::string> configs;
   const std::string& config = makefile->GetConfigurations(configs);
-  GetUicOpts(target, config, _uic_opts);
+  UicGetOpts(target, config, _uic_opts);
 
   if (!_uic_opts.empty()) {
     _uic_opts = cmOutputConverter::EscapeForCMake(_uic_opts);
@@ -268,7 +277,7 @@ static void SetupAutoUicTarget(
   for (std::vector<std::string>::const_iterator li = configs.begin();
        li != configs.end(); ++li) {
     std::string config_uic_opts;
-    GetUicOpts(target, *li, config_uic_opts);
+    UicGetOpts(target, *li, config_uic_opts);
     if (config_uic_opts != _uic_opts) {
       configUicOptions[*li] =
         cmOutputConverter::EscapeForCMake(config_uic_opts);
@@ -331,25 +340,13 @@ static void SetupAutoUicTarget(
   }
 }
 
-static std::string GetRccExecutable(cmGeneratorTarget const* target)
+static std::string RccGetExecutable(cmGeneratorTarget const* target,
+                                    const std::string& qtMajorVersion)
 {
   cmLocalGenerator* lg = target->GetLocalGenerator();
-  cmMakefile* makefile = target->Target->GetMakefile();
-  const char* qtVersion = makefile->GetDefinition("_target_qt_version");
-  if (!qtVersion) {
-    qtVersion = makefile->GetDefinition("Qt5Core_VERSION_MAJOR");
-    if (!qtVersion) {
-      qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR");
-    }
-    if (const char* targetQtVersion =
-          target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION",
-                                                          "")) {
-      qtVersion = targetQtVersion;
-    }
-  }
 
-  std::string targetName = target->GetName();
-  if (strcmp(qtVersion, "5") == 0) {
+  std::string const& targetName = target->GetName();
+  if (qtMajorVersion == "5") {
     cmGeneratorTarget* qt5Rcc = lg->FindGeneratorTargetToUse("Qt5::rcc");
     if (!qt5Rcc) {
       cmSystemTools::Error("Qt5::rcc target not found ", targetName.c_str());
@@ -357,7 +354,7 @@ static std::string GetRccExecutable(cmGeneratorTarget const* target)
     }
     return qt5Rcc->ImportedGetLocation("");
   }
-  if (strcmp(qtVersion, "4") == 0) {
+  if (qtMajorVersion == "4") {
     cmGeneratorTarget* qt4Rcc = lg->FindGeneratorTargetToUse("Qt4::rcc");
     if (!qt4Rcc) {
       cmSystemTools::Error("Qt4::rcc target not found ", targetName.c_str());
@@ -372,7 +369,7 @@ static std::string GetRccExecutable(cmGeneratorTarget const* target)
   return std::string();
 }
 
-static void MergeRccOptions(std::vector<std::string>& opts,
+static void RccMergeOptions(std::vector<std::string>& opts,
                             const std::vector<std::string>& fileOpts,
                             bool isQt5)
 {
@@ -404,41 +401,16 @@ static void MergeRccOptions(std::vector<std::string>& opts,
   opts.insert(opts.end(), extraOpts.begin(), extraOpts.end());
 }
 
-static void copyTargetProperty(cmTarget* destinationTarget,
-                               cmTarget* sourceTarget,
-                               const std::string& propertyName)
-{
-  const char* propertyValue = sourceTarget->GetProperty(propertyName);
-  if (propertyValue) {
-    destinationTarget->SetProperty(propertyName, propertyValue);
-  }
-}
-
-static std::string cmQtAutoGeneratorsStripCR(std::string const& line)
-{
-  // Strip CR characters rcc may have printed (possibly more than one!).
-  std::string::size_type cr = line.find('\r');
-  if (cr != line.npos) {
-    return line.substr(0, cr);
-  }
-  return line;
-}
-
-static std::string ReadAll(const std::string& filename)
-{
-  cmsys::ifstream file(filename.c_str());
-  std::ostringstream stream;
-  stream << file.rdbuf();
-  file.close();
-  return stream.str();
-}
-
 /// @brief Reads the resource files list from from a .qrc file - Qt5 version
 /// @return True if the .qrc file was successfully parsed
-static bool ListQt5RccInputs(cmSourceFile* sf, cmGeneratorTarget const* target,
+static bool RccListInputsQt5(cmSourceFile* sf, cmGeneratorTarget const* target,
                              std::vector<std::string>& depends)
 {
-  std::string rccCommand = GetRccExecutable(target);
+  const std::string rccCommand = RccGetExecutable(target, "5");
+  if (rccCommand.empty()) {
+    cmSystemTools::Error("AUTOGEN: error: rcc executable not available\n");
+    return false;
+  }
 
   bool hasDashDashList = false;
   // Read rcc features
@@ -486,7 +458,7 @@ static bool ListQt5RccInputs(cmSourceFile* sf, cmGeneratorTarget const* target,
     std::istringstream ostr(rccStdOut);
     std::string oline;
     while (std::getline(ostr, oline)) {
-      oline = cmQtAutoGeneratorsStripCR(oline);
+      oline = utilStripCR(oline);
       if (!oline.empty()) {
         depends.push_back(oline);
       }
@@ -497,7 +469,7 @@ static bool ListQt5RccInputs(cmSourceFile* sf, cmGeneratorTarget const* target,
     std::istringstream estr(rccStdErr);
     std::string eline;
     while (std::getline(estr, eline)) {
-      eline = cmQtAutoGeneratorsStripCR(eline);
+      eline = utilStripCR(eline);
       if (cmHasLiteralPrefix(eline, "RCC: Error in")) {
         static std::string searchString = "Cannot find file '";
 
@@ -521,10 +493,16 @@ static bool ListQt5RccInputs(cmSourceFile* sf, cmGeneratorTarget const* target,
 
 /// @brief Reads the resource files list from from a .qrc file - Qt4 version
 /// @return True if the .qrc file was successfully parsed
-static bool ListQt4RccInputs(cmSourceFile* sf,
+static bool RccListInputsQt4(cmSourceFile* sf,
                              std::vector<std::string>& depends)
 {
-  const std::string qrcContents = ReadAll(sf->GetFullPath());
+  // Read file into string
+  std::string qrcContents;
+  {
+    std::ostringstream stream;
+    stream << cmsys::ifstream(sf->GetFullPath().c_str()).rdbuf();
+    qrcContents = stream.str();
+  }
 
   cmsys::RegularExpression fileMatchRegex("(<file[^<]+)");
 
@@ -551,17 +529,18 @@ static bool ListQt4RccInputs(cmSourceFile* sf,
 
 /// @brief Reads the resource files list from from a .qrc file
 /// @return True if the rcc file was successfully parsed
-static bool ListQtRccInputs(const std::string& qtMajorVersion,
-                            cmSourceFile* sf, cmGeneratorTarget const* target,
-                            std::vector<std::string>& depends)
+static bool RccListInputs(const std::string& qtMajorVersion, cmSourceFile* sf,
+                          cmGeneratorTarget const* target,
+                          std::vector<std::string>& depends)
 {
   if (qtMajorVersion == "5") {
-    return ListQt5RccInputs(sf, target, depends);
+    return RccListInputsQt5(sf, target, depends);
   }
-  return ListQt4RccInputs(sf, depends);
+  return RccListInputsQt4(sf, depends);
 }
 
-static void SetupAutoRccTarget(cmGeneratorTarget const* target)
+static void RccSetupAutoTarget(cmGeneratorTarget const* target,
+                               const std::string& qtMajorVersion)
 {
   std::string _rcc_files;
   const char* sepRccFiles = "";
@@ -577,16 +556,12 @@ static void SetupAutoRccTarget(cmGeneratorTarget const* target)
   std::string rccFileOptions;
   const char* optionSep = "";
 
-  const char* qtVersion = makefile->GetDefinition("_target_qt_version");
+  const bool qtMajorVersion5 = (qtMajorVersion == "5");
 
   std::vector<std::string> rccOptions;
   if (const char* opts = target->GetProperty("AUTORCC_OPTIONS")) {
     cmSystemTools::ExpandListArgument(opts, rccOptions);
   }
-  std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR");
-  if (qtMajorVersion == "") {
-    qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR");
-  }
 
   for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
        fileIt != srcFiles.end(); ++fileIt) {
@@ -604,7 +579,7 @@ static void SetupAutoRccTarget(cmGeneratorTarget const* target)
         if (const char* prop = sf->GetProperty("AUTORCC_OPTIONS")) {
           std::vector<std::string> optsVec;
           cmSystemTools::ExpandListArgument(prop, optsVec);
-          MergeRccOptions(rccOptions, optsVec, strcmp(qtVersion, "5") == 0);
+          RccMergeOptions(rccOptions, optsVec, qtMajorVersion5);
         }
 
         if (!rccOptions.empty()) {
@@ -624,7 +599,7 @@ static void SetupAutoRccTarget(cmGeneratorTarget const* target)
         std::string entriesList;
         if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) {
           std::vector<std::string> depends;
-          if (ListQtRccInputs(qtMajorVersion, sf, target, depends)) {
+          if (RccListInputs(qtMajorVersion, sf, target, depends)) {
             entriesList = cmJoin(depends, "@list_sep@");
           } else {
             return;
@@ -637,38 +612,27 @@ static void SetupAutoRccTarget(cmGeneratorTarget const* target)
     }
   }
   makefile->AddDefinition(
-    "_qt_rcc_inputs_" + target->GetName(),
-    cmOutputConverter::EscapeForCMake(qrcInputs).c_str());
-
+    "_rcc_inputs", cmOutputConverter::EscapeForCMake(qrcInputs).c_str());
   makefile->AddDefinition(
     "_rcc_files", cmOutputConverter::EscapeForCMake(_rcc_files).c_str());
-
   makefile->AddDefinition(
-    "_qt_rcc_options_files",
+    "_rcc_options_files",
     cmOutputConverter::EscapeForCMake(rccFileFiles).c_str());
   makefile->AddDefinition(
-    "_qt_rcc_options_options",
+    "_rcc_options_options",
     cmOutputConverter::EscapeForCMake(rccFileOptions).c_str());
-
   makefile->AddDefinition("_qt_rcc_executable",
-                          GetRccExecutable(target).c_str());
+                          RccGetExecutable(target, qtMajorVersion).c_str());
 }
 
 void cmQtAutoGeneratorInitializer::InitializeAutogenSources(
   cmGeneratorTarget* target)
 {
-  cmMakefile* makefile = target->Target->GetMakefile();
-
   if (target->GetPropertyAsBool("AUTOMOC")) {
-    std::string automocTargetName = GetAutogenTargetName(target);
-    std::string mocCppFile = makefile->GetCurrentBinaryDirectory();
-    mocCppFile += "/";
-    mocCppFile += automocTargetName;
-    mocCppFile += ".cpp";
+    cmMakefile* makefile = target->Target->GetMakefile();
+    const std::string mocCppFile =
+      GetAutogenTargetBuildDir(target) + "moc_compilation.cpp";
     makefile->GetOrCreateSource(mocCppFile, true);
-    makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", mocCppFile.c_str(),
-                             false);
-
     target->AddSource(mocCppFile);
   }
 }
@@ -678,56 +642,77 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
 {
   cmMakefile* makefile = target->Target->GetMakefile();
 
-  std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR");
-  if (qtMajorVersion == "") {
-    qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR");
-  }
-
-  // create a custom target for running generators at buildtime:
-  std::string autogenTargetName = GetAutogenTargetName(target);
-
-  std::string targetDir = GetAutogenTargetDir(target);
+  // Create a custom target for running generators at buildtime
+  const std::string autogenTargetName = GetAutogenTargetName(target);
+  const std::string autogenBuildDir = GetAutogenTargetBuildDir(target);
+  const std::string workingDirectory =
+    cmSystemTools::CollapseFullPath("", makefile->GetCurrentBinaryDirectory());
+  const std::string qtMajorVersion = GetQtMajorVersion(target);
+  std::vector<std::string> autogenOutputFiles;
 
-  cmCustomCommandLine currentLine;
-  currentLine.push_back(cmSystemTools::GetCMakeCommand());
-  currentLine.push_back("-E");
-  currentLine.push_back("cmake_autogen");
-  currentLine.push_back(targetDir);
-  currentLine.push_back("$<CONFIGURATION>");
+  // Create autogen target build directory and add it to the clean files
+  cmSystemTools::MakeDirectory(autogenBuildDir);
+  makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES",
+                           autogenBuildDir.c_str(), false);
 
-  cmCustomCommandLines commandLines;
-  commandLines.push_back(currentLine);
+  if (target->GetPropertyAsBool("AUTOMOC") ||
+      target->GetPropertyAsBool("AUTOUIC")) {
+    // Create autogen target includes directory and
+    // add it to the origin target INCLUDE_DIRECTORIES
+    const std::string incsDir = autogenBuildDir + "include";
+    cmSystemTools::MakeDirectory(incsDir);
+    target->AddIncludeDirectory(incsDir, true);
+  }
 
-  std::string workingDirectory =
-    cmSystemTools::CollapseFullPath("", makefile->GetCurrentBinaryDirectory());
+  if (target->GetPropertyAsBool("AUTOMOC")) {
+    // Register moc compilation file as generated
+    autogenOutputFiles.push_back(autogenBuildDir + "moc_compilation.cpp");
+  }
 
+  // Initialize autogen target dependencies
   std::vector<std::string> depends;
   if (const char* autogenDepends =
         target->GetProperty("AUTOGEN_TARGET_DEPENDS")) {
     cmSystemTools::ExpandListArgument(autogenDepends, depends);
   }
-  std::vector<std::string> toolNames;
-  if (target->GetPropertyAsBool("AUTOMOC")) {
-    toolNames.push_back("moc");
-  }
-  if (target->GetPropertyAsBool("AUTOUIC")) {
-    toolNames.push_back("uic");
-  }
-  if (target->GetPropertyAsBool("AUTORCC")) {
-    toolNames.push_back("rcc");
+
+  // Compose command lines
+  cmCustomCommandLines commandLines;
+  {
+    cmCustomCommandLine currentLine;
+    currentLine.push_back(cmSystemTools::GetCMakeCommand());
+    currentLine.push_back("-E");
+    currentLine.push_back("cmake_autogen");
+    currentLine.push_back(GetAutogenTargetFilesDir(target));
+    currentLine.push_back("$<CONFIGURATION>");
+    commandLines.push_back(currentLine);
   }
 
-  std::string tools = toolNames[0];
-  toolNames.erase(toolNames.begin());
-  while (toolNames.size() > 1) {
-    tools += ", " + toolNames[0];
+  // Compose target comment
+  std::string autogenComment;
+  {
+    std::vector<std::string> toolNames;
+    if (target->GetPropertyAsBool("AUTOMOC")) {
+      toolNames.push_back("MOC");
+    }
+    if (target->GetPropertyAsBool("AUTOUIC")) {
+      toolNames.push_back("UIC");
+    }
+    if (target->GetPropertyAsBool("AUTORCC")) {
+      toolNames.push_back("RCC");
+    }
+
+    std::string tools = toolNames[0];
     toolNames.erase(toolNames.begin());
+    while (toolNames.size() > 1) {
+      tools += ", " + toolNames[0];
+      toolNames.erase(toolNames.begin());
+    }
+    if (toolNames.size() == 1) {
+      tools += " and " + toolNames[0];
+    }
+    autogenComment = "Automatic " + tools + " for target " + target->GetName();
   }
-  if (toolNames.size() == 1) {
-    tools += " and " + toolNames[0];
-  }
-  std::string autogenComment = "Automatic " + tools + " for target ";
-  autogenComment += target->GetName();
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
   bool usePRE_BUILD = false;
@@ -741,6 +726,8 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
     //  https://connect.microsoft.com/VisualStudio/feedback/details/769495
     usePRE_BUILD = vsgg->GetVersion() >= cmGlobalVisualStudioGenerator::VS7;
     if (usePRE_BUILD) {
+      // If the autogen target depends on an other target
+      // don't use PRE_BUILD
       for (std::vector<std::string>::iterator it = depends.begin();
            it != depends.end(); ++it) {
         if (!makefile->FindTargetToUse(it->c_str())) {
@@ -752,35 +739,42 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
   }
 #endif
 
-  std::vector<std::string> rcc_output;
-  bool const isNinja = lg->GetGlobalGenerator()->GetName() == "Ninja";
-  if (isNinja
-#if defined(_WIN32) && !defined(__CYGWIN__)
-      || usePRE_BUILD
-#endif
-      ) {
+  if (target->GetPropertyAsBool("AUTORCC")) {
+    cmFilePathChecksum fpathCheckSum(makefile);
     std::vector<cmSourceFile*> srcFiles;
     target->GetConfigCommonSourceFiles(srcFiles);
-    cmFilePathUuid fpathUuid(makefile);
     for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin();
          fileIt != srcFiles.end(); ++fileIt) {
       cmSourceFile* sf = *fileIt;
-      std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath());
-
-      std::string ext = sf->GetExtension();
-
-      if (target->GetPropertyAsBool("AUTORCC")) {
-        if (ext == "qrc" &&
-            !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) {
-          {
-            std::string rcc_output_file = GetAutogenTargetBuildDir(target);
-            // Create output directory
-            cmSystemTools::MakeDirectory(rcc_output_file.c_str());
-            rcc_output_file += fpathUuid.get(absFile, "qrc_", ".cpp");
-            rcc_output.push_back(rcc_output_file);
-          }
+      if (sf->GetExtension() == "qrc" &&
+          !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) {
+        {
+          const std::string absFile =
+            cmsys::SystemTools::GetRealPath(sf->GetFullPath());
+
+          // Run cmake again when .qrc file changes
+          makefile->AddCMakeDependFile(absFile);
+
+          std::string rccOutputFile = autogenBuildDir;
+          rccOutputFile += fpathCheckSum.getPart(absFile);
+          rccOutputFile += "/qrc_";
+          rccOutputFile +=
+            cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile);
+          rccOutputFile += ".cpp";
+
+          // Add rcc output file to origin target sources
+          makefile->GetOrCreateSource(rccOutputFile, true);
+          target->AddSource(rccOutputFile);
+          // Register rcc output file as generated
+          autogenOutputFiles.push_back(rccOutputFile);
+        }
+        if (lg->GetGlobalGenerator()->GetName() == "Ninja"
+#if defined(_WIN32) && !defined(__CYGWIN__)
+            || usePRE_BUILD
+#endif
+            ) {
           if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) {
-            ListQtRccInputs(qtMajorVersion, sf, target, depends);
+            RccListInputs(qtMajorVersion, sf, target, depends);
 #if defined(_WIN32) && !defined(__CYGWIN__)
             // Cannot use PRE_BUILD because the resource files themselves
             // may not be sources within the target so VS may not know the
@@ -811,7 +805,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
   {
     cmTarget* autogenTarget = makefile->AddUtilityCommand(
       autogenTargetName, true, workingDirectory.c_str(),
-      /*byproducts=*/rcc_output, depends, commandLines, false,
+      /*byproducts=*/autogenOutputFiles, depends, commandLines, false,
       autogenComment.c_str());
 
     cmGeneratorTarget* gt = new cmGeneratorTarget(autogenTarget, lg);
@@ -828,7 +822,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget(
       autogenTarget->SetProperty("FOLDER", autogenFolder);
     } else {
       // inherit FOLDER property from target (#13688)
-      copyTargetProperty(gt->Target, target->Target, "FOLDER");
+      utilCopyTargetProperty(gt->Target, target->Target, "FOLDER");
     }
 
     target->Target->AddUtility(autogenTargetName);
@@ -845,7 +839,8 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(
   static_cast<void>(varScope);
 
   // create a custom target for running generators at buildtime:
-  std::string autogenTargetName = GetAutogenTargetName(target);
+  const std::string autogenTargetName = GetAutogenTargetName(target);
+  const std::string qtMajorVersion = GetQtMajorVersion(target);
 
   makefile->AddDefinition(
     "_moc_target_name",
@@ -853,28 +848,14 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(
   makefile->AddDefinition(
     "_origin_target_name",
     cmOutputConverter::EscapeForCMake(target->GetName()).c_str());
-
-  std::string targetDir = GetAutogenTargetDir(target);
-
-  const char* qtVersion = makefile->GetDefinition("Qt5Core_VERSION_MAJOR");
-  if (!qtVersion) {
-    qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR");
-  }
-  if (const char* targetQtVersion =
-        target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION",
-                                                        "")) {
-    qtVersion = targetQtVersion;
-  }
-  if (qtVersion) {
-    makefile->AddDefinition("_target_qt_version", qtVersion);
-  }
+  makefile->AddDefinition("_target_qt_version", qtMajorVersion.c_str());
 
   std::vector<std::string> skipUic;
   std::vector<std::string> skipMoc;
   std::vector<std::string> mocSources;
   std::vector<std::string> mocHeaders;
-  std::map<std::string, std::string> configIncludes;
-  std::map<std::string, std::string> configDefines;
+  std::map<std::string, std::string> configMocIncludes;
+  std::map<std::string, std::string> configMocDefines;
   std::map<std::string, std::string> configUicOptions;
 
   if (target->GetPropertyAsBool("AUTOMOC") ||
@@ -886,39 +867,41 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(
     "_cpp_files",
     cmOutputConverter::EscapeForCMake(cmJoin(mocSources, ";")).c_str());
   if (target->GetPropertyAsBool("AUTOMOC")) {
-    SetupAutoMocTarget(target, autogenTargetName, skipMoc, mocHeaders,
-                       configIncludes, configDefines);
+    MocSetupAutoTarget(target, autogenTargetName, skipMoc, mocHeaders,
+                       configMocIncludes, configMocDefines);
   }
   if (target->GetPropertyAsBool("AUTOUIC")) {
-    SetupAutoUicTarget(target, skipUic, configUicOptions);
+    UicSetupAutoTarget(target, skipUic, configUicOptions);
   }
   if (target->GetPropertyAsBool("AUTORCC")) {
-    SetupAutoRccTarget(target);
+    RccSetupAutoTarget(target, qtMajorVersion);
   }
 
+  // Generate config file
   std::string inputFile = cmSystemTools::GetCMakeRoot();
   inputFile += "/Modules/AutogenInfo.cmake.in";
-  std::string outputFile = targetDir;
+  std::string outputFile = GetAutogenTargetFilesDir(target);
   outputFile += "/AutogenInfo.cmake";
-  makefile->AddDefinition(
-    "_qt_rcc_inputs",
-    makefile->GetDefinition("_qt_rcc_inputs_" + target->GetName()));
+
   makefile->ConfigureFile(inputFile.c_str(), outputFile.c_str(), false, true,
                           false);
 
-  // Ensure we have write permission in case .in was read-only.
-  mode_t perm = 0;
+  // Append custom definitions to config file
+  if (!configMocDefines.empty() || !configMocIncludes.empty() ||
+      !configUicOptions.empty()) {
+
+    // Ensure we have write permission in case .in was read-only.
+    mode_t perm = 0;
 #if defined(_WIN32) && !defined(__CYGWIN__)
-  mode_t mode_write = S_IWRITE;
+    mode_t mode_write = S_IWRITE;
 #else
-  mode_t mode_write = S_IWUSR;
+    mode_t mode_write = S_IWUSR;
 #endif
-  cmSystemTools::GetPermissions(outputFile, perm);
-  if (!(perm & mode_write)) {
-    cmSystemTools::SetPermissions(outputFile, perm | mode_write);
-  }
-  if (!configDefines.empty() || !configIncludes.empty() ||
-      !configUicOptions.empty()) {
+    cmSystemTools::GetPermissions(outputFile, perm);
+    if (!(perm & mode_write)) {
+      cmSystemTools::SetPermissions(outputFile, perm | mode_write);
+    }
+
     cmsys::ofstream infoFile(outputFile.c_str(), std::ios::app);
     if (!infoFile) {
       std::string error = "Internal CMake error when trying to open file: ";
@@ -927,19 +910,19 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget(
       cmSystemTools::Error(error.c_str());
       return;
     }
-    if (!configDefines.empty()) {
+    if (!configMocDefines.empty()) {
       for (std::map<std::string, std::string>::iterator
-             it = configDefines.begin(),
-             end = configDefines.end();
+             it = configMocDefines.begin(),
+             end = configMocDefines.end();
            it != end; ++it) {
         infoFile << "set(AM_MOC_COMPILE_DEFINITIONS_" << it->first << " "
                  << it->second << ")\n";
       }
     }
-    if (!configIncludes.empty()) {
+    if (!configMocIncludes.empty()) {
       for (std::map<std::string, std::string>::iterator
-             it = configIncludes.begin(),
-             end = configIncludes.end();
+             it = configMocIncludes.begin(),
+             end = configMocIncludes.end();
            it != end; ++it) {
         infoFile << "set(AM_MOC_INCLUDES_" << it->first << " " << it->second
                  << ")\n";

+ 320 - 209
Source/cmQtAutoGenerators.cxx

@@ -15,7 +15,6 @@
 #include <utility>
 
 #include "cmAlgorithms.h"
-#include "cmFilePathUuid.h"
 #include "cmGlobalGenerator.h"
 #include "cmMakefile.h"
 #include "cmOutputConverter.h"
@@ -159,7 +158,6 @@ void cmQtAutoGenerators::MergeUicOptions(
 bool cmQtAutoGenerators::Run(const std::string& targetDirectory,
                              const std::string& config)
 {
-  bool success = true;
   cmake cm;
   cm.SetHomeOutputDirectory(targetDirectory);
   cm.SetHomeDirectory(targetDirectory);
@@ -173,18 +171,18 @@ bool cmQtAutoGenerators::Run(const std::string& targetDirectory,
   CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(&gg, snapshot));
   gg.SetCurrentMakefile(mf.get());
 
-  this->ReadAutogenInfoFile(mf.get(), targetDirectory, config);
+  if (!this->ReadAutogenInfoFile(mf.get(), targetDirectory, config)) {
+    return false;
+  }
   this->ReadOldMocDefinitionsFile(mf.get(), targetDirectory);
-
   this->Init();
 
   if (this->QtMajorVersion == "4" || this->QtMajorVersion == "5") {
-    success = this->RunAutogen(mf.get());
+    if (!this->RunAutogen(mf.get())) {
+      return false;
+    }
   }
-
-  this->WriteOldMocDefinitionsFile(targetDirectory);
-
-  return success;
+  return this->WriteOldMocDefinitionsFile(targetDirectory);
 }
 
 bool cmQtAutoGenerators::ReadAutogenInfoFile(
@@ -196,30 +194,41 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
   filename += "/AutogenInfo.cmake";
 
   if (!makefile->ReadListFile(filename.c_str())) {
-    cmSystemTools::Error("Error processing file: ", filename.c_str());
+    std::ostringstream err;
+    err << "AUTOGEN: error processing file: " << filename << std::endl;
+    this->LogError(err.str());
     return false;
   }
 
+  // - Target names
+  this->OriginTargetName =
+    makefile->GetSafeDefinition("AM_ORIGIN_TARGET_NAME");
+  this->AutogenTargetName = makefile->GetSafeDefinition("AM_TARGET_NAME");
+
+  // - Directories
+  this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR");
+  this->ProjectBinaryDir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR");
+  this->CurrentSourceDir =
+    makefile->GetSafeDefinition("AM_CMAKE_CURRENT_SOURCE_DIR");
+  this->CurrentBinaryDir =
+    makefile->GetSafeDefinition("AM_CMAKE_CURRENT_BINARY_DIR");
+
+  // - Qt environment
   this->QtMajorVersion = makefile->GetSafeDefinition("AM_QT_VERSION_MAJOR");
   if (this->QtMajorVersion == "") {
     this->QtMajorVersion =
       makefile->GetSafeDefinition("AM_Qt5Core_VERSION_MAJOR");
   }
-  this->Sources = makefile->GetSafeDefinition("AM_SOURCES");
-  {
-    std::string rccSources = makefile->GetSafeDefinition("AM_RCC_SOURCES");
-    cmSystemTools::ExpandListArgument(rccSources, this->RccSources);
-  }
-  this->SkipMoc = makefile->GetSafeDefinition("AM_SKIP_MOC");
-  this->SkipUic = makefile->GetSafeDefinition("AM_SKIP_UIC");
-  this->Headers = makefile->GetSafeDefinition("AM_HEADERS");
-  this->IncludeProjectDirsBefore =
-    makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
-  this->Srcdir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_SOURCE_DIR");
-  this->Builddir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_BINARY_DIR");
   this->MocExecutable = makefile->GetSafeDefinition("AM_QT_MOC_EXECUTABLE");
   this->UicExecutable = makefile->GetSafeDefinition("AM_QT_UIC_EXECUTABLE");
   this->RccExecutable = makefile->GetSafeDefinition("AM_QT_RCC_EXECUTABLE");
+
+  // - File Lists
+  this->Sources = makefile->GetSafeDefinition("AM_SOURCES");
+  this->Headers = makefile->GetSafeDefinition("AM_HEADERS");
+
+  // - Moc
+  this->SkipMoc = makefile->GetSafeDefinition("AM_SKIP_MOC");
   {
     std::string compileDefsPropOrig = "AM_MOC_COMPILE_DEFINITIONS";
     std::string compileDefsProp = compileDefsPropOrig;
@@ -244,12 +253,9 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
       includes ? includes : makefile->GetSafeDefinition(includesPropOrig);
   }
   this->MocOptionsStr = makefile->GetSafeDefinition("AM_MOC_OPTIONS");
-  this->ProjectBinaryDir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR");
-  this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR");
-  this->TargetName = makefile->GetSafeDefinition("AM_TARGET_NAME");
-  this->OriginTargetName =
-    makefile->GetSafeDefinition("AM_ORIGIN_TARGET_NAME");
 
+  // - Uic
+  this->SkipUic = makefile->GetSafeDefinition("AM_SKIP_UIC");
   {
     const char* uicOptionsFiles =
       makefile->GetSafeDefinition("AM_UIC_OPTIONS_FILES");
@@ -280,6 +286,12 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
       this->UicOptions[*fileIt] = *optionIt;
     }
   }
+
+  // - Rcc
+  {
+    std::string rccSources = makefile->GetSafeDefinition("AM_RCC_SOURCES");
+    cmSystemTools::ExpandListArgument(rccSources, this->RccSources);
+  }
   {
     const char* rccOptionsFiles =
       makefile->GetSafeDefinition("AM_RCC_OPTIONS_FILES");
@@ -303,8 +315,15 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
     std::vector<std::string> rccInputLists;
     cmSystemTools::ExpandListArgument(rccInputs, rccInputLists);
 
+    // qrc files in the end of the list may have been empty
+    if (rccInputLists.size() < this->RccSources.size()) {
+      rccInputLists.resize(this->RccSources.size());
+    }
     if (this->RccSources.size() != rccInputLists.size()) {
-      cmSystemTools::Error("Error processing file: ", filename.c_str());
+      std::ostringstream err;
+      err << "AUTOGEN: RCC sources lists size missmatch in: " << filename;
+      err << std::endl;
+      this->LogError(err.str());
       return false;
     }
 
@@ -318,9 +337,14 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile(
       this->RccInputs[*fileIt] = rccInputFiles;
     }
   }
+
+  // - Settings
   this->CurrentCompileSettingsStr = this->MakeCompileSettingsString(makefile);
 
-  this->RelaxedMode = makefile->IsOn("AM_RELAXED_MODE");
+  // - Flags
+  this->IncludeProjectDirsBefore =
+    makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE");
+  this->MocRelaxedMode = makefile->IsOn("AM_MOC_RELAXED_MODE");
 
   return true;
 }
@@ -341,7 +365,7 @@ std::string cmQtAutoGenerators::MakeCompileSettingsString(cmMakefile* makefile)
   return s;
 }
 
-bool cmQtAutoGenerators::ReadOldMocDefinitionsFile(
+void cmQtAutoGenerators::ReadOldMocDefinitionsFile(
   cmMakefile* makefile, const std::string& targetDirectory)
 {
   std::string filename(cmSystemTools::CollapseFullPath(targetDirectory));
@@ -352,34 +376,49 @@ bool cmQtAutoGenerators::ReadOldMocDefinitionsFile(
     this->OldCompileSettingsStr =
       makefile->GetSafeDefinition("AM_OLD_COMPILE_SETTINGS");
   }
-  return true;
 }
 
-void cmQtAutoGenerators::WriteOldMocDefinitionsFile(
+bool cmQtAutoGenerators::WriteOldMocDefinitionsFile(
   const std::string& targetDirectory)
 {
+  bool success = true;
+
   std::string filename(cmSystemTools::CollapseFullPath(targetDirectory));
   cmSystemTools::ConvertToUnixSlashes(filename);
   filename += "/AutomocOldMocDefinitions.cmake";
 
-  cmsys::ofstream outfile;
-  outfile.open(filename.c_str(), std::ios::trunc);
-  outfile << "set(AM_OLD_COMPILE_SETTINGS "
-          << cmOutputConverter::EscapeForCMake(this->CurrentCompileSettingsStr)
-          << ")\n";
+  {
+    cmsys::ofstream outfile;
+    outfile.open(filename.c_str(), std::ios::trunc);
+    if (outfile) {
+      outfile << "set(AM_OLD_COMPILE_SETTINGS "
+              << cmOutputConverter::EscapeForCMake(
+                   this->CurrentCompileSettingsStr)
+              << ")\n";
+      success = outfile.good();
+    } else {
+      success = false;
+    }
+  }
 
-  outfile.close();
+  return success;
 }
 
 void cmQtAutoGenerators::Init()
 {
-  this->TargetBuildSubDir = this->TargetName;
-  this->TargetBuildSubDir += ".dir/";
+  this->AutogenBuildSubDir = this->AutogenTargetName;
+  this->AutogenBuildSubDir += "/";
 
-  this->OutMocCppFilenameRel = this->TargetName;
-  this->OutMocCppFilenameRel += ".cpp";
+  this->OutMocCppFilenameRel = this->AutogenBuildSubDir;
+  this->OutMocCppFilenameRel += "moc_compilation.cpp";
 
-  this->OutMocCppFilenameAbs = this->Builddir + this->OutMocCppFilenameRel;
+  this->OutMocCppFilenameAbs =
+    this->CurrentBinaryDir + this->OutMocCppFilenameRel;
+
+  // Init file path checksum generator
+  fpathCheckSum.setupParentDirs(this->CurrentSourceDir, this->CurrentBinaryDir,
+                                this->ProjectSourceDir,
+                                this->ProjectBinaryDir);
 
   std::vector<std::string> cdefList;
   cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList);
@@ -464,10 +503,10 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
   // the program goes through all .cpp files to see which moc files are
   // included. It is not really interesting how the moc file is named, but
   // what file the moc is created from. Once a moc is included the same moc
-  // may not be included in the _automoc.cpp file anymore. OTOH if there's a
-  // header containing Q_OBJECT where no corresponding moc file is included
-  // anywhere a moc_<filename>.cpp file is created and included in
-  // the _automoc.cpp file.
+  // may not be included in the moc_compilation.cpp file anymore. OTOH if
+  // there's a header containing Q_OBJECT where no corresponding moc file
+  // is included anywhere a moc_<filename>.cpp file is created and included in
+  // the moc_compilation.cpp file.
 
   // key = moc source filepath, value = moc output filepath
   std::map<std::string, std::string> includedMocs;
@@ -497,11 +536,16 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
       err << "AUTOGEN: Checking " << absFilename << std::endl;
       this->LogInfo(err.str());
     }
-    if (this->RelaxedMode) {
-      this->ParseCppFile(absFilename, headerExtensions, includedMocs, uiFiles);
+    if (this->MocRelaxedMode) {
+      if (!this->ParseCppFile(absFilename, headerExtensions, includedMocs,
+                              uiFiles)) {
+        return false;
+      }
     } else {
-      this->StrictParseCppFile(absFilename, headerExtensions, includedMocs,
-                               uiFiles);
+      if (!this->StrictParseCppFile(absFilename, headerExtensions,
+                                    includedMocs, uiFiles)) {
+        return false;
+      }
     }
     this->SearchHeadersForCppFile(absFilename, headerExtensions, headerFiles);
   }
@@ -533,38 +577,28 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
   this->ParseHeaders(headerFiles, includedMocs, notIncludedMocs, includedUis);
 
   if (!this->MocExecutable.empty()) {
-    this->GenerateMocFiles(includedMocs, notIncludedMocs);
+    if (!this->GenerateMocFiles(includedMocs, notIncludedMocs)) {
+      return false;
+    }
   }
   if (!this->UicExecutable.empty()) {
-    this->GenerateUiFiles(includedUis);
+    if (!this->GenerateUiFiles(includedUis)) {
+      return false;
+    }
   }
   if (!this->RccExecutable.empty()) {
-    this->GenerateQrcFiles();
-  }
-
-  if (this->RunMocFailed) {
-    std::ostringstream err;
-    err << "moc failed..." << std::endl;
-    this->LogError(err.str());
-    return false;
-  }
-  if (this->RunUicFailed) {
-    std::ostringstream err;
-    err << "uic failed..." << std::endl;
-    this->LogError(err.str());
-    return false;
-  }
-  if (this->RunRccFailed) {
-    std::ostringstream err;
-    err << "rcc failed..." << std::endl;
-    this->LogError(err.str());
-    return false;
+    if (!this->GenerateQrcFiles()) {
+      return false;
+    }
   }
 
   return true;
 }
 
-void cmQtAutoGenerators::ParseCppFile(
+/**
+ * @return True on success
+ */
+bool cmQtAutoGenerators::ParseCppFile(
   const std::string& absFilename,
   const std::vector<std::string>& headerExtensions,
   std::map<std::string, std::string>& includedMocs,
@@ -579,12 +613,12 @@ void cmQtAutoGenerators::ParseCppFile(
     std::ostringstream err;
     err << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
         << std::endl;
-    this->LogError(err.str());
-    return;
+    this->LogWarning(err.str());
+    return true;
   }
   this->ParseForUic(absFilename, contentsString, includedUis);
   if (this->MocExecutable.empty()) {
-    return;
+    return true;
   }
 
   const std::string absPath = cmsys::SystemTools::GetFilenamePath(
@@ -648,7 +682,7 @@ void cmQtAutoGenerators::ParseCppFile(
                 << std::endl;
           }
           this->LogError(err.str());
-          ::exit(EXIT_FAILURE);
+          return false;
         }
       } else {
         std::string fileToMoc = absFilename;
@@ -670,7 +704,7 @@ void cmQtAutoGenerators::ParseCppFile(
                   << ".cpp\" for a compatibility with "
                      "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
                   << std::endl;
-              this->LogError(err.str());
+              this->LogWarning(err.str());
             } else {
               std::ostringstream err;
               err << "AUTOGEN: warning: " << absFilename
@@ -683,7 +717,7 @@ void cmQtAutoGenerators::ParseCppFile(
                   << ".cpp\" for compatibility with "
                      "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
                   << std::endl;
-              this->LogError(err.str());
+              this->LogWarning(err.str());
             }
           } else {
             std::ostringstream err;
@@ -696,7 +730,7 @@ void cmQtAutoGenerators::ParseCppFile(
                    "header.\n"
                 << std::endl;
             this->LogError(err.str());
-            ::exit(EXIT_FAILURE);
+            return false;
           }
         } else {
           dotMocIncluded = true;
@@ -727,7 +761,7 @@ void cmQtAutoGenerators::ParseCppFile(
           << ".moc\" for compatibility with "
              "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
           << std::endl;
-      this->LogError(err.str());
+      this->LogWarning(err.str());
 
       includedMocs[absFilename] = ownMocUnderscoreFile;
       includedMocs.erase(ownMocHeaderFile);
@@ -740,13 +774,17 @@ void cmQtAutoGenerators::ParseCppFile(
           << "\"" << scannedFileBasename << ".moc\" !\n"
           << std::endl;
       this->LogError(err.str());
-
-      ::exit(EXIT_FAILURE);
+      return false;
     }
   }
+
+  return true;
 }
 
-void cmQtAutoGenerators::StrictParseCppFile(
+/**
+ * @return True on success
+ */
+bool cmQtAutoGenerators::StrictParseCppFile(
   const std::string& absFilename,
   const std::vector<std::string>& headerExtensions,
   std::map<std::string, std::string>& includedMocs,
@@ -761,12 +799,12 @@ void cmQtAutoGenerators::StrictParseCppFile(
     std::ostringstream err;
     err << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
         << std::endl;
-    this->LogError(err.str());
-    return;
+    this->LogWarning(err.str());
+    return true;
   }
   this->ParseForUic(absFilename, contentsString, includedUis);
   if (this->MocExecutable.empty()) {
-    return;
+    return true;
   }
 
   const std::string absPath = cmsys::SystemTools::GetFilenamePath(
@@ -819,7 +857,7 @@ void cmQtAutoGenerators::StrictParseCppFile(
                 << std::endl;
           }
           this->LogError(err.str());
-          ::exit(EXIT_FAILURE);
+          return false;
         }
       } else {
         if (basename != scannedFileBasename) {
@@ -835,7 +873,7 @@ void cmQtAutoGenerators::StrictParseCppFile(
                                         "moc on this source file.\n"
               << std::endl;
           this->LogError(err.str());
-          ::exit(EXIT_FAILURE);
+          return false;
         }
         dotMocIncluded = true;
         includedMocs[absFilename] = currentMoc;
@@ -857,8 +895,10 @@ void cmQtAutoGenerators::StrictParseCppFile(
         << "\"" << scannedFileBasename << ".moc\" !\n"
         << std::endl;
     this->LogError(err.str());
-    ::exit(EXIT_FAILURE);
+    return false;
   }
+
+  return true;
 }
 
 void cmQtAutoGenerators::ParseForUic(
@@ -873,7 +913,7 @@ void cmQtAutoGenerators::ParseForUic(
     std::ostringstream err;
     err << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
         << std::endl;
-    this->LogError(err.str());
+    this->LogWarning(err.str());
     return;
   }
   this->ParseForUic(absFilename, contentsString, includedUis);
@@ -950,8 +990,6 @@ void cmQtAutoGenerators::ParseHeaders(
   std::map<std::string, std::string>& notIncludedMocs,
   std::map<std::string, std::vector<std::string> >& includedUis)
 {
-  cmFilePathUuid fpathUuid(this->Srcdir, this->Builddir,
-                           this->ProjectSourceDir, this->ProjectBinaryDir);
   for (std::set<std::string>::const_iterator hIt = absHeaders.begin();
        hIt != absHeaders.end(); ++hIt) {
     const std::string& headerName = *hIt;
@@ -967,8 +1005,10 @@ void cmQtAutoGenerators::ParseHeaders(
 
       std::string macroName;
       if (requiresMocing(contents, macroName)) {
-        notIncludedMocs[headerName] =
-          this->TargetBuildSubDir + fpathUuid.get(headerName, "moc_", ".cpp");
+        notIncludedMocs[headerName] = fpathCheckSum.getPart(headerName) +
+          "/moc_" +
+          cmsys::SystemTools::GetFilenameWithoutLastExtension(headerName) +
+          ".cpp";
       }
     }
     this->ParseForUic(headerName, contents, includedUis);
@@ -994,44 +1034,52 @@ bool cmQtAutoGenerators::GenerateMocFiles(
           << "To avoid this error either" << std::endl
           << "- rename the source files or" << std::endl
           << "- do not include the (moc_NAME.cpp|NAME.moc) file" << std::endl;
-      this->NameCollisionLog(err.str(), collisions);
-      ::exit(EXIT_FAILURE);
+      this->LogErrorNameCollision(err.str(), collisions);
+      return false;
     }
   }
 
   // generate moc files that are included by source files.
-  for (std::map<std::string, std::string>::const_iterator it =
-         includedMocs.begin();
-       it != includedMocs.end(); ++it) {
-    if (!this->GenerateMoc(it->first, it->second)) {
-      if (this->RunMocFailed) {
-        return false;
+  {
+    const std::string subDirPrefix = "include/";
+    for (std::map<std::string, std::string>::const_iterator it =
+           includedMocs.begin();
+         it != includedMocs.end(); ++it) {
+      if (!this->GenerateMoc(it->first, it->second, subDirPrefix)) {
+        if (this->RunMocFailed) {
+          return false;
+        }
       }
     }
   }
 
   // generate moc files that are _not_ included by source files.
   bool automocCppChanged = false;
-  for (std::map<std::string, std::string>::const_iterator it =
-         notIncludedMocs.begin();
-       it != notIncludedMocs.end(); ++it) {
-    if (this->GenerateMoc(it->first, it->second)) {
-      automocCppChanged = true;
-    } else {
-      if (this->RunMocFailed) {
-        return false;
+  {
+    const std::string subDirPrefix;
+    for (std::map<std::string, std::string>::const_iterator it =
+           notIncludedMocs.begin();
+         it != notIncludedMocs.end(); ++it) {
+      if (this->GenerateMoc(it->first, it->second, subDirPrefix)) {
+        automocCppChanged = true;
+      } else {
+        if (this->RunMocFailed) {
+          return false;
+        }
       }
     }
   }
 
-  // compose _automoc.cpp content
+  // Compose moc_compilation.cpp content
   std::string automocSource;
   {
     std::ostringstream outStream;
     outStream << "/* This file is autogenerated, do not edit*/\n";
     if (notIncludedMocs.empty()) {
+      // Dummy content
       outStream << "enum some_compilers { need_more_than_nothing };\n";
     } else {
+      // Valid content
       for (std::map<std::string, std::string>::const_iterator it =
              notIncludedMocs.begin();
            it != notIncludedMocs.end(); ++it) {
@@ -1042,12 +1090,12 @@ bool cmQtAutoGenerators::GenerateMocFiles(
     automocSource = outStream.str();
   }
 
-  // check if we even need to update _automoc.cpp
+  // Check if we even need to update moc_compilation.cpp
   if (!automocCppChanged) {
-    // compare contents of the _automoc.cpp file
+    // compare contents of the moc_compilation.cpp file
     const std::string oldContents = ReadAll(this->OutMocCppFilenameAbs);
     if (oldContents == automocSource) {
-      // nothing changed: don't touch the _automoc.cpp file
+      // nothing changed: don't touch the moc_compilation.cpp file
       if (this->Verbose) {
         std::ostringstream err;
         err << "AUTOGEN: " << this->OutMocCppFilenameRel << " still up to date"
@@ -1058,43 +1106,58 @@ bool cmQtAutoGenerators::GenerateMocFiles(
     }
   }
 
-  // actually write _automoc.cpp
+  // Actually write moc_compilation.cpp
   {
-    std::string msg = "Generating moc compilation ";
+    std::string msg = "Generating MOC compilation ";
     msg += this->OutMocCppFilenameRel;
-    cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
-                                       cmsysTerminal_Color_ForegroundBold,
-                                     msg.c_str(), true, this->ColorOutput);
+    this->LogBold(msg);
   }
-  {
+  // Make sure the parent directory exists
+  bool success = this->makeParentDirectory(this->OutMocCppFilenameAbs);
+  if (success) {
     cmsys::ofstream outfile;
     outfile.open(this->OutMocCppFilenameAbs.c_str(), std::ios::trunc);
-    outfile << automocSource;
-    outfile.close();
+    if (!outfile) {
+      success = false;
+      std::ostringstream err;
+      err << "AUTOGEN: error opening " << this->OutMocCppFilenameAbs << "\n";
+      this->LogError(err.str());
+    } else {
+      outfile << automocSource;
+      // Check for write errors
+      if (!outfile.good()) {
+        success = false;
+        std::ostringstream err;
+        err << "AUTOGEN: error writing " << this->OutMocCppFilenameAbs << "\n";
+        this->LogError(err.str());
+      }
+    }
   }
-
-  return true;
+  return success;
 }
 
+/**
+ * @return True if a moc file was created. False may indicate an error.
+ */
 bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile,
-                                     const std::string& mocFileName)
+                                     const std::string& mocFileName,
+                                     const std::string& subDirPrefix)
 {
-  const std::string mocFilePath = this->Builddir + mocFileName;
+  const std::string mocFileRel =
+    this->AutogenBuildSubDir + subDirPrefix + mocFileName;
+  const std::string mocFileAbs = this->CurrentBinaryDir + mocFileRel;
   int sourceNewerThanMoc = 0;
-  bool success = cmsys::SystemTools::FileTimeCompare(sourceFile, mocFilePath,
+  bool success = cmsys::SystemTools::FileTimeCompare(sourceFile, mocFileAbs,
                                                      &sourceNewerThanMoc);
   if (this->GenerateAll || !success || sourceNewerThanMoc >= 0) {
-    // make sure the directory for the resulting moc file exists
-    std::string mocDir = mocFilePath.substr(0, mocFilePath.rfind('/'));
-    if (!cmsys::SystemTools::FileExists(mocDir.c_str(), false)) {
-      cmsys::SystemTools::MakeDirectory(mocDir.c_str());
-    }
+    // Log
+    this->LogBold("Generating MOC source " + mocFileRel);
 
-    std::string msg = "Generating moc source ";
-    msg += mocFileName;
-    cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
-                                       cmsysTerminal_Color_ForegroundBold,
-                                     msg.c_str(), true, this->ColorOutput);
+    // Make sure the parent directory exists
+    if (!this->makeParentDirectory(mocFileAbs)) {
+      this->RunMocFailed = true;
+      return false;
+    }
 
     std::vector<std::string> command;
     command.push_back(this->MocExecutable);
@@ -1108,7 +1171,7 @@ bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile,
     command.push_back("-DWIN32");
 #endif
     command.push_back("-o");
-    command.push_back(mocFilePath);
+    command.push_back(mocFileAbs);
     command.push_back(sourceFile);
 
     if (this->Verbose) {
@@ -1120,12 +1183,15 @@ bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile,
     bool result =
       cmSystemTools::RunSingleCommand(command, &output, &output, &retVal);
     if (!result || retVal) {
-      std::ostringstream err;
-      err << "AUTOGEN: error: process for " << mocFilePath << " failed:\n"
-          << output << std::endl;
-      this->LogError(err.str());
+      {
+        std::ostringstream err;
+        err << "AUTOGEN: error: moc process for " << mocFileRel << " failed:\n"
+            << output << std::endl;
+        this->LogError(err.str());
+      }
+      cmSystemTools::RemoveFile(mocFileAbs);
       this->RunMocFailed = true;
-      cmSystemTools::RemoveFile(mocFilePath);
+      return false;
     }
     return true;
   }
@@ -1166,8 +1232,8 @@ bool cmQtAutoGenerators::GenerateUiFiles(
              "from different sources."
           << std::endl
           << "To avoid this error rename the source files." << std::endl;
-      this->NameCollisionLog(err.str(), collisions);
-      ::exit(EXIT_FAILURE);
+      this->LogErrorNameCollision(err.str(), collisions);
+      return false;
     }
   }
   testMap.clear();
@@ -1191,25 +1257,29 @@ bool cmQtAutoGenerators::GenerateUiFiles(
   return true;
 }
 
+/**
+ * @return True if a uic file was created. False may indicate an error.
+ */
 bool cmQtAutoGenerators::GenerateUi(const std::string& realName,
                                     const std::string& uiInputFile,
                                     const std::string& uiOutputFile)
 {
-  if (!cmsys::SystemTools::FileExists(this->Builddir.c_str(), false)) {
-    cmsys::SystemTools::MakeDirectory(this->Builddir.c_str());
-  }
-
-  const std::string uiBuildFile = this->Builddir + uiOutputFile;
+  const std::string uicFileRel =
+    this->AutogenBuildSubDir + "include/" + uiOutputFile;
+  const std::string uicFileAbs = this->CurrentBinaryDir + uicFileRel;
 
   int sourceNewerThanUi = 0;
-  bool success = cmsys::SystemTools::FileTimeCompare(uiInputFile, uiBuildFile,
+  bool success = cmsys::SystemTools::FileTimeCompare(uiInputFile, uicFileAbs,
                                                      &sourceNewerThanUi);
   if (this->GenerateAll || !success || sourceNewerThanUi >= 0) {
-    std::string msg = "Generating ui header ";
-    msg += uiOutputFile;
-    cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
-                                       cmsysTerminal_Color_ForegroundBold,
-                                     msg.c_str(), true, this->ColorOutput);
+    // Log
+    this->LogBold("Generating UIC header " + uicFileRel);
+
+    // Make sure the parent directory exists
+    if (!this->makeParentDirectory(uicFileAbs)) {
+      this->RunUicFailed = true;
+      return false;
+    }
 
     std::vector<std::string> command;
     command.push_back(this->UicExecutable);
@@ -1226,7 +1296,7 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName,
     command.insert(command.end(), opts.begin(), opts.end());
 
     command.push_back("-o");
-    command.push_back(uiBuildFile);
+    command.push_back(uicFileAbs);
     command.push_back(uiInputFile);
 
     if (this->Verbose) {
@@ -1237,13 +1307,15 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName,
     bool result =
       cmSystemTools::RunSingleCommand(command, &output, &output, &retVal);
     if (!result || retVal) {
-      std::ostringstream err;
-      err << "AUTOUIC: error: process for " << uiOutputFile
-          << " needed by\n \"" << realName << "\"\nfailed:\n"
-          << output << std::endl;
-      this->LogError(err.str());
+      {
+        std::ostringstream err;
+        err << "AUTOUIC: error: uic process for " << uicFileRel
+            << " needed by\n \"" << realName << "\"\nfailed:\n"
+            << output << std::endl;
+        this->LogError(err.str());
+      }
+      cmSystemTools::RemoveFile(uicFileAbs);
       this->RunUicFailed = true;
-      cmSystemTools::RemoveFile(uiOutputFile);
       return false;
     }
     return true;
@@ -1271,18 +1343,13 @@ bool cmQtAutoGenerators::GenerateQrcFiles()
 {
   // generate single map with input / output names
   std::map<std::string, std::string> qrcGenMap;
-  {
-    cmFilePathUuid fpathUuid(this->Srcdir, this->Builddir,
-                             this->ProjectSourceDir, this->ProjectBinaryDir);
-    for (std::vector<std::string>::const_iterator si =
-           this->RccSources.begin();
-         si != this->RccSources.end(); ++si) {
-      const std::string ext =
-        cmsys::SystemTools::GetFilenameLastExtension(*si);
-      if (ext == ".qrc") {
-        qrcGenMap[*si] =
-          (this->TargetBuildSubDir + fpathUuid.get(*si, "qrc_", ".cpp"));
-      }
+  for (std::vector<std::string>::const_iterator si = this->RccSources.begin();
+       si != this->RccSources.end(); ++si) {
+    const std::string ext = cmsys::SystemTools::GetFilenameLastExtension(*si);
+    if (ext == ".qrc") {
+      qrcGenMap[*si] = this->AutogenBuildSubDir + fpathCheckSum.getPart(*si) +
+        "/qrc_" + cmsys::SystemTools::GetFilenameWithoutLastExtension(*si) +
+        ".cpp";
     }
   }
 
@@ -1295,8 +1362,8 @@ bool cmQtAutoGenerators::GenerateQrcFiles()
              " will be generated from different sources."
           << std::endl
           << "To avoid this error rename the source .qrc files." << std::endl;
-      this->NameCollisionLog(err.str(), collisions);
-      ::exit(EXIT_FAILURE);
+      this->LogErrorNameCollision(err.str(), collisions);
+      return false;
     }
   }
 
@@ -1314,25 +1381,24 @@ bool cmQtAutoGenerators::GenerateQrcFiles()
   return true;
 }
 
+/**
+ * @return True if a rcc file was created. False may indicate an error.
+ */
 bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile,
                                      const std::string& qrcOutputFile,
                                      bool unique_n)
 {
-  std::string symbolName;
-  if (unique_n) {
-    symbolName =
-      cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile);
-  } else {
-    symbolName =
-      cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcOutputFile);
-    // Remove "qrc_" at string begin
-    symbolName.erase(0, 4);
+  std::string symbolName =
+    cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile);
+  if (!unique_n) {
+    symbolName += "_";
+    symbolName += fpathCheckSum.getPart(qrcInputFile);
   }
   // Replace '-' with '_'. The former is valid for
   // file names but not for symbol names.
   std::replace(symbolName.begin(), symbolName.end(), '-', '_');
 
-  const std::string qrcBuildFile = this->Builddir + qrcOutputFile;
+  const std::string qrcBuildFile = this->CurrentBinaryDir + qrcOutputFile;
 
   int sourceNewerThanQrc = 0;
   bool generateQrc = !cmsys::SystemTools::FileTimeCompare(
@@ -1342,21 +1408,27 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile,
     generateQrc || this->InputFilesNewerThanQrc(qrcInputFile, qrcBuildFile);
 
   if (this->GenerateAll || generateQrc) {
-    std::string msg = "Generating qrc source ";
-    msg += qrcOutputFile;
-    cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
-                                       cmsysTerminal_Color_ForegroundBold,
-                                     msg.c_str(), true, this->ColorOutput);
+    {
+      std::string msg = "Generating RCC source ";
+      msg += qrcOutputFile;
+      this->LogBold(msg);
+    }
+
+    // Make sure the parent directory exists
+    if (!this->makeParentDirectory(qrcOutputFile)) {
+      this->RunRccFailed = true;
+      return false;
+    }
 
     std::vector<std::string> command;
     command.push_back(this->RccExecutable);
-
-    std::map<std::string, std::string>::const_iterator optionIt =
-      this->RccOptions.find(qrcInputFile);
-    if (optionIt != this->RccOptions.end()) {
-      cmSystemTools::ExpandListArgument(optionIt->second, command);
+    {
+      std::map<std::string, std::string>::const_iterator optionIt =
+        this->RccOptions.find(qrcInputFile);
+      if (optionIt != this->RccOptions.end()) {
+        cmSystemTools::ExpandListArgument(optionIt->second, command);
+      }
     }
-
     command.push_back("-name");
     command.push_back(symbolName);
     command.push_back("-o");
@@ -1371,16 +1443,20 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile,
     bool result =
       cmSystemTools::RunSingleCommand(command, &output, &output, &retVal);
     if (!result || retVal) {
-      std::ostringstream err;
-      err << "AUTORCC: error: process for " << qrcOutputFile << " failed:\n"
-          << output << std::endl;
-      this->LogError(err.str());
-      this->RunRccFailed = true;
+      {
+        std::ostringstream err;
+        err << "AUTORCC: error: rcc process for " << qrcOutputFile
+            << " failed:\n"
+            << output << std::endl;
+        this->LogError(err.str());
+      }
       cmSystemTools::RemoveFile(qrcBuildFile);
+      this->RunRccFailed = true;
       return false;
     }
+    return true;
   }
-  return true;
+  return false;
 }
 
 /**
@@ -1413,7 +1489,7 @@ bool cmQtAutoGenerators::NameCollisionTest(
   return !collisions.empty();
 }
 
-void cmQtAutoGenerators::NameCollisionLog(
+void cmQtAutoGenerators::LogErrorNameCollision(
   const std::string& message,
   const std::multimap<std::string, std::string>& collisions)
 {
@@ -1429,14 +1505,30 @@ void cmQtAutoGenerators::NameCollisionLog(
   this->LogError(err.str());
 }
 
+void cmQtAutoGenerators::LogBold(const std::string& message)
+{
+  cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
+                                     cmsysTerminal_Color_ForegroundBold,
+                                   message.c_str(), true, this->ColorOutput);
+}
+
 void cmQtAutoGenerators::LogInfo(const std::string& message)
 {
-  std::cout << message;
+  std::cout << message.c_str();
+}
+
+void cmQtAutoGenerators::LogWarning(const std::string& message)
+{
+  std::ostringstream ostr;
+  ostr << message << "\n";
+  std::cout << message.c_str();
 }
 
 void cmQtAutoGenerators::LogError(const std::string& message)
 {
-  std::cerr << message;
+  std::ostringstream ostr;
+  ostr << message << "\n\n";
+  std::cerr << ostr.str();
 }
 
 void cmQtAutoGenerators::LogCommand(const std::vector<std::string>& command)
@@ -1455,6 +1547,25 @@ void cmQtAutoGenerators::LogCommand(const std::vector<std::string>& command)
   }
 }
 
+/**
+ * @brief Generates the parent directory of the given file on demand
+ * @return True on success
+ */
+bool cmQtAutoGenerators::makeParentDirectory(const std::string& filename)
+{
+  bool success = true;
+  const std::string dirName = cmSystemTools::GetFilenamePath(filename);
+  if (!dirName.empty()) {
+    success = cmsys::SystemTools::MakeDirectory(dirName);
+    if (!success) {
+      std::ostringstream err;
+      err << "AUTOGEN: Directory creation failed: " << dirName << std::endl;
+      this->LogError(err.str());
+    }
+  }
+  return success;
+}
+
 std::string cmQtAutoGenerators::JoinExts(const std::vector<std::string>& lst)
 {
   if (lst.empty()) {

+ 43 - 25
Source/cmQtAutoGenerators.h

@@ -4,6 +4,7 @@
 #define cmQtAutoGenerators_h
 
 #include <cmConfigure.h> // IWYU pragma: keep
+#include <cmFilePathChecksum.h>
 
 #include <list>
 #include <map>
@@ -23,32 +24,36 @@ private:
   bool ReadAutogenInfoFile(cmMakefile* makefile,
                            const std::string& targetDirectory,
                            const std::string& config);
-  bool ReadOldMocDefinitionsFile(cmMakefile* makefile,
+  void ReadOldMocDefinitionsFile(cmMakefile* makefile,
                                  const std::string& targetDirectory);
-  void WriteOldMocDefinitionsFile(const std::string& targetDirectory);
+  bool WriteOldMocDefinitionsFile(const std::string& targetDirectory);
 
   std::string MakeCompileSettingsString(cmMakefile* makefile);
 
   bool RunAutogen(cmMakefile* makefile);
+
   bool GenerateMocFiles(
     const std::map<std::string, std::string>& includedMocs,
     const std::map<std::string, std::string>& notIncludedMocs);
   bool GenerateMoc(const std::string& sourceFile,
-                   const std::string& mocFileName);
+                   const std::string& mocFileName,
+                   const std::string& subDirPrefix);
+
   bool GenerateUiFiles(
     const std::map<std::string, std::vector<std::string> >& includedUis);
   bool GenerateUi(const std::string& realName, const std::string& uiInputFile,
                   const std::string& uiOutputFile);
+
   bool GenerateQrcFiles();
   bool GenerateQrc(const std::string& qrcInputFile,
                    const std::string& qrcOutputFile, bool unique_n);
 
-  void ParseCppFile(
+  bool ParseCppFile(
     const std::string& absFilename,
     const std::vector<std::string>& headerExtensions,
     std::map<std::string, std::string>& includedMocs,
     std::map<std::string, std::vector<std::string> >& includedUis);
-  void StrictParseCppFile(
+  bool StrictParseCppFile(
     const std::string& absFilename,
     const std::vector<std::string>& headerExtensions,
     std::map<std::string, std::string>& includedMocs,
@@ -76,13 +81,18 @@ private:
 
   bool NameCollisionTest(const std::map<std::string, std::string>& genFiles,
                          std::multimap<std::string, std::string>& collisions);
-  void NameCollisionLog(
+
+  void LogErrorNameCollision(
     const std::string& message,
     const std::multimap<std::string, std::string>& collisions);
-
+  void LogBold(const std::string& message);
   void LogInfo(const std::string& message);
+  void LogWarning(const std::string& message);
   void LogError(const std::string& message);
   void LogCommand(const std::vector<std::string>& command);
+
+  bool makeParentDirectory(const std::string& filename);
+
   std::string JoinExts(const std::vector<std::string>& lst);
 
   static void MergeUicOptions(std::vector<std::string>& opts,
@@ -92,39 +102,47 @@ private:
   bool InputFilesNewerThanQrc(const std::string& qrcFile,
                               const std::string& rccOutput);
 
+  // - Target names
+  std::string OriginTargetName;
+  std::string AutogenTargetName;
+  // - Directories
+  std::string ProjectSourceDir;
+  std::string ProjectBinaryDir;
+  std::string CurrentSourceDir;
+  std::string CurrentBinaryDir;
+  std::string AutogenBuildSubDir;
+  // - Qt environment
   std::string QtMajorVersion;
-  std::string Sources;
-  std::vector<std::string> RccSources;
-  std::string SkipMoc;
-  std::string SkipUic;
-  std::string Headers;
-  std::string Srcdir;
-  std::string Builddir;
   std::string MocExecutable;
   std::string UicExecutable;
   std::string RccExecutable;
+  // - File lists
+  std::string Sources;
+  std::string Headers;
+  // - Moc
+  std::string SkipMoc;
   std::string MocCompileDefinitionsStr;
   std::string MocIncludesStr;
   std::string MocOptionsStr;
-  std::string ProjectBinaryDir;
-  std::string ProjectSourceDir;
-  std::string TargetName;
-  std::string OriginTargetName;
-
-  std::string CurrentCompileSettingsStr;
-  std::string OldCompileSettingsStr;
-
-  std::string TargetBuildSubDir;
   std::string OutMocCppFilenameRel;
   std::string OutMocCppFilenameAbs;
   std::list<std::string> MocIncludes;
   std::list<std::string> MocDefinitions;
   std::vector<std::string> MocOptions;
+  // - Uic
+  std::string SkipUic;
   std::vector<std::string> UicTargetOptions;
   std::map<std::string, std::string> UicOptions;
+  // - Rcc
+  std::vector<std::string> RccSources;
   std::map<std::string, std::string> RccOptions;
   std::map<std::string, std::vector<std::string> > RccInputs;
-
+  // - Settings
+  std::string CurrentCompileSettingsStr;
+  std::string OldCompileSettingsStr;
+  // - Utility
+  cmFilePathChecksum fpathCheckSum;
+  // - Flags
   bool IncludeProjectDirsBefore;
   bool Verbose;
   bool ColorOutput;
@@ -132,7 +150,7 @@ private:
   bool RunUicFailed;
   bool RunRccFailed;
   bool GenerateAll;
-  bool RelaxedMode;
+  bool MocRelaxedMode;
 };
 
 #endif

+ 3 - 4
Tests/QtAutoUicInterface/CMakeLists.txt

@@ -1,5 +1,5 @@
 
-cmake_minimum_required(VERSION 2.8.12)
+cmake_minimum_required(VERSION 3.7)
 
 project(QtAutoUicInterface)
 
@@ -21,7 +21,6 @@ else()
 endif()
 
 set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
 set(CMAKE_AUTOMOC ON)
 set(CMAKE_AUTOUIC ON)
 
@@ -65,6 +64,6 @@ target_link_libraries(MyWidget KI18n ${QT_GUI_TARGET})
 add_executable(QtAutoUicInterface main.cpp)
 target_compile_definitions(QtAutoUicInterface
   PRIVATE
-    UI_LIBWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/ui_libwidget.h"
-    UI_MYWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/ui_mywidget.h"
+    UI_LIBWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/LibWidget_autogen/include/ui_libwidget.h"
+    UI_MYWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/MyWidget_autogen/include/ui_mywidget.h"
 )

+ 5 - 0
Tests/QtAutoUicInterface/libwidget.cpp

@@ -7,3 +7,8 @@ LibWidget::LibWidget(QWidget* parent)
 {
   ui->setupUi(this);
 }
+
+LibWidget::~LibWidget()
+{
+  delete ui;
+}

+ 2 - 1
Tests/QtAutoUicInterface/libwidget.h

@@ -16,9 +16,10 @@ class LibWidget : public QWidget
   Q_OBJECT
 public:
   explicit LibWidget(QWidget* parent = 0);
+  ~LibWidget();
 
 private:
-  const std::auto_ptr<Ui::LibWidget> ui;
+  Ui::LibWidget* ui;
 };
 
 #endif

+ 5 - 0
Tests/QtAutoUicInterface/mywidget.cpp

@@ -7,3 +7,8 @@ MyWidget::MyWidget(QWidget* parent)
 {
   ui->setupUi(this);
 }
+
+MyWidget::~MyWidget()
+{
+  delete ui;
+}

+ 2 - 1
Tests/QtAutoUicInterface/mywidget.h

@@ -16,9 +16,10 @@ class MyWidget : public QWidget
   Q_OBJECT
 public:
   explicit MyWidget(QWidget* parent = 0);
+  ~MyWidget();
 
 private:
-  const std::auto_ptr<Ui::MyWidget> ui;
+  Ui::MyWidget* ui;
 };
 
 #endif

+ 1 - 2
Tests/QtAutogen/CMakeLists.txt

@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.7)
 
 project(QtAutogen)
 
@@ -45,7 +45,6 @@ else()
 endif()
 
 get_property(QT_COMPILE_FEATURES TARGET ${QT_QTCORE_TARGET} PROPERTY INTERFACE_COMPILE_FEATURES)
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
 
 # -- Test: AUTORCC
 # RCC only

+ 1 - 1
Tests/QtAutogen/automoc_rerun/CMakeLists.txt

@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.7)
 project(automoc_rerun CXX)
 
 if (QT_TEST_VERSION STREQUAL 4)

+ 1 - 1
Tests/QtAutogen/autorcc_depends/CMakeLists.txt

@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.7)
 project(autorcc_depends)
 
 set(CMAKE_AUTORCC ON)

+ 0 - 1
Tests/QtAutogen/complex/Bdir/CMakeLists.txt

@@ -6,5 +6,4 @@ set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)
 add_library(libB SHARED libB.cpp)
 generate_export_header(libB)
 
-# set_property(TARGET libB APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} )
 target_link_libraries(libB LINK_PUBLIC libA)

+ 3 - 2
Tests/QtAutogen/complex/CMakeLists.txt

@@ -1,7 +1,6 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.7)
 
 # -- Test: AUTOMOC AUTORCC AUTOUIC
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
 add_definitions(-DFOO -DSomeDefine="Barx")
 
 # enable relaxed mode so automoc can handle all the special cases:
@@ -77,5 +76,7 @@ add_library(libC SHARED libC.cpp)
 set_target_properties(libC PROPERTIES AUTOMOC TRUE)
 generate_export_header(libC)
 target_link_libraries(libC LINK_PUBLIC libB)
+target_include_directories(libC PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+set_property(TARGET libC APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR} )
 
 target_link_libraries(QtAutogen codeeditorLib ${QT_LIBRARIES} libC)

+ 0 - 2
Tests/QtAutogen/defines_test/CMakeLists.txt

@@ -1,6 +1,4 @@
 
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
-
 add_executable(defines_test defines_test.cpp)
 set_target_properties(defines_test PROPERTIES AUTOMOC TRUE)
 target_link_libraries(defines_test Qt4::QtGui)

+ 1 - 2
Tests/QtAutogen/sameName/CMakeLists.txt

@@ -16,6 +16,5 @@ add_executable(sameName
   data.qrc
   main.cpp
 )
-target_include_directories(sameName PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
 target_link_libraries(sameName ${QT_LIBRARIES})
-set_target_properties( sameName PROPERTIES AUTOMOC TRUE AUTORCC TRUE )
+set_target_properties(sameName PROPERTIES AUTOMOC TRUE AUTORCC TRUE)

+ 5 - 0
Tests/QtAutogen/uicOnlySource/uiconly.cpp

@@ -7,6 +7,11 @@ UicOnly::UicOnly(QWidget* parent)
 {
 }
 
+UicOnly::~UicOnly()
+{
+  delete ui;
+}
+
 int main()
 {
   return 0;

+ 2 - 2
Tests/QtAutogen/uicOnlySource/uiconly.h

@@ -3,7 +3,6 @@
 #define UIC_ONLY_H
 
 #include <QWidget>
-#include <memory>
 
 #include "ui_uiconly.h"
 
@@ -12,9 +11,10 @@ class UicOnly : public QWidget
   Q_OBJECT
 public:
   explicit UicOnly(QWidget* parent = 0);
+  ~UicOnly();
 
 private:
-  const std::auto_ptr<Ui::UicOnly> ui;
+  Ui::UicOnly* ui;
 };
 
 #endif