Coverage Report

Created: 2026-09-14 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmQtAutoGenInitializer.cxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
#include "cmQtAutoGenInitializer.h"
4
5
#include <array>
6
#include <cstddef>
7
#include <deque>
8
#include <functional>
9
#include <initializer_list>
10
#include <limits>
11
#include <map>
12
#include <set>
13
#include <sstream> // for basic_ios, istringstream
14
#include <string>
15
#include <unordered_set>
16
#include <utility>
17
#include <vector>
18
19
#include <cm/algorithm>
20
#include <cm/iterator>
21
#include <cm/memory>
22
#include <cm/string_view>
23
#include <cmext/algorithm>
24
#include <cmext/string_view>
25
26
#include <cm3p/json/value.h>
27
#include <cm3p/json/writer.h>
28
29
#include "cmsys/SystemInformation.hxx"
30
31
#include "cmAlgorithms.h"
32
#include "cmCustomCommand.h"
33
#include "cmCustomCommandLines.h"
34
#include "cmDiagnostics.h"
35
#include "cmEvaluatedTargetProperty.h"
36
#include "cmFileSetMetadata.h"
37
#include "cmGenExContext.h"
38
#include "cmGeneratedFileStream.h"
39
#include "cmGeneratorExpression.h"
40
#include "cmGeneratorExpressionDAGChecker.h"
41
#include "cmGeneratorFileSet.h"
42
#include "cmGeneratorTarget.h"
43
#include "cmGlobalGenerator.h"
44
#include "cmLinkItem.h"
45
#include "cmList.h"
46
#include "cmListFileCache.h"
47
#include "cmLocalGenerator.h"
48
#include "cmMakefile.h"
49
#include "cmMessageType.h"
50
#include "cmPolicies.h"
51
#include "cmQtAutoGen.h"
52
#include "cmQtAutoGenGlobalInitializer.h"
53
#include "cmSourceFile.h"
54
#include "cmSourceFileLocationKind.h"
55
#include "cmSourceGroup.h"
56
#include "cmStandardLevelResolver.h"
57
#include "cmState.h"
58
#include "cmStateTypes.h"
59
#include "cmStringAlgorithms.h"
60
#include "cmSystemTools.h"
61
#include "cmTarget.h"
62
#include "cmTargetTypes.h"
63
#include "cmValue.h"
64
#include "cmake.h"
65
66
namespace {
67
68
unsigned int GetParallelCPUCount()
69
0
{
70
0
  static unsigned int count = 0;
71
  // Detect only on the first call
72
0
  if (count == 0) {
73
0
    cmsys::SystemInformation info;
74
0
    info.RunCPUCheck();
75
0
    count =
76
0
      cm::clamp(info.GetNumberOfPhysicalCPU(), 1u, cmQtAutoGen::ParallelMax);
77
0
  }
78
0
  return count;
79
0
}
80
81
std::string FileProjectRelativePath(cmMakefile const* makefile,
82
                                    std::string const& fileName)
83
0
{
84
0
  std::string res;
85
0
  {
86
0
    std::string pSource = cmSystemTools::RelativePath(
87
0
      makefile->GetCurrentSourceDirectory(), fileName);
88
0
    std::string pBinary = cmSystemTools::RelativePath(
89
0
      makefile->GetCurrentBinaryDirectory(), fileName);
90
0
    if (pSource.size() < pBinary.size()) {
91
0
      res = std::move(pSource);
92
0
    } else if (pBinary.size() < fileName.size()) {
93
0
      res = std::move(pBinary);
94
0
    } else {
95
0
      res = fileName;
96
0
    }
97
0
  }
98
0
  return res;
99
0
}
100
101
/**
102
 * Tests if targetDepend is a STATIC_LIBRARY and if any of its
103
 * recursive STATIC_LIBRARY dependencies depends on targetOrigin
104
 * (STATIC_LIBRARY cycle).
105
 */
106
bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin,
107
                        cmGeneratorTarget const* targetDepend,
108
                        std::string const& config)
109
0
{
110
0
  bool cycle = false;
111
0
  if ((targetOrigin->GetType() == cm::TargetType::STATIC_LIBRARY) &&
112
0
      (targetDepend->GetType() == cm::TargetType::STATIC_LIBRARY)) {
113
0
    std::set<cmGeneratorTarget const*> knownLibs;
114
0
    std::deque<cmGeneratorTarget const*> testLibs;
115
116
    // Insert initial static_library dependency
117
0
    knownLibs.insert(targetDepend);
118
0
    testLibs.push_back(targetDepend);
119
120
0
    while (!testLibs.empty()) {
121
0
      cmGeneratorTarget const* testTarget = testLibs.front();
122
0
      testLibs.pop_front();
123
      // Check if the test target is the origin target (cycle)
124
0
      if (testTarget == targetOrigin) {
125
0
        cycle = true;
126
0
        break;
127
0
      }
128
      // Collect all static_library dependencies from the test target
129
0
      cmLinkImplementationLibraries const* libs =
130
0
        testTarget->GetLinkImplementationLibraries(
131
0
          config, cmGeneratorTarget::UseTo::Link);
132
0
      if (libs) {
133
0
        for (cmLinkItem const& item : libs->Libraries) {
134
0
          cmGeneratorTarget const* depTarget = item.Target;
135
0
          if (depTarget &&
136
0
              (depTarget->GetType() == cm::TargetType::STATIC_LIBRARY) &&
137
0
              knownLibs.insert(depTarget).second) {
138
0
            testLibs.push_back(depTarget);
139
0
          }
140
0
        }
141
0
      }
142
0
    }
143
0
  }
144
0
  return cycle;
145
0
}
146
147
/** Sanitizes file search paths.  */
148
class SearchPathSanitizer
149
{
150
public:
151
  SearchPathSanitizer(cmMakefile* makefile)
152
0
    : SourcePath_(makefile->GetCurrentSourceDirectory())
153
0
  {
154
0
  }
155
  std::vector<std::string> operator()(
156
    std::vector<std::string> const& paths) const;
157
158
private:
159
  std::string SourcePath_;
160
};
161
162
std::vector<std::string> SearchPathSanitizer::operator()(
163
  std::vector<std::string> const& paths) const
164
0
{
165
0
  std::vector<std::string> res;
166
0
  res.reserve(paths.size());
167
0
  for (std::string const& srcPath : paths) {
168
    // Collapse relative paths
169
0
    std::string path =
170
0
      cmSystemTools::CollapseFullPath(srcPath, this->SourcePath_);
171
    // Remove suffix slashes
172
0
    while (cmHasSuffix(path, '/')) {
173
0
      path.pop_back();
174
0
    }
175
    // Accept only non empty paths
176
0
    if (!path.empty()) {
177
0
      res.emplace_back(std::move(path));
178
0
    }
179
0
  }
180
0
  return res;
181
0
}
182
183
/** @brief Writes a CMake info file.  */
184
class InfoWriter
185
{
186
public:
187
  // -- Single value
188
  void Set(std::string const& key, std::string const& value)
189
0
  {
190
0
    this->Value_[key] = value;
191
0
  }
192
  void SetConfig(std::string const& key,
193
                 cmQtAutoGenInitializer::ConfigString const& cfgStr);
194
  void SetBool(std::string const& key, bool value)
195
0
  {
196
0
    this->Value_[key] = value;
197
0
  }
198
  void SetUInt(std::string const& key, unsigned int value)
199
0
  {
200
0
    this->Value_[key] = value;
201
0
  }
202
203
  // -- Array utility
204
  template <typename CONT>
205
  static bool MakeArray(Json::Value& jval, CONT const& container);
206
207
  template <typename CONT>
208
  static void MakeStringArray(Json::Value& jval, CONT const& container);
209
210
  // -- Array value
211
  template <typename CONT>
212
  void SetArray(std::string const& key, CONT const& container);
213
  template <typename CONT>
214
  void SetConfigArray(
215
    std::string const& key,
216
    cmQtAutoGenInitializer::ConfigStrings<CONT> const& cfgStr);
217
218
  // -- Array of arrays
219
  template <typename CONT, typename FUNC>
220
  void SetArrayArray(std::string const& key, CONT const& container, FUNC func);
221
222
  // -- Save to json file
223
  bool Save(std::string const& filename);
224
225
private:
226
  Json::Value Value_;
227
};
228
229
void InfoWriter::SetConfig(std::string const& key,
230
                           cmQtAutoGenInitializer::ConfigString const& cfgStr)
231
0
{
232
0
  this->Set(key, cfgStr.Default);
233
0
  for (auto const& item : cfgStr.Config) {
234
0
    this->Set(cmStrCat(key, '_', item.first), item.second);
235
0
  }
236
0
}
237
238
template <typename CONT>
239
bool InfoWriter::MakeArray(Json::Value& jval, CONT const& container)
240
0
{
241
0
  jval = Json::arrayValue;
242
0
  std::size_t const listSize = cm::size(container);
243
0
  if (listSize == 0) {
244
0
    return false;
245
0
  }
246
0
  jval.resize(static_cast<unsigned int>(listSize));
247
0
  return true;
248
0
}
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:bool (anonymous namespace)::InfoWriter::MakeArray<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(Json::Value&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:bool (anonymous namespace)::InfoWriter::MakeArray<std::__1::vector<cmQtAutoGenInitializer::MUFile const*, std::__1::allocator<cmQtAutoGenInitializer::MUFile const*> > >(Json::Value&, std::__1::vector<cmQtAutoGenInitializer::MUFile const*, std::__1::allocator<cmQtAutoGenInitializer::MUFile const*> > const&)
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:bool (anonymous namespace)::InfoWriter::MakeArray<std::__1::set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(Json::Value&, std::__1::set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:bool (anonymous namespace)::InfoWriter::MakeArray<std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > >(Json::Value&, std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > const&)
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:bool (anonymous namespace)::InfoWriter::MakeArray<std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > > > >(Json::Value&, std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > > > const&)
249
250
template <typename CONT>
251
void InfoWriter::MakeStringArray(Json::Value& jval, CONT const& container)
252
0
{
253
0
  if (MakeArray(jval, container)) {
254
0
    Json::ArrayIndex ii = 0;
255
0
    for (std::string const& item : container) {
256
0
      jval[ii++] = item;
257
0
    }
258
0
  }
259
0
}
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:void (anonymous namespace)::InfoWriter::MakeStringArray<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(Json::Value&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:void (anonymous namespace)::InfoWriter::MakeStringArray<std::__1::set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(Json::Value&, std::__1::set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)
260
261
template <typename CONT>
262
void InfoWriter::SetArray(std::string const& key, CONT const& container)
263
0
{
264
0
  MakeStringArray(this->Value_[key], container);
265
0
}
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:void (anonymous namespace)::InfoWriter::SetArray<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:void (anonymous namespace)::InfoWriter::SetArray<std::__1::set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)
266
267
template <typename CONT, typename FUNC>
268
void InfoWriter::SetArrayArray(std::string const& key, CONT const& container,
269
                               FUNC func)
270
0
{
271
0
  Json::Value& jval = this->Value_[key];
272
0
  if (MakeArray(jval, container)) {
273
0
    Json::ArrayIndex ii = 0;
274
0
    for (auto const& citem : container) {
275
0
      Json::Value& aval = jval[ii++];
276
0
      aval = Json::arrayValue;
277
0
      func(aval, citem);
278
0
    }
279
0
  }
280
0
}
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:void (anonymous namespace)::InfoWriter::SetArrayArray<std::__1::vector<cmQtAutoGenInitializer::MUFile const*, std::__1::allocator<cmQtAutoGenInitializer::MUFile const*> >, cmQtAutoGenInitializer::SetupWriteAutogenInfo()::$_5>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<cmQtAutoGenInitializer::MUFile const*, std::__1::allocator<cmQtAutoGenInitializer::MUFile const*> > const&, cmQtAutoGenInitializer::SetupWriteAutogenInfo()::$_5)
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:void (anonymous namespace)::InfoWriter::SetArrayArray<std::__1::vector<cmQtAutoGenInitializer::MUFile const*, std::__1::allocator<cmQtAutoGenInitializer::MUFile const*> >, cmQtAutoGenInitializer::SetupWriteAutogenInfo()::$_6>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<cmQtAutoGenInitializer::MUFile const*, std::__1::allocator<cmQtAutoGenInitializer::MUFile const*> > const&, cmQtAutoGenInitializer::SetupWriteAutogenInfo()::$_6)
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:void (anonymous namespace)::InfoWriter::SetArrayArray<std::__1::vector<cmQtAutoGenInitializer::MUFile const*, std::__1::allocator<cmQtAutoGenInitializer::MUFile const*> >, cmQtAutoGenInitializer::SetupWriteAutogenInfo()::$_7>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<cmQtAutoGenInitializer::MUFile const*, std::__1::allocator<cmQtAutoGenInitializer::MUFile const*> > const&, cmQtAutoGenInitializer::SetupWriteAutogenInfo()::$_7)
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:void (anonymous namespace)::InfoWriter::SetArrayArray<std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >, cmQtAutoGenInitializer::SetupWriteAutogenInfo()::$_8>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > const&, cmQtAutoGenInitializer::SetupWriteAutogenInfo()::$_8)
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:void (anonymous namespace)::InfoWriter::SetArrayArray<std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > > >, cmQtAutoGenInitializer::SetupWriteAutogenInfo()::$_9>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::vector<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > > > const&, cmQtAutoGenInitializer::SetupWriteAutogenInfo()::$_9)
281
282
template <typename CONT>
283
void InfoWriter::SetConfigArray(
284
  std::string const& key,
285
  cmQtAutoGenInitializer::ConfigStrings<CONT> const& cfgStr)
286
0
{
287
0
  this->SetArray(key, cfgStr.Default);
288
0
  for (auto const& item : cfgStr.Config) {
289
0
    this->SetArray(cmStrCat(key, '_', item.first), item.second);
290
0
  }
291
0
}
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:void (anonymous namespace)::InfoWriter::SetConfigArray<std::__1::set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, cmQtAutoGen::ConfigStrings<std::__1::set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > const&)
Unexecuted instantiation: cmQtAutoGenInitializer.cxx:void (anonymous namespace)::InfoWriter::SetConfigArray<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, cmQtAutoGen::ConfigStrings<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > > const&)
292
293
bool InfoWriter::Save(std::string const& filename)
294
0
{
295
0
  cmGeneratedFileStream fileStream;
296
0
  fileStream.SetCopyIfDifferent(true);
297
0
  fileStream.Open(filename, false, true);
298
0
  if (!fileStream) {
299
0
    return false;
300
0
  }
301
302
0
  Json::StyledStreamWriter jsonWriter;
303
0
  try {
304
0
    jsonWriter.write(fileStream, this->Value_);
305
0
  } catch (...) {
306
0
    return false;
307
0
  }
308
309
0
  return fileStream.Close();
310
0
}
311
312
cmQtAutoGen::ConfigStrings<std::vector<std::string>> generateListOptions(
313
  cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle> const&
314
    executableFeatures,
315
  bool IsMultiConfig)
316
0
{
317
0
  cmQtAutoGen::ConfigStrings<std::vector<std::string>> tempListOptions;
318
0
  if (IsMultiConfig) {
319
0
    for (auto const& executableFeature : executableFeatures.Config) {
320
0
      tempListOptions.Config[executableFeature.first] =
321
0
        executableFeature.second->ListOptions;
322
0
    }
323
0
  } else {
324
0
    tempListOptions.Default = executableFeatures.Default->ListOptions;
325
0
  }
326
327
0
  return tempListOptions;
328
0
}
329
330
} // End of unnamed namespace
331
332
cmQtAutoGenInitializer::cmQtAutoGenInitializer(
333
  cmQtAutoGenGlobalInitializer* globalInitializer,
334
  cmGeneratorTarget* genTarget, IntegerVersion qtVersion, bool mocEnabled,
335
  bool uicEnabled, bool rccEnabled, bool globalAutogenTarget,
336
  bool globalAutoRccTarget)
337
0
  : GlobalInitializer(globalInitializer)
338
0
  , GenTarget(genTarget)
339
0
  , GlobalGen(genTarget->GetGlobalGenerator())
340
0
  , LocalGen(genTarget->GetLocalGenerator())
341
0
  , Makefile(genTarget->Makefile)
342
0
  , PathCheckSum(genTarget->Makefile)
343
0
  , QtVersion(qtVersion)
