Coverage Report

Created: 2026-04-29 07:01

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