344
0
{
345
0
  this->AutogenTarget.GlobalTarget = globalAutogenTarget;
346
0
  this->Moc.Enabled = mocEnabled;
347
0
  this->Uic.Enabled = uicEnabled;
348
0
  this->Rcc.Enabled = rccEnabled;
349
0
  this->Rcc.GlobalTarget = globalAutoRccTarget;
350
0
  this->CrossConfig =
351
0
    !this->Makefile->GetSafeDefinition("CMAKE_CROSS_CONFIGS").empty();
352
0
  this->UseBetterGraph =
353
0
    this->GenTarget->GetProperty("AUTOGEN_BETTER_GRAPH_MULTI_CONFIG").IsSet()
354
0
    ? this->GenTarget->GetProperty("AUTOGEN_BETTER_GRAPH_MULTI_CONFIG").IsOn()
355
0
    : (this->QtVersion >= IntegerVersion(6, 8));
356
  // AUTOGEN_BETTER_GRAPH_MULTI_CONFIG is set explicitly because it is read by
357
  // the qt library
358
0
  this->GenTarget->Target->SetProperty("AUTOGEN_BETTER_GRAPH_MULTI_CONFIG",
359
0
                                       this->UseBetterGraph ? "ON" : "OFF");
360
0
}
361
362
void cmQtAutoGenInitializer::AddAutogenExecutableToDependencies(
363
  cmQtAutoGenInitializer::GenVarsT const& genVars,
364
  std::vector<std::string>& dependencies) const
365
0
{
366
0
  if (genVars.ExecutableTarget) {
367
0
    dependencies.push_back(genVars.ExecutableTarget->Target->GetName());
368
0
  } else if (this->MultiConfig && this->UseBetterGraph) {
369
0
    cm::string_view const configGenexWithCommandConfig =
370
0
      "$<COMMAND_CONFIG:$<$<CONFIG:";
371
0
    cm::string_view const configGenex = "$<$<CONFIG:";
372
0
    cm::string_view const configGenexEnd = ">";
373
0
    cm::string_view const configGenexEndWithCommandConfig = ">>";
374
0
    auto genexBegin =
375
0
      this->CrossConfig ? configGenexWithCommandConfig : configGenex;
376
0
    auto genexEnd =
377
0
      this->CrossConfig ? configGenexEndWithCommandConfig : configGenexEnd;
378
0
    for (auto const& config : genVars.Executable.Config) {
379
0
      auto executableWithConfig =
380
0
        cmStrCat(genexBegin, config.first, ">:", config.second, genexEnd);
381
0
      dependencies.emplace_back(std::move(executableWithConfig));
382
0
    }
383
0
  } else {
384
0
    if (!genVars.Executable.Default.empty()) {
385
0
      dependencies.push_back(genVars.Executable.Default);
386
0
    }
387
0
  }
388
0
}
389
390
bool cmQtAutoGenInitializer::InitCustomTargets()
391
0
{
392
  // Configurations
393
0
  this->MultiConfig = this->GlobalGen->IsMultiConfig();
394
0
  this->ConfigDefault = this->Makefile->GetDefaultConfiguration();
395
0
  this->ConfigsList =
396
0
    this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
397
398
  // Verbosity
399
0
  {
400
0
    std::string const def =
401
0
      this->Makefile->GetSafeDefinition("CMAKE_AUTOGEN_VERBOSE");
402
0
    if (!def.empty()) {
403
0
      unsigned long iVerb = 0;
404
0
      if (cmStrToULong(def, &iVerb)) {
405
        // Numeric verbosity
406
0
        this->Verbosity = static_cast<unsigned int>(iVerb);
407
0
      } else {
408
        // Non numeric verbosity
409
0
        if (cmIsOn(def)) {
410
0
          this->Verbosity = 1;
411
0
        }
412
0
      }
413
0
    }
414
0
  }
415
416
  // Targets FOLDER
417
0
  {
418
0
    cmValue folder =
419
0
      this->Makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER");
420
0
    if (!folder) {
421
0
      folder = this->Makefile->GetState()->GetGlobalProperty(
422
0
        "AUTOGEN_TARGETS_FOLDER");
423
0
    }
424
    // Inherit FOLDER property from target (#13688)
425
0
    if (!folder) {
426
0
      folder = this->GenTarget->GetProperty("FOLDER");
427
0
    }
428
0
    if (folder) {
429
0
      this->TargetsFolder = *folder;
430
0
    }
431
0
  }
432
433
  // Check status of policy CMP0071 regarding handling of GENERATED files
434
0
  switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0071)) {
435
0
    case cmPolicies::WARN:
436
      // Ignore GENERATED files but warn
437
0
      this->CMP0071Warn = true;
438
0
      CM_FALLTHROUGH;
439
0
    case cmPolicies::OLD:
440
      // Ignore GENERATED files
441
0
      break;
442
0
    case cmPolicies::NEW:
443
      // Process GENERATED files
444
0
      this->CMP0071Accept = true;
445
0
      break;
446
0
  }
447
448
  // Check status of policy CMP0100 regarding handling of .hh headers
449
0
  switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0100)) {
450
0
    case cmPolicies::WARN:
451
      // Ignore but .hh files but warn
452
0
      this->CMP0100Warn = true;
453
0
      CM_FALLTHROUGH;
454
0
    case cmPolicies::OLD:
455
      // Ignore .hh files
456
0
      break;
457
0
    case cmPolicies::NEW:
458
      // Process .hh file
459
0
      this->CMP0100Accept = true;
460
0
      break;
461
0
  }
462
463
  // Common directories
464
0
  std::string relativeBuildDir;
465
0
  {
466
    // Collapsed current binary directory
467
0
    std::string const cbd = cmSystemTools::CollapseFullPath(
468
0
      std::string(), this->Makefile->GetCurrentBinaryDirectory());
469
0
    std::string infoDir;
470
0
    std::string buildDir;
471
0
    auto idirkind = cmStateEnums::IntermediateDirKind::QtAutogenMetadata;
472
0
    if (this->GenTarget->GetUseShortObjectNames(idirkind)) {
473
0
      infoDir = cmSystemTools::CollapseFullPath(
474
0
        std::string(),
475
0
        cmStrCat(this->GenTarget->GetSupportDirectory(idirkind),
476
0
                 "/autogen_info"));
477
0
      buildDir = cmSystemTools::CollapseFullPath(
478
0
        std::string(),
479
0
        cmStrCat(this->GenTarget->GetSupportDirectory(idirkind), "/autogen"));
480
0
    } else {
481
0
      infoDir = cmStrCat(cbd, "/CMakeFiles/", this->GenTarget->GetName(),
482
0
                         "_autogen.dir");
483
0
      buildDir = cmStrCat(cbd, '/', this->GenTarget->GetName(), "_autogen");
484
0
    }
485
486
    // Info directory
487
0
    this->Dir.Info = infoDir;
488
0
    cmSystemTools::ConvertToUnixSlashes(this->Dir.Info);
489
490
    // Build directory
491
0
    this->Dir.Build = this->GenTarget->GetSafeProperty("AUTOGEN_BUILD_DIR");
492
0
    if (this->Dir.Build.empty()) {
493
0
      this->Dir.Build = buildDir;
494
0
    }
495
0
    cmSystemTools::ConvertToUnixSlashes(this->Dir.Build);
496
0
    this->Dir.RelativeBuild =
497
0
      cmSystemTools::RelativePath(cbd, this->Dir.Build);
498
    // Cleanup build directory
499
0
    this->AddCleanFile(this->Dir.Build);
500
501
    // Working directory
502
0
    this->Dir.Work = cbd;
503
0
    cmSystemTools::ConvertToUnixSlashes(this->Dir.Work);
504
505
    // Include directory
506
0
    this->ConfigFileNamesAndGenex(this->Dir.Include, this->Dir.IncludeGenExp,
507
0
                                  cmStrCat(this->Dir.Build, "/include"), "");
508
0
  }
509
510
  // Moc, Uic and _autogen target settings
511
0
  if (this->MocOrUicEnabled()) {
512
    // Init moc specific settings
513
0
    if (this->Moc.Enabled && !this->InitMoc()) {
514
0
      return false;
515
0
    }
516
517
    // Init uic specific settings
518
0
    if (this->Uic.Enabled && !this->InitUic()) {
519
0
      return false;
520
0
    }
521
522
    // Autogen target name
523
0
    this->AutogenTarget.Name =
524
0
      cmStrCat(this->GenTarget->GetName(), "_autogen");
525
526
    // Autogen target parallel processing
527
0
    {
528
0
      using ParallelType = decltype(this->AutogenTarget.Parallel);
529
0
      unsigned long propInt = 0;
530
0
      std::string const& prop =
531
0
        this->GenTarget->GetSafeProperty("AUTOGEN_PARALLEL");
532
0
      if (prop.empty() || (prop == "AUTO")) {
533
        // Autodetect number of CPUs
534
0
        this->AutogenTarget.Parallel = GetParallelCPUCount();
535
0
      } else if (cmStrToULong(prop, &propInt) && propInt > 0 &&
536
0
                 propInt <= std::numeric_limits<ParallelType>::max()) {
537
0
        this->AutogenTarget.Parallel = static_cast<ParallelType>(propInt);
538
0
      } else {
539
        // Warn the project author that AUTOGEN_PARALLEL is not valid.
540
0
        this->Makefile->IssueDiagnostic(
541
0
          cmDiagnostics::CMD_AUTHOR,
542
0
          cmStrCat("AUTOGEN_PARALLEL=\"", prop, "\" for target \"",
543
0
                   this->GenTarget->GetName(),
544
0
                   "\" is not valid. Using AUTOGEN_PARALLEL=1"));
545
0
        this->AutogenTarget.Parallel = 1;
546
0
      }
547
0
    }
548
549
#ifdef _WIN32
550
    {
551
      auto const& value =
552
        this->GenTarget->GetProperty("AUTOGEN_COMMAND_LINE_LENGTH_MAX");
553
      if (value.IsSet()) {
554
        using maxCommandLineLengthType =
555
          decltype(this->AutogenTarget.MaxCommandLineLength);
556
        unsigned long propInt = 0;
557
        if (cmStrToULong(value, &propInt) && propInt > 0 &&
558
            propInt <= std::numeric_limits<maxCommandLineLengthType>::max()) {
559
          this->AutogenTarget.MaxCommandLineLength =
560
            static_cast<maxCommandLineLengthType>(propInt);
561
        } else {
562
          // Warn the project author that AUTOGEN_PARALLEL is not valid.
563
          this->Makefile->IssueDiagnostic(
564
            cmDiagnostics::CMD_AUTHOR,
565
            cmStrCat("AUTOGEN_COMMAND_LINE_LENGTH_MAX=\"", *value,
566
                     "\" for target \"", this->GenTarget->GetName(),
567
                     "\" is not valid. Using no limit for "
568
                     "AUTOGEN_COMMAND_LINE_LENGTH_MAX"));
569
          this->AutogenTarget.MaxCommandLineLength =
570
            std::numeric_limits<maxCommandLineLengthType>::max();
571
        }
572
      } else {
573
        // Actually 32767 (see
574
        // https://devblogs.microsoft.com/oldnewthing/20031210-00/?p=41553) but
575
        // we allow for a small margin
576
        this->AutogenTarget.MaxCommandLineLength = 32000;
577
      }
578
    }
579
#endif
580
581
    // Autogen target info and settings files
582
0
    {
583
      // Info file
584
0
      this->AutogenTarget.InfoFile =
585
0
        cmStrCat(this->Dir.Info, "/AutogenInfo.json");
586
587
      // Used settings file
588
0
      this->ConfigFileNames(this->AutogenTarget.SettingsFile,
589
0
                            cmStrCat(this->Dir.Info, "/AutogenUsed"), ".txt");
590
0
      this->ConfigFileClean(this->AutogenTarget.SettingsFile);
591
592
      // Parse cache file
593
0
      this->ConfigFileNames(this->AutogenTarget.ParseCacheFile,
594
0
                            cmStrCat(this->Dir.Info, "/ParseCache"), ".txt");
595
0
      this->ConfigFileClean(this->AutogenTarget.ParseCacheFile);
596
0
    }
597
598
    // Autogen target: Compute user defined dependencies
599
0
    {
600
0
      this->AutogenTarget.DependOrigin =
601
0
        this->GenTarget->GetPropertyAsBool("AUTOGEN_ORIGIN_DEPENDS");
602
603
0
      std::string const& deps =
604
0
        this->GenTarget->GetSafeProperty("AUTOGEN_TARGET_DEPENDS");
605
0
      if (!deps.empty()) {
606
0
        for (auto const& depName : cmList{ deps }) {
607
          // Allow target and file dependencies
608
0
          auto* depTarget = this->Makefile->FindTargetToUse(depName);
609
0
          if (depTarget) {
610
0
            this->AutogenTarget.DependTargets.insert(depTarget);
611
0
          } else {
612
0
            this->AutogenTarget.DependFiles.insert(depName);
613
0
          }
614
0
        }
615
0
      }
616
0
    }
617
618
0
    if (this->Moc.Enabled) {
619
      // Path prefix
620
0
      if (this->GenTarget->GetProperty("AUTOMOC_PATH_PREFIX").IsOn()) {
621
0
        this->Moc.PathPrefix = true;
622
0
      }
623
624
      // CMAKE_AUTOMOC_RELAXED_MODE
625
0
      if (this->Makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE")) {
626
0
        this->Moc.RelaxedMode = true;
627
0
        this->Makefile->IssueDiagnostic(
628
0
          cmDiagnostics::CMD_AUTHOR,
629
0
          cmStrCat("AUTOMOC: CMAKE_AUTOMOC_RELAXED_MODE is "
630
0
                   "deprecated an will be removed in the future.  Consider "
631
0
                   "disabling it and converting the target ",
632
0
                   this->GenTarget->GetName(), " to regular mode."));
633
0
      }
634
635
      // Options
636
0
      cmExpandList(this->GenTarget->GetSafeProperty("AUTOMOC_MOC_OPTIONS"),
637
0
                   this->Moc.Options);
638
      // Filters
639
0
      cmExpandList(this->GenTarget->GetSafeProperty("AUTOMOC_MACRO_NAMES"),
640
0
                   this->Moc.MacroNames);
641
0
      this->Moc.MacroNames.erase(cmRemoveDuplicates(this->Moc.MacroNames),
642
0
                                 this->Moc.MacroNames.end());
643
0
      {
644
0
        cmList const filterList = { this->GenTarget->GetSafeProperty(
645
0
          "AUTOMOC_DEPEND_FILTERS") };
646
0
        if ((filterList.size() % 2) != 0) {
647
0
          cmSystemTools::Error(
648
0
            cmStrCat("AutoMoc: AUTOMOC_DEPEND_FILTERS predefs size ",
649
0
                     filterList.size(), " is not a multiple of 2."));
650
0
          return false;
651
0
        }
652
0
        this->Moc.DependFilters.reserve(1 + (filterList.size() / 2));
653
0
        this->Moc.DependFilters.emplace_back(
654
0
          "Q_PLUGIN_METADATA",
655
0
          "[\n][ \t]*Q_PLUGIN_METADATA[ \t]*\\("
656
0
          "[^\\)]*FILE[ \t]*\"([^\"]+)\"");
657
0
        for (cmList::size_type ii = 0; ii != filterList.size(); ii += 2) {
658
0
          this->Moc.DependFilters.emplace_back(filterList[ii],
659
0
                                               filterList[ii + 1]);
660
0
        }
661
0
      }
662
0
    }
663
0
  }
664
665
  // Init rcc specific settings
666
0
  if (this->Rcc.Enabled && !this->InitRcc()) {
667
0
    return false;
668
0
  }
669
670
  // Add autogen include directory to the origin target INCLUDE_DIRECTORIES
671
0
  if (this->MocOrUicEnabled() || (this->Rcc.Enabled && this->MultiConfig)) {
672
0
    auto addBefore = false;
673
0
    auto const& value =
674
0
      this->GenTarget->GetProperty("AUTOGEN_USE_SYSTEM_INCLUDE");
675
0
    if (value.IsSet()) {
676
0
      if (value.IsOn()) {
677
0
        this->GenTarget->AddSystemIncludeDirectory(this->Dir.IncludeGenExp,
678
0
                                                   "CXX");
679
0
      } else {
680
0
        addBefore = true;
681
0
      }
682
0
    } else {
683
0
      switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0151)) {
684
0
        case cmPolicies::WARN:
685
0
        case cmPolicies::OLD:
686
0
          addBefore = true;
687
0
          break;
688
0
        case cmPolicies::NEW:
689
0
          this->GenTarget->AddSystemIncludeDirectory(this->Dir.IncludeGenExp,
690
0
                                                     "CXX");
691
0
          break;
692
0
      }
693
0
    }
694
0
    this->GenTarget->AddIncludeDirectory(this->Dir.IncludeGenExp, addBefore);
695
0
  }
696
697
  // Scan files
698
0
  if (!this->InitScanFiles()) {
699
0
    return false;
700
0
  }
701
702
  // Create autogen target
703
0
  if (this->MocOrUicEnabled() && !this->InitAutogenTarget()) {
704
0
    return false;
705
0
  }
706
707
  // Create rcc targets
708
0
  if (this->Rcc.Enabled && !this->InitRccTargets()) {
709
0
    return false;
710
0
  }
711
712
0
  return true;
713
0
}
714
715
bool cmQtAutoGenInitializer::InitMoc()
716
0
{
717
  // Mocs compilation file
718
0
  if (this->GlobalGen->IsXcode()) {
719
    // XXX(xcode-per-cfg-src): Drop this Xcode-specific code path
720
    // when the Xcode generator supports per-config sources.
721
0
    this->Moc.CompilationFile.Default =
722
0
      cmStrCat(this->Dir.Build, "/mocs_compilation.cpp");
723
0
    this->Moc.CompilationFileGenex = this->Moc.CompilationFile.Default;
724
0
  } else {
725
0
    this->ConfigFileNamesAndGenex(
726
0
      this->Moc.CompilationFile, this->Moc.CompilationFileGenex,
727
0
      cmStrCat(this->Dir.Build, "/mocs_compilation"_s), ".cpp"_s);
728
0
  }
729
730
  // Moc predefs
731
0
  if (this->GenTarget->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") &&
732
0
      (this->QtVersion >= IntegerVersion(5, 8))) {
733
    // Command
734
0
    cmList::assign(
735
0
      this->Moc.PredefsCmd,
736
0
      this->Makefile->GetDefinition("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND"));
737
    // Header
738
0
    if (!this->Moc.PredefsCmd.empty()) {
739
0
      this->ConfigFileNames(this->Moc.PredefsFile,
740
0
                            cmStrCat(this->Dir.Build, "/moc_predefs"), ".h");
741
0
    }
742
0
  }
743
744
  // Moc includes
745
0
  {
746
    // If the property AUTOMOC_INCLUDE_DIRECTORIES is set on the target,
747
    // use its value for moc include paths instead of gathering all
748
    // include directories from the target.
749
0
    cmValue autoIncDirs =
750
0
      this->GenTarget->GetProperty("AUTOMOC_INCLUDE_DIRECTORIES");
751
0
    if (autoIncDirs) {
752
0
      cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
753
0
      cmGeneratorExpression ge(*this->Makefile->GetCMakeInstance(), lfbt);
754
0
      auto cge = ge.Parse(*autoIncDirs);
755
756
      // Build a single list of configs to iterate, whether single or multi
757
0
      std::vector<std::string> configs = this->MultiConfig
758
0
        ? this->ConfigsList
759
0
        : std::vector<std::string>{ this->ConfigDefault };
760
761
0
      for (auto const& cfg : configs) {
762
0
        std::string eval = cge->Evaluate(this->LocalGen, cfg);
763
0
        std::vector<std::string> incList = cmList(eval);
764
765
        // Validate absolute paths
766
0
        for (auto const& path : incList) {
767
0
          if (!cmGeneratorExpression::StartsWithGeneratorExpression(path) &&
768
0
              !cmSystemTools::FileIsFullPath(path)) {
769
0
            this->Makefile->IssueMessage(
770
0
              MessageType::FATAL_ERROR,
771
0
              cmStrCat("AUTOMOC_INCLUDE_DIRECTORIES: path '", path,
772
0
                       "' is not absolute."));
773
0
            return false;
774
0
          }
775
0
        }
776
0
        if (this->MultiConfig) {
777
0
          this->Moc.Includes.Config[cfg] = std::move(incList);
778
0
        } else {
779
0
          this->Moc.Includes.Default = std::move(incList);
780
0
        }
781
0
      }
782
0
    } else {
783
      // Otherwise, discover include directories from the target for moc.
784
0
      SearchPathSanitizer const sanitizer(this->Makefile);
785
0
      auto getDirs = [this, &sanitizer](
786
0
                       std::string const& cfg) -> std::vector<std::string> {
787
        // Get the include dirs for this target, without stripping the implicit
788
        // include dirs off, see issue #13667.
789
0
        std::vector<std::string> dirs;
790
0
        bool const appendImplicit = (this->QtVersion.Major >= 5);
791
0
        this->LocalGen->GetIncludeDirectoriesImplicit(
792
0
          dirs, this->GenTarget, "CXX", cfg, false, appendImplicit);
793
0
        return sanitizer(dirs);
794
0
      };
795
796
      // Other configuration settings
797
0
      if (this->MultiConfig) {
798
0
        for (std::string const& cfg : this->ConfigsList) {
799
0
          std::vector<std::string> dirs = getDirs(cfg);
800
0
          if (dirs == this->Moc.Includes.Default) {
801
0
            continue;
802
0
          }
803
0
          this->Moc.Includes.Config[cfg] = std::move(dirs);
804
0
        }
805
0
      } else {
806
        // Default configuration include directories
807
0
        this->Moc.Includes.Default = getDirs(this->ConfigDefault);
808
0
      }
809
0
    }
810
0
  }
811
  // Moc compile definitions
812
0
  {
813
0
    auto getDefs = [this](std::string const& cfg) -> std::set<std::string> {
814
0
      std::set<std::string> defines;
815
0
      this->LocalGen->GetTargetDefines(this->GenTarget, cfg, "CXX", defines);
816
0
      if (this->Moc.PredefsCmd.empty() &&
817
0
          this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") ==
818
0
            "Windows") {
819
        // Add WIN32 definition if we don't have a moc_predefs.h
820
0
        defines.insert("WIN32");
821
0
      }
822
0
      return defines;
823
0
    };
824
825
    // Other configuration defines
826
0
    if (this->MultiConfig) {
827
0
      for (std::string const& cfg : this->ConfigsList) {
828
0
        std::set<std::string> defines = getDefs(cfg);
829
0
        if (defines == this->Moc.Defines.Default) {
830
0
          continue;
831
0
        }
832
0
        this->Moc.Defines.Config[cfg] = std::move(defines);
833
0
      }
834
0
    } else {
835
      // Default configuration defines
836
0
      this->Moc.Defines.Default = getDefs(this->ConfigDefault);
837
0
    }
838
0
  }
839
840
  // Moc executable
841
0
  {
842
0
    if (!this->GetQtExecutable(this->Moc, "moc", false)) {
843
0
      return false;
844
0
    }
845
    // Let the _autogen target depend on the moc executable
846
0
    if (this->Moc.ExecutableTarget) {
847
0
      this->AutogenTarget.DependTargets.insert(
848
0
        this->Moc.ExecutableTarget->Target);
849
0
    }
850
0
  }
851
852
0
  return true;
853
0
}
854
855
bool cmQtAutoGenInitializer::InitUic()
856
0
{
857
  // Uic search paths
858
0
  {
859
0
    std::string const& usp =
860
0
      this->GenTarget->GetSafeProperty("AUTOUIC_SEARCH_PATHS");
861
0
    if (!usp.empty()) {
862
0
      this->Uic.SearchPaths =
863
0
        SearchPathSanitizer(this->Makefile)(cmList{ usp });
864
0
    }
865
0
  }
866
  // Uic target options
867
0
  {
868
0
    auto getOpts = [this](std::string const& cfg) -> std::vector<std::string> {
869
0
      std::vector<std::string> opts;
870
0
      this->GenTarget->GetAutoUicOptions(opts, cfg);
871
0
      return opts;
872
0
    };
873
874
    // Default options
875
0
    this->Uic.Options.Default = getOpts(this->ConfigDefault);
876
    // Configuration specific options
877
0
    if (this->MultiConfig) {
878
0
      for (std::string const& cfg : this->ConfigsList) {
879
0
        std::vector<std::string> options = getOpts(cfg);
880
0
        if (options == this->Uic.Options.Default) {
881
0
          continue;
882
0
        }
883
0
        this->Uic.Options.Config[cfg] = std::move(options);
884
0
      }
885
0
    }
886
0
  }
887
888
  // Uic executable
889
0
  {
890
0
    if (!this->GetQtExecutable(this->Uic, "uic", true)) {
891
0
      return false;
892
0
    }
893
    // Let the _autogen target depend on the uic executable
894
0
    if (this->Uic.ExecutableTarget) {
895
0
      this->AutogenTarget.DependTargets.insert(
896
0
        this->Uic.ExecutableTarget->Target);
897
0
    }
898
0
  }
899
900
0
  return true;
901
0
}
902
903
bool cmQtAutoGenInitializer::InitRcc()
904
0
{
905
  // Rcc executable
906
0
  {
907
0
    if (!this->GetQtExecutable(this->Rcc, "rcc", false)) {
908
0
      return false;
909
0
    }
910
    // Evaluate test output on demand
911
0
    auto& features = this->Rcc.ExecutableFeatures;
912
0
    auto checkAndAddOptions = [this](CompilerFeaturesHandle& feature) {
913
0
      if (!feature->Evaluated) {
914
        // Look for list options
915
0
        if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) {
916
0
          static std::array<std::string, 2> const listOptions{ { "--list",
917
0
                                                                 "-list" } };
918
0
          for (std::string const& opt : listOptions) {
919
0
            if (feature->HelpOutput.find(opt) != std::string::npos) {
920
0
              feature->ListOptions.emplace_back(opt);
921
0
              break;
922
0
            }
923
0
          }
924
0
        }
925
        // Evaluation finished
926
0
        feature->Evaluated = true;
927
0
      }
928
0
    };
929
0
    if (this->MultiConfig && this->UseBetterGraph) {
930
0
      for (auto const& config : this->ConfigsList) {
931
0
        checkAndAddOptions(features.Config[config]);
932
0
      }
933
0
    } else {
934
0
      checkAndAddOptions(features.Default);
935
0
    }
936
0
  }
937
938
  // Disable zstd if it is not supported
939
0
  {
940
0
    if (this->QtVersion.Major >= 6) {
941
0
      std::string const qtFeatureZSTD = "QT_FEATURE_zstd";
942
0
      if (this->GenTarget->Target->GetMakefile()->IsDefinitionSet(
943
0
            qtFeatureZSTD)) {
944
0
        auto const zstdDef =
945
0
          this->GenTarget->Target->GetMakefile()->GetSafeDefinition(
946
0
            qtFeatureZSTD);
947
0
        auto const zstdVal = cmValue(zstdDef);
948
0
        if (zstdVal.IsOff()) {
949
0
          auto const& kw = this->GlobalInitializer->kw();
950
0
          auto rccOptions =
951
0
            this->GenTarget->GetSafeProperty(kw.AUTORCC_OPTIONS);
952
0
          std::string const nozstd = "--no-zstd";
953
0
          if (rccOptions.find(nozstd) == std::string::npos) {
954
0
            rccOptions.append(";" + nozstd + ";");
955
0
          }
956
0
          this->GenTarget->Target->SetProperty(kw.AUTORCC_OPTIONS, rccOptions);
957
0
        }
958
0
      }
959
0
    }
960
0
  }
961
962
0
  return true;
963
0
}
964
965
bool cmQtAutoGenInitializer::InitScanFiles()
966
0
{
967
0
  cmake const* cm = this->Makefile->GetCMakeInstance();
968
0
  auto const& kw = this->GlobalInitializer->kw();
969
970
0
  auto makeMUFile = [this, &kw](cmSourceFile* sf, std::string const& fullPath,
971
0
                                std::vector<size_t> const& configs,
972
0
                                bool muIt) -> MUFileHandle {
973
0
    MUFileHandle muf = cm::make_unique<MUFile>();
974
0
    muf->FullPath = fullPath;
975
0
    muf->SF = sf;
976
0
    if (!configs.empty() && configs.size() != this->ConfigsList.size()) {
977
0
      muf->Configs = configs;
978
0
    }
979
0
    muf->Generated = sf->GetIsGenerated();
980
0
    bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN);
981
0
    muf->SkipMoc = this->Moc.Enabled &&
982
0
      (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOMOC));
983
0
    muf->SkipUic = this->Uic.Enabled &&
984
0
      (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC));
985
0
    if (muIt) {
986
0
      muf->MocIt = this->Moc.Enabled && !muf->SkipMoc;
987
0
      muf->UicIt = this->Uic.Enabled && !muf->SkipUic;
988
0
    }
989
0
    return muf;
990
0
  };
991
992
0
  auto addMUHeader = [this](MUFileHandle&& muf, cm::string_view extension) {
993
0
    cmSourceFile* sf = muf->SF;
994
0
    bool const muIt = (muf->MocIt || muf->UicIt);
995
0
    if (this->CMP0100Accept || (extension != "hh")) {
996
      // Accept
997
0
      if (muIt && muf->Generated) {
998
0
        this->AutogenTarget.FilesGenerated.emplace_back(muf.get());
999
0
      }
1000
0
      this->AutogenTarget.Headers.emplace(sf, std::move(muf));
1001
0
    } else if (muIt && this->CMP0100Warn) {
1002
      // Store file for warning message
1003
0
      this->AutogenTarget.CMP0100HeadersWarn.push_back(sf);
1004
0
    }
1005
0
  };
1006
1007
0
  auto addMUSource = [this](MUFileHandle&& muf) {
1008
0
    if ((muf->MocIt || muf->UicIt) && muf->Generated) {
1009
0
      this->AutogenTarget.FilesGenerated.emplace_back(muf.get());
1010
0
    }
1011
0
    this->AutogenTarget.Sources.emplace(muf->SF, std::move(muf));
1012
0
  };
1013
1014
0
  auto addMUModuleUnit = [this](MUFileHandle&& muf) {
1015
0
    if (muf->SkipMoc) {
1016
0
      return;
1017
0
    }
1018
    // AUTOUIC is not wired up for module units (the uic eval pass ignores
1019
    // the ModuleUnits collection), so don't carry a UicIt flag nothing acts
1020
    // on.
1021
0
    muf->UicIt = false;
1022
0
    this->AutogenTarget.ModuleUnits.emplace(muf->SF, std::move(muf));
1023
0
  };
1024
1025
  // Scan through target files
1026
0
  {
1027
    // Scan through target files
1028
0
    for (cmGeneratorTarget::AllConfigSource const& acs :
1029
0
         this->GenTarget->GetAllConfigSources()) {
1030
0
      std::string const& fullPath = acs.Source->GetFullPath();
1031
0
      std::string const& extLower =
1032
0
        cmSystemTools::LowerCase(acs.Source->GetExtension());
1033
1034
      // Register files that will be scanned by moc or uic
1035
0
      if (this->MocOrUicEnabled()) {
1036
        // Query one config only: file-set membership can differ per
1037
        // config, but a per-config module unit kind is not modeled here.
1038
0
        cmGeneratorFileSet const* fileSet =
1039
0
          this->GenTarget->GetFileSetForSource(this->ConfigDefault,
1040
0
                                               acs.Source);
1041
0
        if (fileSet &&
1042
0
            fileSet->GetType() == cm::FileSetMetadata::CXX_MODULES) {
1043
0
          addMUModuleUnit(makeMUFile(acs.Source, fullPath, acs.Configs, true));
1044
0
        } else if (cm->IsAHeaderExtension(extLower)) {
1045
0
          addMUHeader(makeMUFile(acs.Source, fullPath, acs.Configs, true),
1046
0
                      extLower);
1047
0
        } else if (cm->IsACLikeSourceExtension(extLower)) {
1048
0
          addMUSource(makeMUFile(acs.Source, fullPath, acs.Configs, true));
1049
0
        }
1050
0
      }
1051
1052
      // Register rcc enabled files
1053
0
      if (this->Rcc.Enabled) {
1054
0
        if ((extLower == kw.qrc) &&
1055
0
            !acs.Source->GetPropertyAsBool(kw.SKIP_AUTOGEN) &&
1056
0
            !acs.Source->GetPropertyAsBool(kw.SKIP_AUTORCC)) {
1057
          // Register qrc file
1058
0
          Qrc qrc;
1059
0
          qrc.QrcFile = fullPath;
1060
0
          qrc.QrcName =
1061
0
            cmSystemTools::GetFilenameWithoutLastExtension(qrc.QrcFile);
1062
0
          qrc.Generated = acs.Source->GetIsGenerated();
1063
          // RCC options
1064
0
          {
1065
0
            std::string const& opts =
1066
0
              acs.Source->GetSafeProperty(kw.AUTORCC_OPTIONS);
1067
0
            if (!opts.empty()) {
1068
0
              cmExpandList(opts, qrc.Options);
1069
0
            }
1070
0
          }
1071
0
          this->Rcc.Qrcs.push_back(std::move(qrc));
1072
0
        }
1073
0
      }
1074
0
    }
1075
0
  }
1076
  // cmGeneratorTarget::GetAllConfigSources computes the target's
1077
  // sources meta data cache. Clear it so that OBJECT library targets that
1078
  // are AUTOGEN initialized after this target get their added
1079
  // mocs_compilation.cpp source acknowledged by this target.
1080
0
  this->GenTarget->ClearSourcesCache();
1081
1082
  // For source files find additional headers and private headers
1083
0
  if (this->MocOrUicEnabled()) {
1084
    // Header search suffixes and extensions
1085
0
    static std::initializer_list<cm::string_view> const suffixes{ "", "_p" };
1086
0
    auto const& exts = cm->GetHeaderExtensions();
1087
    // Scan through sources
1088
0
    for (auto const& pair : this->AutogenTarget.Sources) {
1089
0
      MUFile const& muf = *pair.second;
1090
0
      if (muf.MocIt || muf.UicIt) {
1091
        // Search for the default header file and a private header
1092
0
        std::string const& srcFullPath = muf.SF->ResolveFullPath();
1093
0
        std::string const basePath = cmStrCat(
1094
0
          cmQtAutoGen::SubDirPrefix(srcFullPath),
1095
0
          cmSystemTools::GetFilenameWithoutLastExtension(srcFullPath));
1096
0
        for (auto const& suffix : suffixes) {
1097
0
          std::string const suffixedPath = cmStrCat(basePath, suffix);
1098
0
          for (auto const& ext : exts) {
1099
0
            std::string const fullPath = cmStrCat(suffixedPath, '.', ext);
1100
1101
0
            auto constexpr locationKind = cmSourceFileLocationKind::Known;
1102
0
            cmSourceFile* sf =
1103
0
              this->Makefile->GetSource(fullPath, locationKind);
1104
0
            if (sf) {
1105
              // Check if we know about this header already
1106
0
              if (cm::contains(this->AutogenTarget.Headers, sf)) {
1107
0
                continue;
1108
0
              }
1109
              // We only accept not-GENERATED files that do exist.
1110
0
              if (!sf->GetIsGenerated() &&
1111
0
                  !cmSystemTools::FileExists(fullPath)) {
1112
0
                continue;
1113
0
              }
1114
0
            } else if (cmSystemTools::FileExists(fullPath)) {
1115
              // Create a new source file for the existing file
1116
0
              sf = this->Makefile->CreateSource(fullPath, false, locationKind);
1117
0
            }
1118
1119
0
            if (sf) {
1120
0
              auto eMuf = makeMUFile(sf, fullPath, muf.Configs, true);
1121
              // Only process moc/uic when the parent is processed as well
1122
0
              if (!muf.MocIt) {
1123
0
                eMuf->MocIt = false;
1124
0
              }
1125
0
              if (!muf.UicIt) {
1126
0
                eMuf->UicIt = false;
1127
0
              }
1128
0
              addMUHeader(std::move(eMuf), ext);
1129
0
            }
1130
0
          }
1131
0
        }
1132
0
      }
1133
0
    }
1134
0
  }
1135
1136
  // Scan through all source files in the makefile to extract moc and uic
1137
  // parameters.  Historically we support non target source file parameters.
1138
  // The reason is that their file names might be discovered from source files
1139
  // at generation time.
1140
0
  if (this->MocOrUicEnabled()) {
1141
0
    for (auto const& sf : this->Makefile->GetSourceFiles()) {
1142
      // sf->GetExtension() is only valid after sf->ResolveFullPath() ...
1143
      // Since we're iterating over source files that might be not in the
1144
      // target we need to check for path errors (not existing files).
1145
0
      std::string pathError;
1146
0
      std::string const& fullPath = sf->ResolveFullPath(&pathError);
1147
0
      if (!pathError.empty() || fullPath.empty()) {
1148
0
        continue;
1149
0
      }
1150
0
      std::string const& extLower =
1151
0
        cmSystemTools::LowerCase(sf->GetExtension());
1152
1153
0
      if (cm->IsAHeaderExtension(extLower)) {
1154
0
        if (!cm::contains(this->AutogenTarget.Headers, sf.get())) {
1155
0
          auto muf = makeMUFile(sf.get(), fullPath, {}, false);
1156
0
          if (muf->SkipMoc || muf->SkipUic) {
1157
0
            addMUHeader(std::move(muf), extLower);
1158
0
          }
1159
0
        }
1160
0
      } else if (cm->IsACLikeSourceExtension(extLower)) {
1161
0
        if (!cm::contains(this->AutogenTarget.Sources, sf.get())) {
1162
0
          auto muf = makeMUFile(sf.get(), fullPath, {}, false);
1163
0
          if (muf->SkipMoc || muf->SkipUic) {
1164
0
            addMUSource(std::move(muf));
1165
0
          }
1166
0
        }
1167
0
      } else if (this->Uic.Enabled && (extLower == kw.ui)) {
1168
        // .ui file
1169
0
        bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN);
1170
0
        bool const skipUic =
1171
0
          (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC));
1172
0
        if (!skipUic) {
1173
          // Check if the .ui file has uic options
1174
0
          std::string const uicOpts = sf->GetSafeProperty(kw.AUTOUIC_OPTIONS);
1175
0
          if (uicOpts.empty()) {
1176
0
            this->Uic.UiFilesNoOptions.emplace_back(fullPath);
1177
0
          } else {
1178
0
            this->Uic.UiFilesWithOptions.emplace_back(
1179
0
              fullPath, std::move(cmList{ uicOpts }.data()));
1180
0
          }
1181
1182
0
          auto uiHeaderRelativePath = cmSystemTools::RelativePath(
1183
0
            this->LocalGen->GetCurrentSourceDirectory(),
1184
0
            cmSystemTools::GetFilenamePath(fullPath));
1185
1186
          // Avoid creating a path containing adjacent slashes
1187
0
          if (!uiHeaderRelativePath.empty() &&
1188
0
              uiHeaderRelativePath.back() != '/') {
1189
0
            uiHeaderRelativePath += '/';
1190
0
          }
1191
1192
0
          auto uiHeaderFilePath = cmStrCat(
1193
0
            '/', uiHeaderRelativePath, "ui_"_s,
1194
0
            cmSystemTools::GetFilenameWithoutLastExtension(fullPath), ".h"_s);
1195
1196
0
          ConfigString uiHeader;
1197
0
          std::string uiHeaderGenex;
1198
0
          this->ConfigFileNamesAndGenex(
1199
0
            uiHeader, uiHeaderGenex, cmStrCat(this->Dir.Build, "/include"_s),
1200
0
            uiHeaderFilePath);
1201
1202
0
          this->Uic.UiHeaders.emplace_back(uiHeader, uiHeaderGenex);
1203
0
        } else {
1204
          // Register skipped .ui file
1205
0
          this->Uic.SkipUi.insert(fullPath);
1206
0
        }
1207
0
      }
1208
0
    }
1209
0
  }
1210
1211
  // Process GENERATED sources and headers
1212
0
  if (this->MocOrUicEnabled() && !this->AutogenTarget.FilesGenerated.empty()) {
1213
0
    if (this->CMP0071Accept) {
1214
      // Let the autogen target depend on the GENERATED files
1215
0
      if (this->MultiConfig && !this->CrossConfig) {
1216
0
        for (MUFile const* muf : this->AutogenTarget.FilesGenerated) {
1217
0
          if (muf->Configs.empty()) {
1218
0
            this->AutogenTarget.DependFiles.insert(muf->FullPath);
1219
0
          } else {
1220
0
            for (size_t ci : muf->Configs) {
1221
0
              std::string const& config = this->ConfigsList[ci];
1222
0
              std::string const& pathWithConfig =
1223
0
                cmStrCat("$<$<CONFIG:", config, ">:", muf->FullPath, '>');
1224
0
              this->AutogenTarget.DependFiles.insert(pathWithConfig);
1225
0
            }
1226
0
          }
1227
0
        }
1228
0
      } else {
1229
0
        for (MUFile const* muf : this->AutogenTarget.FilesGenerated) {
1230
0
          this->AutogenTarget.DependFiles.insert(muf->FullPath);
1231
0
        }
1232
0
      }
1233
0
    } else if (this->CMP0071Warn) {
1234
0
      cm::string_view property;
1235
0
      if (this->Moc.Enabled && this->Uic.Enabled) {
1236
0
        property = "SKIP_AUTOGEN";
1237
0
      } else if (this->Moc.Enabled) {
1238
0
        property = "SKIP_AUTOMOC";
1239
0
      } else if (this->Uic.Enabled) {
1240
0
        property = "SKIP_AUTOUIC";
1241
0
      }
1242
0
      std::string files;
1243
0
      for (MUFile const* muf : this->AutogenTarget.FilesGenerated) {
1244
0
        files += cmStrCat("  ", Quoted(muf->FullPath), '\n');
1245
0
      }
1246
0
      this->Makefile->IssuePolicyWarning(
1247
0
        cmPolicies::CMP0071, {},
1248
0
        cmStrCat(
1249
0
          "For compatibility, CMake is excluding the GENERATED source "
1250
0
          "file(s):\n"_s,
1251
0
          files, "from processing by "_s,
1252
0
          cmQtAutoGen::Tools(this->Moc.Enabled, this->Uic.Enabled, false),
1253
0
          ".  If any of the files should be processed, set CMP0071 to NEW.  "
1254
0
          "If any of the files should not be processed, "
1255
0
          "explicitly exclude them by setting the source file property "_s,
1256
0
          property, ":\n  set_property(SOURCE file.h PROPERTY "_s, property,
1257
0
          " ON)"_s));
1258
0
    }
1259
0
  }
1260
1261
  // Generate CMP0100 warning
1262
0
  if (this->MocOrUicEnabled() &&
1263
0
      !this->AutogenTarget.CMP0100HeadersWarn.empty()) {
1264
0
    cm::string_view property;
1265
0
    if (this->Moc.Enabled && this->Uic.Enabled) {
1266
0
      property = "SKIP_AUTOGEN";
1267
0
    } else if (this->Moc.Enabled) {
1268
0
      property = "SKIP_AUTOMOC";
1269
0
    } else if (this->Uic.Enabled) {
1270
0
      property = "SKIP_AUTOUIC";
1271
0
    }
1272
0
    std::string files;
1273
0
    for (cmSourceFile const* sf : this->AutogenTarget.CMP0100HeadersWarn) {
1274
0
      files += cmStrCat("  ", Quoted(sf->GetFullPath()), '\n');
1275
0
    }
1276
0
    this->Makefile->IssuePolicyWarning(
1277
0
      cmPolicies::CMP0100, {},
1278
0
      cmStrCat(
1279
0
        "For compatibility, CMake is excluding the header file(s):\n"_s, files,
1280
0
        "from processing by "_s,
1281
0
        cmQtAutoGen::Tools(this->Moc.Enabled, this->Uic.Enabled, false),
1282
0
        ".  If any of the files should be processed, set CMP0100 to NEW.  "
1283
0
        "If any of the files should not be processed, "
1284
0
        "explicitly exclude them by setting the source file property "_s,
1285
0
        property, ":\n  set_property(SOURCE file.hh PROPERTY "_s, property,
1286
0
        " ON)"_s));
1287
0
  }
1288
1289
  // Process qrc files
1290
0
  if (!this->Rcc.Qrcs.empty()) {
1291
0
    bool const modernQt = (this->QtVersion.Major >= 5);
1292
    // Target rcc options
1293
0
    cmList const optionsTarget{ this->GenTarget->GetSafeProperty(
1294
0
      kw.AUTORCC_OPTIONS) };
1295
1296
    // Check if file name is unique
1297
0
    for (Qrc& qrc : this->Rcc.Qrcs) {
1298
0
      qrc.Unique = true;
1299
0
      for (Qrc const& qrc2 : this->Rcc.Qrcs) {
1300
0
        if ((&qrc != &qrc2) && (qrc.QrcName == qrc2.QrcName)) {
1301
0
          qrc.Unique = false;
1302
0
          break;
1303
0
        }
1304
0
      }
1305
0
    }
1306
    // Path checksum and file names
1307
0
    for (Qrc& qrc : this->Rcc.Qrcs) {
1308
      // Path checksum
1309
0
      qrc.QrcPathChecksum = this->PathCheckSum.getPart(qrc.QrcFile);
1310
      // Output file name
1311
0
      if (this->MultiConfig && !this->GlobalGen->IsXcode() &&
1312
0
          this->UseBetterGraph) {
1313
0
        this->ConfigFileNamesAndGenex(qrc.OutputFile, qrc.OutputFileGenex,
1314
0
                                      cmStrCat(this->Dir.Build, '/',
1315
0
                                               qrc.QrcPathChecksum, "/qrc_",
1316
0
                                               qrc.QrcName),
1317
0
                                      ".cpp"_s);
1318
0
      } else {
1319
        // For non-better-graph, all configs use the same file
1320
0
        std::string const outputFile =
1321
0
          cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum, "/qrc_",
1322
0
                   qrc.QrcName, ".cpp");
1323
0
        this->ConfigFileNameCommon(qrc.OutputFile, outputFile);
1324
0
        qrc.OutputFileGenex = outputFile;
1325
0
      }
1326
0
      std::string const base = cmStrCat(this->Dir.Info, "/AutoRcc_",
1327
0
                                        qrc.QrcName, '_', qrc.QrcPathChecksum);
1328
0
      qrc.LockFile = cmStrCat(base, "_Lock.lock");
1329
0
      qrc.InfoFile = cmStrCat(base, "_Info.json");
1330
0
      this->ConfigFileNames(qrc.SettingsFile, cmStrCat(base, "_Used"), ".txt");
1331
0
    }
1332
    // rcc options
1333
0
    for (Qrc& qrc : this->Rcc.Qrcs) {
1334
      // Target options
1335
0
      std::vector<std::string> opts = optionsTarget;
1336
      // Merge computed "-name XYZ" option
1337
0
      {
1338
0
        std::string name = qrc.QrcName;
1339
        // Replace '-' with '_'. The former is not valid for symbol names.
1340
0
        std::replace(name.begin(), name.end(), '-', '_');
1341
0
        if (!qrc.Unique) {
1342
0
          name += cmStrCat('_', qrc.QrcPathChecksum);
1343
0
        }
1344
0
        std::vector<std::string> nameOpts;
1345
0
        nameOpts.emplace_back("-name");
1346
0
        nameOpts.emplace_back(std::move(name));
1347
0
        RccMergeOptions(opts, nameOpts, modernQt);
1348
0
      }
1349
      // Merge file option
1350
0
      RccMergeOptions(opts, qrc.Options, modernQt);
1351
0
      qrc.Options = std::move(opts);
1352
0
    }
1353
    // rcc resources
1354
0
    for (Qrc& qrc : this->Rcc.Qrcs) {
1355
0
      if (!qrc.Generated) {
1356
0
        std::string error;
1357
0
        if (this->MultiConfig && this->UseBetterGraph) {
1358
0
          for (auto const& config : this->ConfigsList) {
1359
0
            RccLister const lister(
1360
0
              this->Rcc.Executable.Config[config],
1361
0
              this->Rcc.ExecutableFeatures.Config[config]->ListOptions);
1362
0
            if (!lister.list(qrc.QrcFile, qrc.Resources.Config[config],
1363
0
                             error)) {
1364
0
              cmSystemTools::Error(error);
1365
0
              return false;
1366
0
            }
1367
0
          }
1368
0
        } else {
1369
0
          RccLister const lister(
1370
0
            this->Rcc.Executable.Default,
1371
0
            this->Rcc.ExecutableFeatures.Default->ListOptions);
1372
0
          if (!lister.list(qrc.QrcFile, qrc.Resources.Default, error)) {
1373
0
            cmSystemTools::Error(error);
1374
0
            return false;
1375
0
          }
1376
0
        }
1377
0
      }
1378
0
    }
1379
0
  }
1380
1381
0
  return true;
1382
0
}
1383
1384
bool cmQtAutoGenInitializer::InitAutogenTarget()
1385
0
{
1386
  // Register info file as generated by CMake
1387
0
  this->Makefile->AddCMakeOutputFile(this->AutogenTarget.InfoFile);
1388
1389
  // Determine whether to use a depfile for the AUTOGEN target.
1390
0
  bool const useDepfile = [this]() -> bool {
1391
0
    auto const& gen = this->GlobalGen->GetName();
1392
0
    return this->QtVersion >= IntegerVersion(5, 15) &&
1393
0
      (gen.find("Ninja") != std::string::npos ||
1394
0
       gen.find("Make") != std::string::npos ||
1395
0
       gen.find("Visual Studio") != std::string::npos || gen == "Xcode");
1396
0
  }();
1397
1398
  // Under VS, attach the autogen custom command to the origin target instead
1399
  // of creating separate targets, to reduce the number of targets loaded into
1400
  // the IDE.  The dependencies of the origin target then provide the ordering
1401
  // that '_autogen_timestamp_deps' provides otherwise.  The conditions match
1402
  // those of the PRE_BUILD event below, so that the '_autogen' target keeps
1403
  // existing wherever it did before depfiles were enabled for VS.
1404
0
  bool const attachToOrigin = useDepfile &&
1405
0
    this->AutogenTarget.DependFiles.empty() &&
1406
0
    !this->AutogenTarget.GlobalTarget && this->GlobalGen->IsVisualStudio();
1407
1408
  // Files provided by the autogen target
1409
0
  std::vector<std::string> autogenByproducts;
1410
0
  std::vector<std::string> timestampByproducts;
1411
0
  if (this->Moc.Enabled) {
1412
0
    this->AddGeneratedSource(this->Moc.CompilationFile, this->Moc, true);
1413
0
    if (useDepfile) {
1414
0
      if (this->CrossConfig &&
1415
0
          this->GlobalGen->GetName().find("Ninja") != std::string::npos &&
1416
0
          !this->UseBetterGraph) {
1417
        // Make all mocs_compilation_<CONFIG>.cpp files byproducts of the
1418
        // ${target}_autogen/timestamp custom command.
1419
        // We cannot just use Moc.CompilationFileGenex here, because that
1420
        // custom command runs cmake_autogen for each configuration.
1421
0
        for (auto const& p : this->Moc.CompilationFile.Config) {
1422
0
          timestampByproducts.push_back(p.second);
1423
0
        }
1424
0
      } else {
1425
0
        timestampByproducts.push_back(this->Moc.CompilationFileGenex);
1426
0
      }
1427
0
    } else {
1428
0
      autogenByproducts.push_back(this->Moc.CompilationFileGenex);
1429
0
    }
1430
1431
    // Module-unit moc outputs are implementation units ("module M;") that
1432
    // are compiled individually rather than folded into
1433
    // mocs_compilation.cpp, and must be scanned so dyndep can order them
1434
    // after the module's BMI.
1435
    // Sort by path so GetMocBuildPath's dedup-suffix assignment and the
1436
    // AddSource order below do not depend on unordered_map hash order.
1437
    // moc can only process C++ module units since Qt 6.13.  With older Qt
1438
    // there is no moc output to compile, and cmQtAutoMocUic reports any
1439
    // meta-object macro found in such a unit instead.
1440
0
    std::vector<MUFile*> moduleUnits;
1441
0
    if (this->QtVersion >= IntegerVersion(6, 13)) {
1442
0
      moduleUnits.reserve(this->AutogenTarget.ModuleUnits.size());
1443
0
      for (auto const& pair : this->AutogenTarget.ModuleUnits) {
1444
0
        moduleUnits.push_back(pair.second.get());
1445
0
      }
1446
0
      std::sort(moduleUnits.begin(), moduleUnits.end(),
1447
0
                [](MUFile const* a, MUFile const* b) {
1448
0
                  return (a->FullPath < b->FullPath);
1449
0
                });
1450
0
    }
1451
0
    for (MUFile* mufPtr : moduleUnits) {
1452
0
      MUFile& muf = *mufPtr;
1453
0
      if (!muf.MocIt) {
1454
0
        continue;
1455
0
      }
1456
0
      std::string const& mocBuildPath = this->GetMocBuildPath(muf);
1457
0
      if (!this->MultiConfig || this->GlobalGen->IsXcode()) {
1458
0
        std::string const outPath =
1459
0
          cmStrCat(this->Dir.Include.Default, '/', mocBuildPath);
1460
0
        cmSourceFile* sf = this->RegisterGeneratedSource(outPath, true);
1461
        // A PCH force-include would inject declarations ahead of the
1462
        // module implementation unit's "module M;", which may only be
1463
        // preceded by comments and preprocessor directives.
1464
0
        sf->SetProperty("SKIP_PRECOMPILE_HEADERS", "ON");
1465
0
        this->GenTarget->AddSource(outPath);
1466
        // Declare as a byproduct so Ninja re-stats it after autogen reruns.
1467
0
        if (useDepfile) {
1468
0
          timestampByproducts.push_back(outPath);
1469
0
        } else {
1470
0
          autogenByproducts.push_back(outPath);
1471
0
        }
1472
0
      } else {
1473
0
        for (auto const& cfg : this->ConfigsList) {
1474
0
          std::string const outPath =
1475
0
            cmStrCat(this->Dir.Include.Config.at(cfg), '/', mocBuildPath);
1476
0
          cmSourceFile* sf = this->RegisterGeneratedSource(outPath, true);
1477
          // A PCH force-include would inject declarations ahead of the
1478
          // module implementation unit's "module M;", which may only be
1479
          // preceded by comments and preprocessor directives.
1480
0
          sf->SetProperty("SKIP_PRECOMPILE_HEADERS", "ON");
1481
0
          this->GenTarget->AddSource(
1482
0
            cmStrCat("$<$<CONFIG:"_s, cfg, ">:"_s, outPath, ">"_s));
1483
          // Declare as a byproduct so Ninja re-stats it after autogen reruns.
1484
0
          if (useDepfile) {
1485
0
            timestampByproducts.push_back(outPath);
1486
0
          } else {
1487
0
            autogenByproducts.push_back(outPath);
1488
0
          }
1489
0
        }
1490
0
      }
1491
0
    }
1492
0
  }
1493
1494
0
  if (this->Uic.Enabled) {
1495
0
    for (auto const& file : this->Uic.UiHeaders) {
1496
0
      this->AddGeneratedSource(file.first, this->Uic);
1497
0
      if (!this->GlobalGen->IsFastbuild()) {
1498
0
        autogenByproducts.push_back(file.second);
1499
0
      }
1500
0
    }
1501
0
  }
1502
1503
0
  if (attachToOrigin) {
1504
    // Without an autogen target the timestamp command provides all byproducts.
1505
0
    cm::append(timestampByproducts, autogenByproducts);
1506
0
    autogenByproducts.clear();
1507
0
  }
1508
1509
  // Compose target comment
1510
0
  std::string autogenComment;
1511
0
  {
1512
0
    std::string tools;
1513
0
    if (this->Moc.Enabled) {
1514
0
      tools += "MOC";
1515
0
    }
1516
0
    if (this->Uic.Enabled) {
1517
0
      if (!tools.empty()) {
1518
0
        tools += " and ";
1519
0
      }
1520
0
      tools += "UIC";
1521
0
    }
1522
0
    autogenComment = cmStrCat("Automatic ", tools, " for target ",
1523
0
                              this->GenTarget->GetName());
1524
0
  }
1525
1526
  // Compose command lines
1527
  // FIXME: Take advantage of our per-config mocs_compilation_$<CONFIG>.cpp
1528
  // instead of fiddling with the include directories
1529
1530
0
  bool constexpr stdPipesUTF8 = true;
1531
0
  cmCustomCommandLines commandLines;
1532
0
  AddCMakeProcessToCommandLines(this->AutogenTarget.InfoFile, "cmake_autogen",
1533
0
                                commandLines);
1534
1535
  // Use PRE_BUILD on demand
1536
0
  bool usePRE_BUILD = false;
1537
0
  if (this->GlobalGen->GetName().find("Visual Studio") != std::string::npos) {
1538
    // Under VS use a PRE_BUILD event instead of a separate target to
1539
    // reduce the number of targets loaded into the IDE.
1540
    // This also works around a VS 11 bug that may skip updating the target:
1541
    //  https://connect.microsoft.com/VisualStudio/feedback/details/769495
1542
0
    usePRE_BUILD = true;
1543
0
  }
1544
  // Disable PRE_BUILD in some cases
1545
0
  if (usePRE_BUILD) {
1546
    // Cannot use PRE_BUILD with file depends
1547
0
    if (!this->AutogenTarget.DependFiles.empty()) {
1548
0
      usePRE_BUILD = false;
1549
0
    }
1550
    // Cannot use PRE_BUILD when a global autogen target is in place
1551
0
    if (this->AutogenTarget.GlobalTarget) {
1552
0
      usePRE_BUILD = false;
1553
0
    }
1554
    // Cannot use PRE_BUILD with depfiles
1555
0
    if (useDepfile) {
1556
0
      usePRE_BUILD = false;
1557
0
    }
1558
0
  }
1559
  // Create the autogen target/command
1560
0
  if (usePRE_BUILD) {
1561
    // Add additional autogen target dependencies to origin target
1562
0
    for (cmTarget const* depTarget : this->AutogenTarget.DependTargets) {
1563
0
      this->GenTarget->Target->AddUtility(depTarget->GetName(), false,
1564
0
                                          this->Makefile);
1565
0
    }
1566
1567
0
    if (!this->Uic.UiFilesNoOptions.empty() ||
1568
0
        !this->Uic.UiFilesWithOptions.empty()) {
1569
      // Add a generated timestamp file
1570
0
      ConfigString timestampFile;
1571
0
      std::string timestampFileGenex;
1572
0
      ConfigFileNamesAndGenex(timestampFile, timestampFileGenex,
1573
0
                              cmStrCat(this->Dir.Build, "/autouic"_s),
1574
0
                              ".stamp"_s);
1575
0
      this->AddGeneratedSource(timestampFile, this->Uic);
1576
1577
      // Add a step in the pre-build command to touch the timestamp file
1578
0
      commandLines.push_back(
1579
0
        cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", "touch",
1580
0
                            timestampFileGenex }));
1581
1582
      // UIC needs to be re-run if any of the known UI files change or the
1583
      // executable itself has been updated
1584
0
      auto uicDependencies = this->Uic.UiFilesNoOptions;
1585
0
      for (auto const& uiFile : this->Uic.UiFilesWithOptions) {
1586
0
        uicDependencies.push_back(uiFile.first);
1587
0
      }
1588
0
      AddAutogenExecutableToDependencies(this->Uic, uicDependencies);
1589
1590
      // Add a rule file to cause the target to build if a dependency has
1591
      // changed, which will trigger the pre-build command to run autogen
1592
0
      auto cc = cm::make_unique<cmCustomCommand>();
1593
0
      cc->SetOutputs(timestampFileGenex);
1594
0
      cc->SetDepends(uicDependencies);
1595
0
      cc->SetComment("");
1596
0
      cc->SetWorkingDirectory(this->Dir.Work.c_str());
1597
0
      cc->SetEscapeOldStyle(false);
1598
0
      cc->SetStdPipesUTF8(stdPipesUTF8);
1599
0
      this->LocalGen->AddCustomCommandToOutput(std::move(cc));
1600
0
    }
1601
1602
    // Add the pre-build command directly to bypass the OBJECT_LIBRARY
1603
    // rejection in cmMakefile::AddCustomCommandToTarget because we know
1604
    // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case.
1605
    //
1606
    // PRE_BUILD does not support file dependencies!
1607
0
    cmCustomCommand cc;
1608
0
    cc.SetByproducts(autogenByproducts);
1609
0
    cc.SetCommandLines(commandLines);
1610
0
    cc.SetComment(autogenComment.c_str());
1611
0
    cc.SetBacktrace(this->Makefile->GetBacktrace());
1612
0
    cc.SetWorkingDirectory(this->Dir.Work.c_str());
1613
0
    cc.SetStdPipesUTF8(stdPipesUTF8);
1614
0
    cc.SetEscapeOldStyle(false);
1615
0
    cc.SetEscapeAllowMakeVars(true);
1616
0
    this->GenTarget->Target->AddPreBuildCommand(std::move(cc));
1617
0
  } else {
1618
1619
    // Add link library target dependencies to the autogen target
1620
    // dependencies.  Not needed when attaching to the origin target, which
1621
    // already depends on its own link libraries.
1622
0
    if (this->AutogenTarget.DependOrigin && !attachToOrigin) {
1623
      // add_dependencies/addUtility do not support generator expressions.
1624
      // We depend only on the libraries found in all configs therefore.
1625
0
      std::map<cmGeneratorTarget const*, std::size_t> targetsPartOfAllConfigs;
1626
0
      for (std::string const& config : this->ConfigsList) {
1627
        // The same target might appear multiple times in a config, but we
1628
        // should only count it once.
1629
0
        std::set<cmGeneratorTarget const*> seenTargets;
1630
0
        cmLinkImplementationLibraries const* libs =
1631
0
          this->GenTarget->GetLinkImplementationLibraries(
1632
0
            config, cmGeneratorTarget::UseTo::Link);
1633
0
        if (libs) {
1634
0
          for (cmLinkItem const& item : libs->Libraries) {
1635
0
            cmGeneratorTarget const* libTarget = item.Target;
1636
0
            if (libTarget &&
1637
0
                !StaticLibraryCycle(this->GenTarget, libTarget, config) &&
1638
0
                seenTargets.insert(libTarget).second) {
1639
              // Increment target config count
1640
0
              targetsPartOfAllConfigs[libTarget]++;
1641
0
            }
1642
0
          }
1643
0
        }
1644
0
      }
1645
0
      for (auto const& item : targetsPartOfAllConfigs) {
1646
0
        if (item.second == this->ConfigsList.size()) {
1647
0
          this->AutogenTarget.DependTargets.insert(item.first->Target);
1648
0
        }
1649
0
      }
1650
0
    }
1651
1652
0
    cmTarget* timestampTarget = nullptr;
1653
0
    std::vector<std::string> dependencies(
1654
0
      this->AutogenTarget.DependFiles.begin(),
1655
0
      this->AutogenTarget.DependFiles.end());
1656
0
    if (useDepfile) {
1657
      // Create a custom command that generates a timestamp file and
1658
      // has a depfile assigned. The depfile is created by JobDepFilesMergeT.
1659
0
      if (!attachToOrigin) {
1660
        // Also create an additional '_autogen_timestamp_deps' that the custom
1661
        // command will depend on. It will have no sources or commands to
1662
        // execute, but it will have dependencies that would originally be
1663
        // assigned to the pre-Qt 5.15 'autogen' target. These dependencies
1664
        // will serve as a list of order-only dependencies for the custom
1665
        // command, without forcing the custom command to re-execute.
1666
        //
1667
        // The dependency tree would then look like
1668
        // '_autogen_timestamp_deps (order-only)' <- '/timestamp' file <-
1669
        // '_autogen' target.
1670
0
        auto const timestampTargetName =
1671
0
          cmStrCat(this->GenTarget->GetName(), "_autogen_timestamp_deps");
1672
1673
0
        auto cc = cm::make_unique<cmCustomCommand>();
1674
0
        cc->SetWorkingDirectory(this->Dir.Work.c_str());
1675
0
        cc->SetDepends(dependencies);
1676
0
        cc->SetEscapeOldStyle(false);
1677
0
        timestampTarget = this->LocalGen->AddUtilityCommand(
1678
0
          timestampTargetName, true, std::move(cc));
1679
1680
0
        this->LocalGen->AddGeneratorTarget(
1681
0
          cm::make_unique<cmGeneratorTarget>(timestampTarget, this->LocalGen));
1682
1683
        // Set FOLDER property on the timestamp target, so it appears in the
1684
        // appropriate folder in an IDE or in the file api.
1685
0
        if (!this->TargetsFolder.empty()) {
1686
0
          timestampTarget->SetProperty("FOLDER", this->TargetsFolder);
1687
0
        }
1688
1689
        // Make '/timestamp' file depend on '_autogen_timestamp_deps'.
1690
0
        dependencies.clear();
1691
0
        dependencies.push_back(timestampTargetName);
1692
0
      }
1693
1694
      // Make '/timestamp' file depend on the moc and uic executables
1695
      // (whichever are enabled).
1696
0
      AddAutogenExecutableToDependencies(this->Moc, dependencies);
1697
0
      AddAutogenExecutableToDependencies(this->Uic, dependencies);
1698
0
      std::string outputFile;
1699
0
      std::string depFile;
1700
      // Create the custom command that outputs the timestamp file.
1701
0
      if (this->MultiConfig && this->UseBetterGraph) {
1702
        // create timestamp file with $<CONFIG> in the name so that
1703
        // every cmake_autogen target has its own timestamp file
1704
0
        std::string const configView = "$<CONFIG>";
1705
0
        std::string const timestampFileWithoutConfig = "timestamp_";
1706
0
        std::string const depFileWithoutConfig =
1707
0
          cmStrCat(this->Dir.Build, "/deps_");
1708
0
        std::string const timestampFileName =
1709
0
          timestampFileWithoutConfig + configView;
1710
0
        outputFile = cmStrCat(this->Dir.Build, '/', timestampFileName);
1711
0
        auto const depFileWithConfig =
1712
0
          cmStrCat(depFileWithoutConfig, configView);
1713
0
        depFile = depFileWithConfig;
1714
0
        commandLines.push_back(cmMakeCommandLine(
1715
0
          { cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile }));
1716
1717
0
        ConfigString outputFileWithConfig;
1718
0
        for (std::string const& config : this->ConfigsList) {
1719
0
          auto tempTimestampFileName = timestampFileWithoutConfig + config;
1720
0
          auto tempDepFile = depFileWithoutConfig + config;
1721
0
          outputFileWithConfig.Config[config] =
1722
0
            cmStrCat(this->Dir.Build, '/', tempTimestampFileName);
1723
0
          this->AutogenTarget.DepFileRuleName.Config[config] =
1724
0
            cmStrCat(this->Dir.RelativeBuild, '/', tempTimestampFileName);
1725
0
          this->AutogenTarget.DepFile.Config[config] = tempDepFile;
1726
0
        }
1727
0
        this->AddGeneratedSource(outputFileWithConfig, this->Moc);
1728
0
      } else {
1729
0
        cm::string_view const timestampFileName = "timestamp";
1730
0
        outputFile = cmStrCat(this->Dir.Build, '/', timestampFileName);
1731
0
        this->AutogenTarget.DepFile.Default =
1732
0
          cmStrCat(this->Dir.Build, "/deps");
1733
0
        depFile = this->AutogenTarget.DepFile.Default;
1734
0
        this->AutogenTarget.DepFileRuleName.Default =
1735
0
          cmStrCat(this->Dir.RelativeBuild, '/', timestampFileName);
1736
0
        commandLines.push_back(cmMakeCommandLine(
1737
0
          { cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile }));
1738
0
        this->AddGeneratedSource(outputFile, this->Moc);
1739
0
      }
1740
0
      auto cc = cm::make_unique<cmCustomCommand>();
1741
0
      cc->SetOutputs(outputFile);
1742
0
      cc->SetByproducts(timestampByproducts);
1743
0
      cc->SetDepends(dependencies);
1744
0
      cc->SetCommandLines(commandLines);
1745
0
      cc->SetComment(autogenComment.c_str());
1746
0
      cc->SetWorkingDirectory(this->Dir.Work.c_str());
1747
0
      cc->SetEscapeOldStyle(false);
1748
0
      cc->SetDepfile(depFile);
1749
0
      cc->SetStdPipesUTF8(stdPipesUTF8);
1750
0
      this->LocalGen->AddCustomCommandToOutput(std::move(cc));
1751
0
      dependencies.clear();
1752
0
      dependencies.emplace_back(std::move(outputFile));
1753
0
      commandLines.clear();
1754
0
      autogenComment.clear();
1755
0
    }
1756
1757
0
    if (attachToOrigin) {
1758
      // Add additional autogen target dependencies to the origin target
1759
0
      for (cmTarget const* depTarget : this->AutogenTarget.DependTargets) {
1760
0
        this->GenTarget->Target->AddUtility(depTarget->GetName(), false,
1761
0
                                            this->Makefile);
1762
0
      }
1763
0
    } else {
1764
      // Create autogen target
1765
0
      auto cc = cm::make_unique<cmCustomCommand>();
1766
0
      cc->SetWorkingDirectory(this->Dir.Work.c_str());
1767
0
      cc->SetByproducts(autogenByproducts);
1768
0
      cc->SetDepends(dependencies);
1769
0
      cc->SetCommandLines(commandLines);
1770
0
      cc->SetEscapeOldStyle(false);
1771
0
      cc->SetComment(autogenComment.c_str());
1772
0
      cmTarget* autogenTarget = this->LocalGen->AddUtilityCommand(
1773
0
        this->AutogenTarget.Name, true, std::move(cc));
1774
      // Create autogen generator target
1775
0
      this->LocalGen->AddGeneratorTarget(
1776
0
        cm::make_unique<cmGeneratorTarget>(autogenTarget, this->LocalGen));
1777
1778
      // Order the autogen target(s) just before the original target.
1779
0
      cmTarget* orderTarget =
1780
0
        timestampTarget ? timestampTarget : autogenTarget;
1781
      // Forward origin utilities to autogen target
1782
0
      if (this->AutogenTarget.DependOrigin) {
1783
0
        for (BT<std::pair<std::string, bool>> const& depName :
1784
0
             this->GenTarget->GetUtilities()) {
1785
0
          orderTarget->AddUtility(depName.Value.first, false, this->Makefile);
1786
0
        }
1787
0
      }
1788
1789
      // Add additional autogen target dependencies to autogen target
1790
0
      for (cmTarget const* depTarget : this->AutogenTarget.DependTargets) {
1791
0
        orderTarget->AddUtility(depTarget->GetName(), false, this->Makefile);
1792
0
      }
1793
1794
      // Set FOLDER property in autogen target
1795
0
      if (!this->TargetsFolder.empty()) {
1796
0
        autogenTarget->SetProperty("FOLDER", this->TargetsFolder);
1797
0
      }
1798
1799
      // Add autogen target to the origin target dependencies
1800
0
      this->GenTarget->Target->AddUtility(this->AutogenTarget.Name, false,
1801
0
                                          this->Makefile);
1802
1803
      // Add autogen target to the global autogen target dependencies
1804
0
      if (this->AutogenTarget.GlobalTarget) {
1805
0
        this->GlobalInitializer->AddToGlobalAutoGen(this->LocalGen,
1806
0
                                                    this->AutogenTarget.Name);
1807
0
      }
1808
0
    }
1809
0
  }
1810
1811
0
  return true;
1812
0
}
1813
1814
void cmQtAutoGenInitializer::AddCMakeProcessToCommandLines(
1815
  std::string const& infoFile, std::string const& processName,
1816
  cmCustomCommandLines& commandLines)
1817
0
{
1818
0
  std::vector<std::string> autogenConfigs;
1819
0
  this->GlobalGen->GetQtAutoGenConfigs(autogenConfigs);
1820
0
  if (this->CrossConfig && this->UseBetterGraph) {
1821
0
    commandLines.push_back(cmMakeCommandLine(
1822
0
      { cmSystemTools::GetCMakeCommand(), "-E", processName, infoFile,
1823
0
        "$<CONFIG>", "$<COMMAND_CONFIG:$<CONFIG>>" }));
1824
0
  } else if ((this->MultiConfig && this->GlobalGen->IsXcode()) ||
1825
0
             this->CrossConfig) {
1826
0
    auto const& configs =
1827
0
      processName == "cmake_autorcc" ? this->ConfigsList : autogenConfigs;
1828
0
    for (std::string const& config : configs) {
1829
0
      commandLines.push_back(
1830
0
        cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E",
1831
0
                            processName, infoFile, config }));
1832
0
    }
1833
0
  } else {
1834
0
    std::string autoInfoFileConfig;
1835
0
    if (this->MultiConfig) {
1836
0
      autoInfoFileConfig = "$<CONFIG>";
1837
0
    } else {
1838
0
      autoInfoFileConfig = autogenConfigs[0];
1839
0
    }
1840
0
    commandLines.push_back(
1841
0
      cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", processName,
1842
0
                          infoFile, autoInfoFileConfig }));
1843
0
  }
1844
0
}
1845
1846
bool cmQtAutoGenInitializer::InitRccTargets()
1847
0
{
1848
0
  for (Qrc const& qrc : this->Rcc.Qrcs) {
1849
    // Register info file as generated by CMake
1850
0
    this->Makefile->AddCMakeOutputFile(qrc.InfoFile);
1851
    // Register file at target
1852
0
    this->AddGeneratedSource(qrc.OutputFile, this->Rcc);
1853
1854
    // Set SKIP_UNITY_BUILD_INCLUSION property on generated source(s)
1855
0
    auto setSkipUnity = [this](std::string const& path) {
1856
0
      if (cmSourceFile* sf = this->Makefile->GetSource(path)) {
1857
0
        sf->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "On");
1858
0
      }
1859
0
    };
1860
0
    if (!this->MultiConfig || this->GlobalGen->IsXcode()) {
1861
0
      setSkipUnity(qrc.OutputFile.Default);
1862
0
    } else {
1863
0
      for (auto const& p : qrc.OutputFile.Config) {
1864
0
        setSkipUnity(p.second);
1865
0
      }
1866
0
    }
1867
1868
0
    std::vector<std::string> ccOutput{ qrc.OutputFileGenex };
1869
1870
    // Add the .qrc and info file to the custom command dependencies
1871
0
    std::vector<std::string> ccDepends{ qrc.QrcFile, qrc.InfoFile };
1872
1873
0
    cmCustomCommandLines commandLines;
1874
0
    AddCMakeProcessToCommandLines(qrc.InfoFile, "cmake_autorcc", commandLines);
1875
1876
0
    std::string const ccComment =
1877
0
      cmStrCat("Automatic RCC for ",
1878
0
               FileProjectRelativePath(this->Makefile, qrc.QrcFile));
1879
1880
0
    auto cc = cm::make_unique<cmCustomCommand>();
1881
0
    cc->SetWorkingDirectory(this->Dir.Work.c_str());
1882
0
    cc->SetCommandLines(commandLines);
1883
0
    cc->SetComment(ccComment.c_str());
1884
0
    cc->SetStdPipesUTF8(true);
1885
1886
0
    if (qrc.Generated || this->Rcc.GlobalTarget) {
1887
      // Create custom rcc target
1888
0
      std::string ccName;
1889
0
      {
1890
0
        ccName = cmStrCat(this->GenTarget->GetName(), "_arcc_", qrc.QrcName);
1891
0
        if (!qrc.Unique) {
1892
0
          ccName += cmStrCat('_', qrc.QrcPathChecksum);
1893
0
        }
1894
1895
0
        cc->SetByproducts(ccOutput);
1896
0
        cc->SetDepends(ccDepends);
1897
0
        cc->SetEscapeOldStyle(false);
1898
0
        cmTarget* autoRccTarget =
1899
0
          this->LocalGen->AddUtilityCommand(ccName, true, std::move(cc));
1900
1901
        // Create autogen generator target
1902
0
        this->LocalGen->AddGeneratorTarget(
1903
0
          cm::make_unique<cmGeneratorTarget>(autoRccTarget, this->LocalGen));
1904
1905
        // Set FOLDER property in autogen target
1906
0
        if (!this->TargetsFolder.empty()) {
1907
0
          autoRccTarget->SetProperty("FOLDER", this->TargetsFolder);
1908
0
        }
1909
0
        if (!this->Rcc.ExecutableTargetName.empty()) {
1910
0
          autoRccTarget->AddUtility(this->Rcc.ExecutableTargetName, false,
1911
0
                                    this->Makefile);
1912
0
        }
1913
0
      }
1914
      // Add autogen target to the origin target dependencies
1915
0
      this->GenTarget->Target->AddUtility(ccName, false, this->Makefile);
1916
1917
      // Add autogen target to the global autogen target dependencies
1918
0
      if (this->Rcc.GlobalTarget) {
1919
0
        this->GlobalInitializer->AddToGlobalAutoRcc(this->LocalGen, ccName);
1920
0
      }
1921
0
    } else {
1922
      // Create custom rcc command
1923
0
      {
1924
        // Add the resource files to the dependencies
1925
0
        if (this->MultiConfig && this->UseBetterGraph) {
1926
0
          for (auto const& config : this->ConfigsList) {
1927
            // Add resource file to the custom command dependencies
1928
0
            auto resourceFilesWithConfig = cmStrCat(
1929
0
              "$<$<CONFIG:", config,
1930
0
              ">:", cmList{ qrc.Resources.Config.at(config) }.to_string(),
1931
0
              '>');
1932
0
            ccDepends.emplace_back(std::move(resourceFilesWithConfig));
1933
0
          }
1934
0
        } else {
1935
0
          for (std::string const& fileName : qrc.Resources.Default) {
1936
            // Add resource file to the custom command dependencies
1937
0
            ccDepends.push_back(fileName);
1938
0
          }
1939
0
        }
1940
1941
0
        if (!this->Rcc.ExecutableTargetName.empty()) {
1942
0
          ccDepends.push_back(this->Rcc.ExecutableTargetName);
1943
0
        }
1944
1945
0
        AddAutogenExecutableToDependencies(this->Rcc, ccDepends);
1946
1947
0
        cc->SetOutputs(ccOutput);
1948
0
        cc->SetDepends(ccDepends);
1949
0
        this->LocalGen->AddCustomCommandToOutput(std::move(cc));
1950
0
      }
1951
      // Reconfigure when .qrc file changes
1952
0
      this->Makefile->AddCMakeDependFile(qrc.QrcFile);
1953
0
    }
1954
0
  }
1955
1956
0
  return true;
1957
0
}
1958
1959
bool cmQtAutoGenInitializer::SetupCustomTargets()
1960
0
{
1961
  // Create info directory on demand
1962
0
  if (!cmSystemTools::MakeDirectory(this->Dir.Info)) {
1963
0
    cmSystemTools::Error(cmStrCat("AutoGen: Could not create directory: ",
1964
0
                                  Quoted(this->Dir.Info)));
1965
0
    return false;
1966
0
  }
1967
1968
  // Generate autogen target info file
1969
0
  if (this->MocOrUicEnabled()) {
1970
    // Write autogen target info files
1971
0
    if (!this->SetupWriteAutogenInfo()) {
1972
0
      return false;
1973
0
    }
1974
0
  }
1975
1976
  // Write AUTORCC info files
1977
0
  return !this->Rcc.Enabled || this->SetupWriteRccInfo();
1978
0
}
1979
1980
bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
1981
0
{
1982
  // Utility lambdas
1983
0
  auto MfDef = [this](std::string const& key) {
1984
0
    return this->Makefile->GetSafeDefinition(key);
1985
0
  };
1986
1987
  // Filtered headers and sources
1988
0
  std::set<std::string> moc_skip;
1989
0
  std::set<std::string> uic_skip;
1990
0
  std::vector<MUFile const*> headers;
1991
0
  std::vector<MUFile const*> sources;
1992
0
  std::vector<MUFile const*> moduleUnits;
1993
1994
  // Filter headers
1995
0
  {
1996
0
    headers.reserve(this->AutogenTarget.Headers.size());
1997
0
    for (auto const& pair : this->AutogenTarget.Headers) {
1998
0
      MUFile const* const muf = pair.second.get();
1999
0
      if (muf->SkipMoc) {
2000
0
        moc_skip.insert(muf->FullPath);
2001
0
      }
2002
0
      if (muf->SkipUic) {
2003
0
        uic_skip.insert(muf->FullPath);
2004
0
      }
2005
0
      if (muf->Generated && !this->CMP0071Accept) {
2006
0
        continue;
2007
0
      }
2008
0
      if (muf->MocIt || muf->UicIt) {
2009
0
        headers.emplace_back(muf);
2010
0
      }
2011
0
    }
2012
0
    std::sort(headers.begin(), headers.end(),
2013
0
              [](MUFile const* a, MUFile const* b) {
2014
0
                return (a->FullPath < b->FullPath);
2015
0
              });
2016
0
  }
2017
2018
  // Filter sources
2019
0
  {
2020
0
    sources.reserve(this->AutogenTarget.Sources.size());
2021
0
    for (auto const& pair : this->AutogenTarget.Sources) {
2022
0
      MUFile const* const muf = pair.second.get();
2023
0
      if (muf->Generated && !this->CMP0071Accept) {
2024
0
        continue;
2025
0
      }
2026
0
      if (muf->SkipMoc) {
2027
0
        moc_skip.insert(muf->FullPath);
2028
0
      }
2029
0
      if (muf->SkipUic) {
2030
0
        uic_skip.insert(muf->FullPath);
2031
0
      }
2032
0
      if (muf->MocIt || muf->UicIt) {
2033
0
        sources.emplace_back(muf);
2034
0
      }
2035
0
    }
2036
0
    std::sort(sources.begin(), sources.end(),
2037
0
              [](MUFile const* a, MUFile const* b) {
2038
0
                return (a->FullPath < b->FullPath);
2039
0
              });
2040
0
  }
2041
2042
  // Filter module units
2043
0
  {
2044
0
    moduleUnits.reserve(this->AutogenTarget.ModuleUnits.size());
2045
0
    for (auto const& pair : this->AutogenTarget.ModuleUnits) {
2046
0
      MUFile const* const muf = pair.second.get();
2047
0
      if (muf->MocIt) {
2048
0
        moduleUnits.emplace_back(muf);
2049
0
      }
2050
0
    }
2051
0
    std::sort(moduleUnits.begin(), moduleUnits.end(),
2052
0
              [](MUFile const* a, MUFile const* b) {
2053
0
                return (a->FullPath < b->FullPath);
2054
0
              });
2055
0
  }
2056
2057
  // Info writer
2058
0
  InfoWriter info;
2059
2060
  // General
2061
0
  info.SetBool("MULTI_CONFIG", this->MultiConfig);
2062
0
  info.SetBool("CROSS_CONFIG", this->CrossConfig);
2063
0
  info.SetBool("USE_BETTER_GRAPH", this->UseBetterGraph);
2064
0
  info.SetUInt("PARALLEL", this->AutogenTarget.Parallel);
2065
#ifdef _WIN32
2066
  info.SetUInt("AUTOGEN_COMMAND_LINE_LENGTH_MAX",
2067
               this->AutogenTarget.MaxCommandLineLength);
2068
#endif
2069
0
  info.SetUInt("VERBOSITY", this->Verbosity);
2070
2071
  // Directories
2072
0
  info.Set("CMAKE_SOURCE_DIR", MfDef("CMAKE_SOURCE_DIR"));
2073
0
  info.Set("CMAKE_BINARY_DIR", MfDef("CMAKE_BINARY_DIR"));
2074
0
  info.Set("CMAKE_CURRENT_SOURCE_DIR", MfDef("CMAKE_CURRENT_SOURCE_DIR"));
2075
0
  info.Set("CMAKE_CURRENT_BINARY_DIR", MfDef("CMAKE_CURRENT_BINARY_DIR"));
2076
0
  info.Set("BUILD_DIR", this->Dir.Build);
2077
0
  info.SetConfig("INCLUDE_DIR", this->Dir.Include);
2078
2079
0
  info.SetUInt("QT_VERSION_MAJOR", this->QtVersion.Major);
2080
0
  info.SetUInt("QT_VERSION_MINOR", this->QtVersion.Minor);
2081
0
  info.SetConfig("QT_MOC_EXECUTABLE", this->Moc.Executable);
2082
0
  info.SetConfig("QT_UIC_EXECUTABLE", this->Uic.Executable);
2083
2084
0
  info.Set("CMAKE_EXECUTABLE", cmSystemTools::GetCMakeCommand());
2085
0
  info.SetConfig("SETTINGS_FILE", this->AutogenTarget.SettingsFile);
2086
0
  info.SetConfig("PARSE_CACHE_FILE", this->AutogenTarget.ParseCacheFile);
2087
0
  info.SetConfig("DEP_FILE", this->AutogenTarget.DepFile);
2088
0
  info.SetConfig("DEP_FILE_RULE_NAME", this->AutogenTarget.DepFileRuleName);
2089
0
  info.SetArray("CMAKE_LIST_FILES", this->Makefile->GetListFiles());
2090
0
  info.SetArray("HEADER_EXTENSIONS",
2091
0
                this->Makefile->GetCMakeInstance()->GetHeaderExtensions());
2092
0
  auto cfgArray = [this](std::vector<size_t> const& configs) -> Json::Value {
2093
0
    Json::Value value;
2094
0
    if (!configs.empty()) {
2095
0
      value = Json::arrayValue;
2096
0
      for (size_t ci : configs) {
2097
0
        value.append(this->ConfigsList[ci]);
2098
0
      }
2099
0
    }
2100
0
    return value;
2101
0
  };
2102
0
  info.SetArrayArray("HEADERS", headers,
2103
0
                     [this, &cfgArray](Json::Value& jval, MUFile const* muf) {
2104
0
                       jval.resize(4u);
2105
0
                       jval[0u] = muf->FullPath;
2106
0
                       jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm',
2107
0
                                           muf->UicIt ? 'U' : 'u');
2108
0
                       jval[2u] = this->GetMocBuildPath(*muf);
2109
0
                       jval[3u] = cfgArray(muf->Configs);
2110
0
                     });
2111
0
  info.SetArrayArray(
2112
0
    "SOURCES", sources, [&cfgArray](Json::Value& jval, MUFile const* muf) {
2113
0
      jval.resize(3u);
2114
0
      jval[0u] = muf->FullPath;
2115
0
      jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm', muf->UicIt ? 'U' : 'u');
2116
0
      jval[2u] = cfgArray(muf->Configs);
2117
0
    });
2118
0
  info.SetArrayArray("CXX_MODULE_UNITS", moduleUnits,
2119
0
                     [this, &cfgArray](Json::Value& jval, MUFile const* muf) {
2120
0
                       jval.resize(4u);
2121
0
                       jval[0u] = muf->FullPath;
2122
0
                       jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm',
2123
0
                                           muf->UicIt ? 'U' : 'u');
2124
0
                       jval[2u] = cfgArray(muf->Configs);
2125
0
                       jval[3u] = this->GetMocBuildPath(*muf);
2126
0
                     });
2127
2128
  // Write moc settings
2129
0
  if (this->Moc.Enabled) {
2130
0
    info.SetArray("MOC_SKIP", moc_skip);
2131
0
    info.SetConfigArray("MOC_DEFINITIONS", this->Moc.Defines);
2132
0
    info.SetConfigArray("MOC_INCLUDES", this->Moc.Includes);
2133
0
    info.SetArray("MOC_OPTIONS", this->Moc.Options);
2134
0
    info.SetBool("MOC_RELAXED_MODE", this->Moc.RelaxedMode);
2135
0
    info.SetBool("MOC_PATH_PREFIX", this->Moc.PathPrefix);
2136
2137
0
    cm::EvaluatedTargetPropertyEntries InterfaceAutoMocMacroNamesEntries;
2138
2139
0
    if (this->MultiConfig) {
2140
0
      for (auto const& cfg : this->ConfigsList) {
2141
0
        if (!cfg.empty()) {
2142
0
          cm::GenEx::Context context(this->LocalGen, cfg, "CXX");
2143
0
          cmGeneratorExpressionDAGChecker dagChecker{
2144
0
            this->GenTarget, "AUTOMOC_MACRO_NAMES", nullptr, nullptr, context,
2145
0
          };
2146
0
          cm::AddInterfaceEntries(
2147
0
            this->GenTarget, "INTERFACE_AUTOMOC_MACRO_NAMES", context,
2148
0
            &dagChecker, InterfaceAutoMocMacroNamesEntries,
2149
0
            cm::IncludeRuntimeInterface::Yes);
2150
0
        }
2151
0
      }
2152
0
    } else {
2153
0
      cm::GenEx::Context context(this->LocalGen, this->ConfigDefault, "CXX");
2154
0
      cmGeneratorExpressionDAGChecker dagChecker{
2155
0
        this->GenTarget, "AUTOMOC_MACRO_NAMES", nullptr, nullptr, context,
2156
0
      };
2157
0
      AddInterfaceEntries(
2158
0
        this->GenTarget, "INTERFACE_AUTOMOC_MACRO_NAMES", context, &dagChecker,
2159
0
        InterfaceAutoMocMacroNamesEntries, cm::IncludeRuntimeInterface::Yes);
2160
0
    }
2161
2162
0
    for (auto const& entry : InterfaceAutoMocMacroNamesEntries.Entries) {
2163
0
      this->Moc.MacroNames.insert(this->Moc.MacroNames.end(),
2164
0
                                  entry.Values.begin(), entry.Values.end());
2165
0
    }
2166
0
    this->Moc.MacroNames.erase(cmRemoveDuplicates(this->Moc.MacroNames),
2167
0
                               this->Moc.MacroNames.end());
2168
2169
0
    info.SetArray("MOC_MACRO_NAMES", this->Moc.MacroNames);
2170
0
    info.SetArrayArray(
2171
0
      "MOC_DEPEND_FILTERS", this->Moc.DependFilters,
2172
0
      [](Json::Value& jval, std::pair<std::string, std::string> const& pair) {
2173
0
        jval.resize(2u);
2174
0
        jval[0u] = pair.first;
2175
0
        jval[1u] = pair.second;
2176
0
      });
2177
0
    info.SetConfig("MOC_COMPILATION_FILE", this->Moc.CompilationFile);
2178
0
    info.SetConfig("MOC_PREDEFS_FILE", this->Moc.PredefsFile);
2179
2180
0
    cmStandardLevelResolver const resolver{ this->Makefile };
2181
0
    auto const CompileOptionFlag =
2182
0
      resolver.GetCompileOptionDef(this->GenTarget, "CXX", "");
2183
2184
0
    auto const CompileOptionValue =
2185
0
      this->GenTarget->Makefile->GetSafeDefinition(CompileOptionFlag);
2186
2187
0
    if (!CompileOptionValue.empty()) {
2188
      // Determine where to insert the compile option (e.g., -std=gnu++23).
2189
      // CMAKE_CXX_COMPILER_PREDEFINES_COMMAND is built as:
2190
      //   [CMAKE_CXX_COMPILER, CMAKE_CXX_COMPILER_ARG1, predefs_flags...]
2191
      // We need to insert after all compiler elements, before predefs flags.
2192
0
      size_t compilerElements = 1; // CMAKE_CXX_COMPILER
2193
2194
0
      cmValue compilerArg1 =
2195
0
        this->Makefile->GetDefinition("CMAKE_CXX_COMPILER_ARG1");
2196
0
      if (compilerArg1 && !compilerArg1->empty()) {
2197
0
        std::vector<std::string> arg1List;
2198
0
        cmSystemTools::ParseUnixCommandLine(compilerArg1->c_str(), arg1List);
2199
0
        compilerElements += arg1List.size();
2200
0
      }
2201
2202
0
      if (this->Moc.PredefsCmd.size() > compilerElements) {
2203
0
        this->Moc.PredefsCmd.insert(
2204
0
          this->Moc.PredefsCmd.begin() + compilerElements, CompileOptionValue);
2205
0
      }
2206
0
    }
2207
0
    info.SetArray("MOC_PREDEFS_CMD", this->Moc.PredefsCmd);
2208
0
  }
2209
2210
  // Write uic settings
2211
0
  if (this->Uic.Enabled) {
2212
    // Add skipped .ui files
2213
0
    uic_skip.insert(this->Uic.SkipUi.begin(), this->Uic.SkipUi.end());
2214
2215
0
    info.SetArray("UIC_SKIP", uic_skip);
2216
0
    info.SetArrayArray("UIC_UI_FILES", this->Uic.UiFilesWithOptions,
2217
0
                       [](Json::Value& jval, UicT::UiFileT const& uiFile) {
2218
0
                         jval.resize(2u);
2219
0
                         jval[0u] = uiFile.first;
2220
0
                         InfoWriter::MakeStringArray(jval[1u], uiFile.second);
2221
0
                       });
2222
0
    info.SetConfigArray("UIC_OPTIONS", this->Uic.Options);
2223
0
    info.SetArray("UIC_SEARCH_PATHS", this->Uic.SearchPaths);
2224
0
  }
2225
2226
0
  info.Save(this->AutogenTarget.InfoFile);
2227
2228
0
  return true;
2229
0
}
2230
2231
bool cmQtAutoGenInitializer::SetupWriteRccInfo()
2232
0
{
2233
0
  for (Qrc const& qrc : this->Rcc.Qrcs) {
2234
    // Utility lambdas
2235
0
    auto MfDef = [this](std::string const& key) {
2236
0
      return this->Makefile->GetSafeDefinition(key);
2237
0
    };
2238
2239
0
    InfoWriter info;
2240
2241
    // General
2242
0
    info.SetBool("MULTI_CONFIG", this->MultiConfig);
2243
0
    info.SetBool("CROSS_CONFIG", this->CrossConfig);
2244
0
    info.SetBool("USE_BETTER_GRAPH", this->UseBetterGraph);
2245
0
    info.SetUInt("VERBOSITY", this->Verbosity);
2246
0
    info.Set("GENERATOR", this->GlobalGen->GetName());
2247
2248
    // Files
2249
0
    info.Set("LOCK_FILE", qrc.LockFile);
2250
0
    info.SetConfig("SETTINGS_FILE", qrc.SettingsFile);
2251
2252
    // Directories
2253
0
    info.Set("CMAKE_SOURCE_DIR", MfDef("CMAKE_SOURCE_DIR"));
2254
0
    info.Set("CMAKE_BINARY_DIR", MfDef("CMAKE_BINARY_DIR"));
2255
0
    info.Set("CMAKE_CURRENT_SOURCE_DIR", MfDef("CMAKE_CURRENT_SOURCE_DIR"));
2256
0
    info.Set("CMAKE_CURRENT_BINARY_DIR", MfDef("CMAKE_CURRENT_BINARY_DIR"));
2257
0
    info.Set("BUILD_DIR", this->Dir.Build);
2258
0
    info.SetConfig("INCLUDE_DIR", this->Dir.Include);
2259
2260
    // rcc executable
2261
0
    info.SetConfig("RCC_EXECUTABLE", this->Rcc.Executable);
2262
0
    info.SetConfigArray(
2263
0
      "RCC_LIST_OPTIONS",
2264
0
      generateListOptions(this->Rcc.ExecutableFeatures, this->MultiConfig));
2265
2266
    // qrc file
2267
0
    info.Set("SOURCE", qrc.QrcFile);
2268
0
    info.Set("OUTPUT_CHECKSUM", qrc.QrcPathChecksum);
2269
0
    info.Set("OUTPUT_NAME",
2270
0
             cmSystemTools::GetFilenameName(qrc.OutputFileGenex));
2271
0
    info.SetArray("OPTIONS", qrc.Options);
2272
0
    info.SetConfigArray("INPUTS", qrc.Resources);
2273
2274
0
    info.Save(qrc.InfoFile);
2275
0
  }
2276
2277
0
  return true;
2278
0
}
2279
2280
cmSourceFile* cmQtAutoGenInitializer::RegisterGeneratedSource(
2281
  std::string const& filename, bool scanForModules)
2282
0
{
2283
0
  cmSourceFile* gFile = this->Makefile->GetOrCreateSource(filename, true);
2284
0
  gFile->SetSpecialSourceType(
2285
0
    cmSourceFile::SpecialSourceType::QtAutogenSource);
2286
0
  gFile->MarkAsGenerated();
2287
0
  gFile->SetProperty("SKIP_AUTOGEN", "1");
2288
0
  gFile->SetProperty("SKIP_LINTING", "ON");
2289
0
  gFile->SetProperty("CXX_SCAN_FOR_MODULES", scanForModules ? "1" : "0");
2290
0
  return gFile;
2291
0
}
2292
2293
cmSourceFile* cmQtAutoGenInitializer::AddGeneratedSource(
2294
  std::string const& filename, GenVarsT const& genVars, bool prepend)
2295
0
{
2296
  // Register source at makefile
2297
0
  cmSourceFile* gFile = this->RegisterGeneratedSource(filename);
2298
  // Add source file to target
2299
0
  this->GenTarget->AddSource(filename, prepend);
2300
2301
  // Add source file to source group
2302
0
  this->AddToSourceGroup(filename, genVars.GenNameUpper);
2303
2304
0
  return gFile;
2305
0
}
2306
2307
void cmQtAutoGenInitializer::AddGeneratedSource(ConfigString const& filename,
2308
                                                GenVarsT const& genVars,
2309
                                                bool prepend)
2310
0
{
2311
  // XXX(xcode-per-cfg-src): Drop the Xcode-specific part of the condition
2312
  // when the Xcode generator supports per-config sources.
2313
0
  if (!this->MultiConfig || this->GlobalGen->IsXcode()) {
2314
0
    cmSourceFile* sf =
2315
0
      this->AddGeneratedSource(filename.Default, genVars, prepend);
2316
0
    handleSkipPch(sf);
2317
0
    return;
2318
0
  }
2319
0
  for (auto const& cfg : this->ConfigsList) {
2320
0
    std::string const& filenameCfg = filename.Config.at(cfg);
2321
    // Register source at makefile
2322
0
    cmSourceFile* sf = this->RegisterGeneratedSource(filenameCfg);
2323
0
    handleSkipPch(sf);
2324
    // Add source file to target for this configuration.
2325
0
    this->GenTarget->AddSource(
2326
0
      cmStrCat("$<$<CONFIG:"_s, cfg, ">:"_s, filenameCfg, ">"_s), prepend);
2327
    // Add source file to source group
2328
0
    this->AddToSourceGroup(filenameCfg, genVars.GenNameUpper);
2329
0
  }
2330
0
}
2331
2332
void cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName,
2333
                                              cm::string_view genNameUpper)
2334
0
{
2335
0
  cmSourceGroup* sourceGroup = nullptr;
2336
  // Acquire source group
2337
0
  {
2338
0
    std::string property;
2339
0
    std::string groupName;
2340
0
    {
2341
      // Prefer generator specific source group name
2342
0
      std::initializer_list<std::string> const props{
2343
0
        cmStrCat(genNameUpper, "_SOURCE_GROUP"), "AUTOGEN_SOURCE_GROUP"
2344
0
      };
2345
0
      for (std::string const& prop : props) {
2346
0
        cmValue propName = this->Makefile->GetState()->GetGlobalProperty(prop);
2347
0
        if (cmNonempty(propName)) {
2348
0
          groupName = *propName;
2349
0
          property = prop;
2350
0
          break;
2351
0
        }
2352
0
      }
2353
0
    }
2354
    // Generate a source group on demand
2355
0
    if (!groupName.empty()) {
2356
0
      sourceGroup = this->Makefile->GetOrCreateSourceGroup(groupName);
2357
0
      if (!sourceGroup) {
2358
0
        cmSystemTools::Error(
2359
0
          cmStrCat(genNameUpper, " error in ", property,
2360
0
                   ": Could not find or create the source group ",
2361
0
                   cmQtAutoGen::Quoted(groupName)));
2362
0
      }
2363
0
    }
2364
0
  }
2365
0
  if (sourceGroup) {
2366
0
    sourceGroup->AddGroupFile(fileName);
2367
0
  }
2368
0
}
2369
2370
void cmQtAutoGenInitializer::AddCleanFile(std::string const& fileName)
2371
0
{
2372
0
  this->GenTarget->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", fileName);
2373
0
}
2374
2375
void cmQtAutoGenInitializer::ConfigFileNames(ConfigString& configString,
2376
                                             cm::string_view prefix,
2377
                                             cm::string_view suffix)
2378
0
{
2379
0
  configString.Default = cmStrCat(prefix, suffix);
2380
0
  if (this->MultiConfig) {
2381
0
    for (auto const& cfg : this->ConfigsList) {
2382
0
      configString.Config[cfg] = cmStrCat(prefix, '_', cfg, suffix);
2383
0
    }
2384
0
  }
2385
0
}
2386
2387
void cmQtAutoGenInitializer::ConfigFileNamesAndGenex(
2388
  ConfigString& configString, std::string& genex, cm::string_view const prefix,
2389
  cm::string_view const suffix)
2390
0
{
2391
0
  this->ConfigFileNames(configString, prefix, suffix);
2392
0
  if (this->MultiConfig) {
2393
0
    genex = cmStrCat(prefix, "_$<CONFIG>"_s, suffix);
2394
0
  } else {
2395
0
    genex = configString.Default;
2396
0
  }
2397
0
}
2398
2399
void cmQtAutoGenInitializer::ConfigFileNameCommon(ConfigString& configString,
2400
                                                  std::string const& fileName)
2401
0
{
2402
0
  configString.Default = fileName;
2403
0
  if (this->MultiConfig) {
2404
0
    for (auto const& cfg : this->ConfigsList) {
2405
0
      configString.Config[cfg] = fileName;
2406
0
    }
2407
0
  }
2408
0
}
2409
2410
void cmQtAutoGenInitializer::ConfigFileClean(ConfigString& configString)
2411
0
{
2412
0
  this->AddCleanFile(configString.Default);
2413
0
  if (this->MultiConfig) {
2414
0
    for (auto const& pair : configString.Config) {
2415
0
      this->AddCleanFile(pair.second);
2416
0
    }
2417
0
  }
2418
0
}
2419
2420
static cmQtAutoGen::IntegerVersion parseMocVersion(std::string str)
2421
0
{
2422
0
  cmQtAutoGen::IntegerVersion result;
2423
2424
0
  static std::string const prelude = "moc ";
2425
0
  size_t const pos = str.find(prelude);
2426
0
  if (pos == std::string::npos) {
2427
0
    return result;
2428
0
  }
2429
2430
0
  str.erase(0, prelude.size() + pos);
2431
0
  std::istringstream iss(str);
2432
0
  std::string major;
2433
0
  std::string minor;
2434
0
  if (!std::getline(iss, major, '.') || !std::getline(iss, minor, '.')) {
2435
0
    return result;
2436
0
  }
2437
2438
0
  result.Major = static_cast<unsigned int>(std::stoi(major));
2439
0
  result.Minor = static_cast<unsigned int>(std::stoi(minor));
2440
0
  return result;
2441
0
}
2442
2443
static cmQtAutoGen::IntegerVersion GetMocVersion(
2444
  std::string const& mocExecutablePath)
2445
0
{
2446
0
  std::string capturedStdOut;
2447
0
  int exitCode;
2448
0
  if (!cmSystemTools::RunSingleCommand({ mocExecutablePath, "--version" },
2449
0
                                       &capturedStdOut, nullptr, &exitCode,
2450
0
                                       nullptr, cmSystemTools::OUTPUT_NONE)) {
2451
0
    return {};
2452
0
  }
2453
2454
0
  if (exitCode != 0) {
2455
0
    return {};
2456
0
  }
2457
2458
0
  return parseMocVersion(capturedStdOut);
2459
0
}
2460
2461
static std::string FindMocExecutableFromMocTarget(cmMakefile const* makefile,
2462
                                                  unsigned int qtMajorVersion)
2463
0
{
2464
0
  std::string result;
2465
0
  std::string const mocTargetName = cmStrCat("Qt", qtMajorVersion, "::moc");
2466
0
  cmTarget const* mocTarget = makefile->FindTargetToUse(mocTargetName);
2467
0
  if (mocTarget) {
2468
0
    result = mocTarget->GetSafeProperty("IMPORTED_LOCATION");
2469
0
  }
2470
0
  return result;
2471
0
}
2472
2473
std::pair<cmQtAutoGen::IntegerVersion, unsigned int>
2474
cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target,
2475
                                     std::string mocExecutable)
2476
0
{
2477
  // Converts a char ptr to an unsigned int value
2478
0
  auto toUInt = [](char const* const input) -> unsigned int {
2479
0
    unsigned long tmp = 0;
2480
0
    if (input && cmStrToULong(input, &tmp)) {
2481
0
      return static_cast<unsigned int>(tmp);
2482
0
    }
2483
0
    return 0u;
2484
0
  };
2485
0
  auto toUInt2 = [](cmValue input) -> unsigned int {
2486
0
    unsigned long tmp = 0;
2487
0
    if (input && cmStrToULong(*input, &tmp)) {
2488
0
      return static_cast<unsigned int>(tmp);
2489
0
    }
2490
0
    return 0u;
2491
0
  };
2492
2493
  // Initialize return value to a default
2494
0
  std::pair<IntegerVersion, unsigned int> res(
2495
0
    IntegerVersion(),
2496
0
    toUInt(target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION",
2497
0
                                                           "")));
2498
2499
  // Acquire known Qt versions
2500
0
  std::vector<cmQtAutoGen::IntegerVersion> knownQtVersions;
2501
0
  {
2502
    // Qt version variable prefixes
2503
0
    static std::initializer_list<
2504
0
      std::pair<cm::string_view, cm::string_view>> const keys{
2505
0
      { "Qt6Core_VERSION_MAJOR", "Qt6Core_VERSION_MINOR" },
2506
0
      { "Qt5Core_VERSION_MAJOR", "Qt5Core_VERSION_MINOR" },
2507
0
      { "QT_VERSION_MAJOR", "QT_VERSION_MINOR" },
2508
0
    };
2509
2510
0
    knownQtVersions.reserve(keys.size() * 2);
2511
2512
    // Adds a version to the result (nullptr safe)
2513
0
    auto addVersion = [&knownQtVersions, &toUInt2](cmValue major,
2514
0
                                                   cmValue minor) {
2515
0
      cmQtAutoGen::IntegerVersion ver(toUInt2(major), toUInt2(minor));
2516
0
      if (ver.Major != 0) {
2517
0
        knownQtVersions.emplace_back(ver);
2518
0
      }
2519
0
    };
2520
2521
    // Read versions from variables
2522
0
    for (auto const& keyPair : keys) {
2523
0
      addVersion(target->Makefile->GetDefinition(std::string(keyPair.first)),
2524
0
                 target->Makefile->GetDefinition(std::string(keyPair.second)));
2525
0
    }
2526
2527
    // Read versions from directory properties
2528
0
    for (auto const& keyPair : keys) {
2529
0
      addVersion(target->Makefile->GetProperty(std::string(keyPair.first)),
2530
0
                 target->Makefile->GetProperty(std::string(keyPair.second)));
2531
0
    }
2532
0
  }
2533
2534
  // Evaluate known Qt versions
2535
0
  if (!knownQtVersions.empty()) {
2536
0
    if (res.second == 0) {
2537
      // No specific version was requested by the target:
2538
      // Use highest known Qt version.
2539
0
      res.first = knownQtVersions.at(0);
2540
0
    } else {
2541
      // Pick a version from the known versions:
2542
0
      for (auto const& it : knownQtVersions) {
2543
0
        if (it.Major == res.second) {
2544
0
          res.first = it;
2545
0
          break;
2546
0
        }
2547
0
      }
2548
0
    }
2549
0
  }
2550
2551
0
  if (res.first.Major == 0) {
2552
    // We could not get the version number from variables or directory
2553
    // properties. This might happen if the find_package call for Qt is wrapped
2554
    // in a function. Try to find the moc executable path from the available
2555
    // targets and call "moc --version" to get the Qt version.
2556
0
    if (mocExecutable.empty()) {
2557
0
      mocExecutable =
2558
0
        FindMocExecutableFromMocTarget(target->Makefile, res.second);
2559
0
    }
2560
0
    if (!mocExecutable.empty()) {
2561
0
      res.first = GetMocVersion(mocExecutable);
2562
0
    }
2563
0
  }
2564
2565
0
  return res;
2566
0
}
2567
2568
std::string const& cmQtAutoGenInitializer::GetMocBuildPath(MUFile const& muf)
2569
0
{
2570
  // The de-duplication below is not idempotent: without memoizing, a second
2571
  // call for the same file would hand out a different path.
2572
0
  if (!muf.MocBuildPath.empty()) {
2573
0
    return muf.MocBuildPath;
2574
0
  }
2575
2576
0
  std::string& res = muf.MocBuildPath;
2577
0
  if (!muf.MocIt) {
2578
0
    return res;
2579
0
  }
2580
2581
0
  std::string basePath =
2582
0
    cmStrCat(this->PathCheckSum.getPart(muf.FullPath), "/moc_",
2583
0
             FileNameWithoutLastExtension(muf.FullPath));
2584
2585
0
  res = cmStrCat(basePath, ".cpp");
2586
0
  if (this->Moc.EmittedBuildPaths.emplace(res).second) {
2587
0
    return res;
2588
0
  }
2589
2590
  // File name already emitted.
2591
  // Try appending the header suffix to the base path.
2592
0
  basePath = cmStrCat(basePath, '_', muf.SF->GetExtension());
2593
0
  res = cmStrCat(basePath, ".cpp");
2594
0
  if (this->Moc.EmittedBuildPaths.emplace(res).second) {
2595
0
    return res;
2596
0
  }
2597
2598
  // File name with header extension already emitted.
2599
  // Try adding a number to the base path.
2600
0
  constexpr std::size_t number_begin = 2;
2601
0
  constexpr std::size_t number_end = 256;
2602
0
  for (std::size_t ii = number_begin; ii != number_end; ++ii) {
2603
0
    res = cmStrCat(basePath, '_', ii, ".cpp");
2604
0
    if (this->Moc.EmittedBuildPaths.emplace(res).second) {
2605
0
      return res;
2606
0
    }
2607
0
  }
2608
2609
  // Output file name conflict (unlikely, but still...)
2610
0
  cmSystemTools::Error(
2611
0
    cmStrCat("moc output file name conflict for ", muf.FullPath));
2612
2613
0
  return res;
2614
0
}
2615
2616
bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
2617
                                             std::string const& executable,
2618
                                             bool ignoreMissingTarget) const
2619
0
{
2620
0
  auto print_err = [this, &genVars](std::string const& err) {
2621
0
    cmSystemTools::Error(cmStrCat(genVars.GenNameUpper, " for target ",
2622
0
                                  this->GenTarget->GetName(), ": ", err));
2623
0
  };
2624
2625
  // Custom executable
2626
0
  {
2627
0
    std::string const prop = cmStrCat(genVars.GenNameUpper, "_EXECUTABLE");
2628
0
    std::string const& val = this->GenTarget->Target->GetSafeProperty(prop);
2629
0
    if (!val.empty()) {
2630
      // Evaluate generator expression
2631
0
      {
2632
0
        cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
2633
0
        cmGeneratorExpression ge(*this->Makefile->GetCMakeInstance(), lfbt);
2634
0
        std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(val);
2635
0
        if (this->MultiConfig && this->UseBetterGraph) {
2636
0
          for (auto const& config : this->ConfigsList) {
2637
0
            genVars.Executable.Config[config] =
2638
0
              cge->Evaluate(this->LocalGen, config);
2639
0
          }
2640
0
        } else {
2641
0
          genVars.Executable.Default = cge->Evaluate(this->LocalGen, "");
2642
0
        }
2643
0
      }
2644
2645
0
      if (genVars.Executable.Default.empty() &&
2646
0
          genVars.Executable.Config.empty() && !ignoreMissingTarget) {
2647
0
        print_err(prop + " evaluates to an empty value");
2648
0
        return false;
2649
0
      }
2650
2651
      // Create empty compiler features.
2652
0
      if (this->MultiConfig && this->UseBetterGraph) {
2653
0
        for (auto const& config : this->ConfigsList) {
2654
0
          genVars.ExecutableFeatures.Config[config] =
2655
0
            std::make_shared<cmQtAutoGen::CompilerFeatures>();
2656
0
        }
2657
0
      } else {
2658
0
        genVars.ExecutableFeatures.Default =
2659
0
          std::make_shared<cmQtAutoGen::CompilerFeatures>();
2660
0
      }
2661
0
      return true;
2662
0
    }
2663
0
  }
2664
2665
  // Find executable target
2666
0
  {
2667
    // Find executable target name
2668
0
    cm::string_view prefix;
2669
0
    if (this->QtVersion.Major == 4) {
2670
0
      prefix = "Qt4::";
2671
0
    } else if (this->QtVersion.Major == 5) {
2672
0
      prefix = "Qt5::";
2673
0
    } else if (this->QtVersion.Major == 6) {
2674
0
      prefix = "Qt6::";
2675
0
    }
2676
0
    std::string const targetName = cmStrCat(prefix, executable);
2677
2678
    // Find target
2679
0
    cmGeneratorTarget* genTarget =
2680
0
      this->LocalGen->FindGeneratorTargetToUse(targetName);
2681
0
    if (genTarget) {
2682
0
      genVars.ExecutableTargetName = targetName;
2683
0
      genVars.ExecutableTarget = genTarget;
2684
0
      if (genTarget->IsImported()) {
2685
0
        if (this->MultiConfig && this->UseBetterGraph) {
2686
0
          for (auto const& config : this->ConfigsList) {
2687
0
            genVars.Executable.Config[config] =
2688
0
              genTarget->ImportedGetLocation(config);
2689
0
          }
2690
0
        } else {
2691
0
          genVars.Executable.Default =
2692
0
            genTarget->ImportedGetLocation(this->ConfigDefault);
2693
0
        }
2694
2695
0
      } else {
2696
0
        if (this->MultiConfig && this->UseBetterGraph) {
2697
0
          for (auto const& config : this->ConfigsList) {
2698
0
            genVars.Executable.Config[config] = genTarget->GetLocation(config);
2699
0
          }
2700
0
        } else {
2701
0
          genVars.Executable.Default =
2702
0
            genTarget->GetLocation(this->ConfigDefault);
2703
0
        }
2704
0
      }
2705
0
    } else {
2706
0
      if (ignoreMissingTarget) {
2707
        // Create empty compiler features.
2708
0
        if (this->MultiConfig && this->UseBetterGraph) {
2709
0
          for (auto const& config : this->ConfigsList) {
2710
0
            genVars.ExecutableFeatures.Config[config] =
2711
0
              std::make_shared<cmQtAutoGen::CompilerFeatures>();
2712
0
          }
2713
0
        } else {
2714
0
          genVars.ExecutableFeatures.Default =
2715
0
            std::make_shared<cmQtAutoGen::CompilerFeatures>();
2716
0
        }
2717
2718
0
        return true;
2719
0
      }
2720
0
      print_err(cmStrCat("Could not find ", executable, " executable target ",
2721
0
                         targetName));
2722
0
      return false;
2723
0
    }
2724
0
  }
2725
2726
  // Get executable features
2727
0
  {
2728
0
    std::string err;
2729
0
    genVars.ExecutableFeatures = this->GlobalInitializer->GetCompilerFeatures(
2730
0
      executable, genVars.Executable, err, this->MultiConfig,
2731
0
      this->UseBetterGraph);
2732
0
    if (this->MultiConfig && this->UseBetterGraph) {
2733
0
      for (auto const& config : this->ConfigsList) {
2734
0
        if (!genVars.ExecutableFeatures.Config[config]) {
2735
0
          print_err(err);
2736
0
          return false;
2737
0
        }
2738
0
      }
2739
0
    } else {
2740
0
      if (!genVars.ExecutableFeatures.Default) {
2741
0
        print_err(err);
2742
0
        return false;
2743
0
      }
2744
0
    }
2745
0
  }
2746
2747
0
  return true;
2748
0
}
2749
2750
void cmQtAutoGenInitializer::handleSkipPch(cmSourceFile* sf)
2751
0
{
2752
0
  bool skipPch = true;
2753
0
  for (auto const& pair : this->AutogenTarget.Sources) {
2754
0
    if (!pair.first->GetIsGenerated() &&
2755
0
        !pair.first->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
2756
0
      skipPch = false;
2757
0
    }
2758
0
  }
2759
2760
0
  if (skipPch) {
2761
0
    sf->SetProperty("SKIP_PRECOMPILE_HEADERS", "ON");
2762
0
  }
2763
0
}