Coverage Report

Created: 2026-06-15 07:03

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->IssuePolicyWarning(
1225
0
        cmPolicies::CMP0071, {},
1226
0
        cmStrCat(
1227
0
          "For compatibility, CMake is excluding the GENERATED source "
1228
0
          "file(s):\n"_s,
1229
0
          files, "from processing by "_s,
1230
0
          cmQtAutoGen::Tools(this->Moc.Enabled, this->Uic.Enabled, false),
1231
0
          ".  If any of the files should be processed, set CMP0071 to NEW.  "
1232
0
          "If any of the files should not be processed, "
1233
0
          "explicitly exclude them by setting the source file property "_s,
1234
0
          property, ":\n  set_property(SOURCE file.h PROPERTY "_s, property,
1235
0
          " ON)"_s));
1236
0
    }
1237
0
  }
1238
1239
  // Generate CMP0100 warning
1240
0
  if (this->MocOrUicEnabled() &&
1241
0
      !this->AutogenTarget.CMP0100HeadersWarn.empty()) {
1242
0
    cm::string_view property;
1243
0
    if (this->Moc.Enabled && this->Uic.Enabled) {
1244
0
      property = "SKIP_AUTOGEN";
1245
0
    } else if (this->Moc.Enabled) {
1246
0
      property = "SKIP_AUTOMOC";
1247
0
    } else if (this->Uic.Enabled) {
1248
0
      property = "SKIP_AUTOUIC";
1249
0
    }
1250
0
    std::string files;
1251
0
    for (cmSourceFile const* sf : this->AutogenTarget.CMP0100HeadersWarn) {
1252
0
      files += cmStrCat("  ", Quoted(sf->GetFullPath()), '\n');
1253
0
    }
1254
0
    this->Makefile->IssuePolicyWarning(
1255
0
      cmPolicies::CMP0100, {},
1256
0
      cmStrCat(
1257
0
        "For compatibility, CMake is excluding the header file(s):\n"_s, files,
1258
0
        "from processing by "_s,
1259
0
        cmQtAutoGen::Tools(this->Moc.Enabled, this->Uic.Enabled, false),
1260
0
        ".  If any of the files should be processed, set CMP0100 to NEW.  "
1261
0
        "If any of the files should not be processed, "
1262
0
        "explicitly exclude them by setting the source file property "_s,
1263
0
        property, ":\n  set_property(SOURCE file.hh PROPERTY "_s, property,
1264
0
        " ON)"_s));
1265
0
  }
1266
1267
  // Process qrc files
1268
0
  if (!this->Rcc.Qrcs.empty()) {
1269
0
    bool const modernQt = (this->QtVersion.Major >= 5);
1270
    // Target rcc options
1271
0
    cmList const optionsTarget{ this->GenTarget->GetSafeProperty(
1272
0
      kw.AUTORCC_OPTIONS) };
1273
1274
    // Check if file name is unique
1275
0
    for (Qrc& qrc : this->Rcc.Qrcs) {
1276
0
      qrc.Unique = true;
1277
0
      for (Qrc const& qrc2 : this->Rcc.Qrcs) {
1278
0
        if ((&qrc != &qrc2) && (qrc.QrcName == qrc2.QrcName)) {
1279
0
          qrc.Unique = false;
1280
0
          break;
1281
0
        }
1282
0
      }
1283
0
    }
1284
    // Path checksum and file names
1285
0
    for (Qrc& qrc : this->Rcc.Qrcs) {
1286
      // Path checksum
1287
0
      qrc.QrcPathChecksum = this->PathCheckSum.getPart(qrc.QrcFile);
1288
      // Output file name
1289
0
      if (this->MultiConfig && !this->GlobalGen->IsXcode() &&
1290
0
          this->UseBetterGraph) {
1291
0
        this->ConfigFileNamesAndGenex(qrc.OutputFile, qrc.OutputFileGenex,
1292
0
                                      cmStrCat(this->Dir.Build, '/',
1293
0
                                               qrc.QrcPathChecksum, "/qrc_",
1294
0
                                               qrc.QrcName),
1295
0
                                      ".cpp"_s);
1296
0
      } else {
1297
        // For non-better-graph, all configs use the same file
1298
0
        std::string const outputFile =
1299
0
          cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum, "/qrc_",
1300
0
                   qrc.QrcName, ".cpp");
1301
0
        this->ConfigFileNameCommon(qrc.OutputFile, outputFile);
1302
0
        qrc.OutputFileGenex = outputFile;
1303
0
      }
1304
0
      std::string const base = cmStrCat(this->Dir.Info, "/AutoRcc_",
1305
0
                                        qrc.QrcName, '_', qrc.QrcPathChecksum);
1306
0
      qrc.LockFile = cmStrCat(base, "_Lock.lock");
1307
0
      qrc.InfoFile = cmStrCat(base, "_Info.json");
1308
0
      this->ConfigFileNames(qrc.SettingsFile, cmStrCat(base, "_Used"), ".txt");
1309
0
    }
1310
    // rcc options
1311
0
    for (Qrc& qrc : this->Rcc.Qrcs) {
1312
      // Target options
1313
0
      std::vector<std::string> opts = optionsTarget;
1314
      // Merge computed "-name XYZ" option
1315
0
      {
1316
0
        std::string name = qrc.QrcName;
1317
        // Replace '-' with '_'. The former is not valid for symbol names.
1318
0
        std::replace(name.begin(), name.end(), '-', '_');
1319
0
        if (!qrc.Unique) {
1320
0
          name += cmStrCat('_', qrc.QrcPathChecksum);
1321
0
        }
1322
0
        std::vector<std::string> nameOpts;
1323
0
        nameOpts.emplace_back("-name");
1324
0
        nameOpts.emplace_back(std::move(name));
1325
0
        RccMergeOptions(opts, nameOpts, modernQt);
1326
0
      }
1327
      // Merge file option
1328
0
      RccMergeOptions(opts, qrc.Options, modernQt);
1329
0
      qrc.Options = std::move(opts);
1330
0
    }
1331
    // rcc resources
1332
0
    for (Qrc& qrc : this->Rcc.Qrcs) {
1333
0
      if (!qrc.Generated) {
1334
0
        std::string error;
1335
0
        if (this->MultiConfig && this->UseBetterGraph) {
1336
0
          for (auto const& config : this->ConfigsList) {
1337
0
            RccLister const lister(
1338
0
              this->Rcc.Executable.Config[config],
1339
0
              this->Rcc.ExecutableFeatures.Config[config]->ListOptions);
1340
0
            if (!lister.list(qrc.QrcFile, qrc.Resources.Config[config],
1341
0
                             error)) {
1342
0
              cmSystemTools::Error(error);
1343
0
              return false;
1344
0
            }
1345
0
          }
1346
0
        } else {
1347
0
          RccLister const lister(
1348
0
            this->Rcc.Executable.Default,
1349
0
            this->Rcc.ExecutableFeatures.Default->ListOptions);
1350
0
          if (!lister.list(qrc.QrcFile, qrc.Resources.Default, error)) {
1351
0
            cmSystemTools::Error(error);
1352
0
            return false;
1353
0
          }
1354
0
        }
1355
0
      }
1356
0
    }
1357
0
  }
1358
1359
0
  return true;
1360
0
}
1361
1362
bool cmQtAutoGenInitializer::InitAutogenTarget()
1363
0
{
1364
  // Register info file as generated by CMake
1365
0
  this->Makefile->AddCMakeOutputFile(this->AutogenTarget.InfoFile);
1366
1367
  // Determine whether to use a depfile for the AUTOGEN target.
1368
0
  bool const useDepfile = [this]() -> bool {
1369
0
    auto const& gen = this->GlobalGen->GetName();
1370
0
    return this->QtVersion >= IntegerVersion(5, 15) &&
1371
0
      (gen.find("Ninja") != std::string::npos ||
1372
0
       gen.find("Make") != std::string::npos ||
1373
0
       gen.find("Visual Studio") != std::string::npos || gen == "Xcode");
1374
0
  }();
1375
1376
  // Files provided by the autogen target
1377
0
  std::vector<std::string> autogenByproducts;
1378
0
  std::vector<std::string> timestampByproducts;
1379
0
  if (this->Moc.Enabled) {
1380
0
    this->AddGeneratedSource(this->Moc.CompilationFile, this->Moc, true);
1381
0
    if (useDepfile) {
1382
0
      if (this->CrossConfig &&
1383
0
          this->GlobalGen->GetName().find("Ninja") != std::string::npos &&
1384
0
          !this->UseBetterGraph) {
1385
        // Make all mocs_compilation_<CONFIG>.cpp files byproducts of the
1386
        // ${target}_autogen/timestamp custom command.
1387
        // We cannot just use Moc.CompilationFileGenex here, because that
1388
        // custom command runs cmake_autogen for each configuration.
1389
0
        for (auto const& p : this->Moc.CompilationFile.Config) {
1390
0
          timestampByproducts.push_back(p.second);
1391
0
        }
1392
0
      } else {
1393
0
        timestampByproducts.push_back(this->Moc.CompilationFileGenex);
1394
0
      }
1395
0
    } else {
1396
0
      autogenByproducts.push_back(this->Moc.CompilationFileGenex);
1397
0
    }
1398
0
  }
1399
1400
0
  if (this->Uic.Enabled) {
1401
0
    for (auto const& file : this->Uic.UiHeaders) {
1402
0
      this->AddGeneratedSource(file.first, this->Uic);
1403
0
      if (!this->GlobalGen->IsFastbuild()) {
1404
0
        autogenByproducts.push_back(file.second);
1405
0
      }
1406
0
    }
1407
0
  }
1408
1409
  // Compose target comment
1410
0
  std::string autogenComment;
1411
0
  {
1412
0
    std::string tools;
1413
0
    if (this->Moc.Enabled) {
1414
0
      tools += "MOC";
1415
0
    }
1416
0
    if (this->Uic.Enabled) {
1417
0
      if (!tools.empty()) {
1418
0
        tools += " and ";
1419
0
      }
1420
0
      tools += "UIC";
1421
0
    }
1422
0
    autogenComment = cmStrCat("Automatic ", tools, " for target ",
1423
0
                              this->GenTarget->GetName());
1424
0
  }
1425
1426
  // Compose command lines
1427
  // FIXME: Take advantage of our per-config mocs_compilation_$<CONFIG>.cpp
1428
  // instead of fiddling with the include directories
1429
1430
0
  bool constexpr stdPipesUTF8 = true;
1431
0
  cmCustomCommandLines commandLines;
1432
0
  AddCMakeProcessToCommandLines(this->AutogenTarget.InfoFile, "cmake_autogen",
1433
0
                                commandLines);
1434
1435
  // Use PRE_BUILD on demand
1436
0
  bool usePRE_BUILD = false;
1437
0
  if (this->GlobalGen->GetName().find("Visual Studio") != std::string::npos) {
1438
    // Under VS use a PRE_BUILD event instead of a separate target to
1439
    // reduce the number of targets loaded into the IDE.
1440
    // This also works around a VS 11 bug that may skip updating the target:
1441
    //  https://connect.microsoft.com/VisualStudio/feedback/details/769495
1442
0
    usePRE_BUILD = true;
1443
0
  }
1444
  // Disable PRE_BUILD in some cases
1445
0
  if (usePRE_BUILD) {
1446
    // Cannot use PRE_BUILD with file depends
1447
0
    if (!this->AutogenTarget.DependFiles.empty()) {
1448
0
      usePRE_BUILD = false;
1449
0
    }
1450
    // Cannot use PRE_BUILD when a global autogen target is in place
1451
0
    if (this->AutogenTarget.GlobalTarget) {
1452
0
      usePRE_BUILD = false;
1453
0
    }
1454
    // Cannot use PRE_BUILD with depfiles
1455
0
    if (useDepfile) {
1456
0
      usePRE_BUILD = false;
1457
0
    }
1458
0
  }
1459
  // Create the autogen target/command
1460
0
  if (usePRE_BUILD) {
1461
    // Add additional autogen target dependencies to origin target
1462
0
    for (cmTarget const* depTarget : this->AutogenTarget.DependTargets) {
1463
0
      this->GenTarget->Target->AddUtility(depTarget->GetName(), false,
1464
0
                                          this->Makefile);
1465
0
    }
1466
1467
0
    if (!this->Uic.UiFilesNoOptions.empty() ||
1468
0
        !this->Uic.UiFilesWithOptions.empty()) {
1469
      // Add a generated timestamp file
1470
0
      ConfigString timestampFile;
1471
0
      std::string timestampFileGenex;
1472
0
      ConfigFileNamesAndGenex(timestampFile, timestampFileGenex,
1473
0
                              cmStrCat(this->Dir.Build, "/autouic"_s),
1474
0
                              ".stamp"_s);
1475
0
      this->AddGeneratedSource(timestampFile, this->Uic);
1476
1477
      // Add a step in the pre-build command to touch the timestamp file
1478
0
      commandLines.push_back(
1479
0
        cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", "touch",
1480
0
                            timestampFileGenex }));
1481
1482
      // UIC needs to be re-run if any of the known UI files change or the
1483
      // executable itself has been updated
1484
0
      auto uicDependencies = this->Uic.UiFilesNoOptions;
1485
0
      for (auto const& uiFile : this->Uic.UiFilesWithOptions) {
1486
0
        uicDependencies.push_back(uiFile.first);
1487
0
      }
1488
0
      AddAutogenExecutableToDependencies(this->Uic, uicDependencies);
1489
1490
      // Add a rule file to cause the target to build if a dependency has
1491
      // changed, which will trigger the pre-build command to run autogen
1492
0
      auto cc = cm::make_unique<cmCustomCommand>();
1493
0
      cc->SetOutputs(timestampFileGenex);
1494
0
      cc->SetDepends(uicDependencies);
1495
0
      cc->SetComment("");
1496
0
      cc->SetWorkingDirectory(this->Dir.Work.c_str());
1497
0
      cc->SetEscapeOldStyle(false);
1498
0
      cc->SetStdPipesUTF8(stdPipesUTF8);
1499
0
      this->LocalGen->AddCustomCommandToOutput(std::move(cc));
1500
0
    }
1501
1502
    // Add the pre-build command directly to bypass the OBJECT_LIBRARY
1503
    // rejection in cmMakefile::AddCustomCommandToTarget because we know
1504
    // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case.
1505
    //
1506
    // PRE_BUILD does not support file dependencies!
1507
0
    cmCustomCommand cc;
1508
0
    cc.SetByproducts(autogenByproducts);
1509
0
    cc.SetCommandLines(commandLines);
1510
0
    cc.SetComment(autogenComment.c_str());
1511
0
    cc.SetBacktrace(this->Makefile->GetBacktrace());
1512
0
    cc.SetWorkingDirectory(this->Dir.Work.c_str());
1513
0
    cc.SetStdPipesUTF8(stdPipesUTF8);
1514
0
    cc.SetEscapeOldStyle(false);
1515
0
    cc.SetEscapeAllowMakeVars(true);
1516
0
    this->GenTarget->Target->AddPreBuildCommand(std::move(cc));
1517
0
  } else {
1518
1519
    // Add link library target dependencies to the autogen target
1520
    // dependencies
1521
0
    if (this->AutogenTarget.DependOrigin) {
1522
      // add_dependencies/addUtility do not support generator expressions.
1523
      // We depend only on the libraries found in all configs therefore.
1524
0
      std::map<cmGeneratorTarget const*, std::size_t> targetsPartOfAllConfigs;
1525
0
      for (std::string const& config : this->ConfigsList) {
1526
        // The same target might appear multiple times in a config, but we
1527
        // should only count it once.
1528
0
        std::set<cmGeneratorTarget const*> seenTargets;
1529
0
        cmLinkImplementationLibraries const* libs =
1530
0
          this->GenTarget->GetLinkImplementationLibraries(
1531
0
            config, cmGeneratorTarget::UseTo::Link);
1532
0
        if (libs) {
1533
0
          for (cmLinkItem const& item : libs->Libraries) {
1534
0
            cmGeneratorTarget const* libTarget = item.Target;
1535
0
            if (libTarget &&
1536
0
                !StaticLibraryCycle(this->GenTarget, libTarget, config) &&
1537
0
                seenTargets.insert(libTarget).second) {
1538
              // Increment target config count
1539
0
              targetsPartOfAllConfigs[libTarget]++;
1540
0
            }
1541
0
          }
1542
0
        }
1543
0
      }
1544
0
      for (auto const& item : targetsPartOfAllConfigs) {
1545
0
        if (item.second == this->ConfigsList.size()) {
1546
0
          this->AutogenTarget.DependTargets.insert(item.first->Target);
1547
0
        }
1548
0
      }
1549
0
    }
1550
1551
0
    cmTarget* timestampTarget = nullptr;
1552
0
    std::vector<std::string> dependencies(
1553
0
      this->AutogenTarget.DependFiles.begin(),
1554
0
      this->AutogenTarget.DependFiles.end());
1555
0
    if (useDepfile) {
1556
      // Create a custom command that generates a timestamp file and
1557
      // has a depfile assigned. The depfile is created by JobDepFilesMergeT.
1558
      //
1559
      // Also create an additional '_autogen_timestamp_deps' that the custom
1560
      // command will depend on. It will have no sources or commands to
1561
      // execute, but it will have dependencies that would originally be
1562
      // assigned to the pre-Qt 5.15 'autogen' target. These dependencies will
1563
      // serve as a list of order-only dependencies for the custom command,
1564
      // without forcing the custom command to re-execute.
1565
      //
1566
      // The dependency tree would then look like
1567
      // '_autogen_timestamp_deps (order-only)' <- '/timestamp' file <-
1568
      // '_autogen' target.
1569
0
      auto const timestampTargetName =
1570
0
        cmStrCat(this->GenTarget->GetName(), "_autogen_timestamp_deps");
1571
1572
0
      auto cc = cm::make_unique<cmCustomCommand>();
1573
0
      cc->SetWorkingDirectory(this->Dir.Work.c_str());
1574
0
      cc->SetDepends(dependencies);
1575
0
      cc->SetEscapeOldStyle(false);
1576
0
      timestampTarget = this->LocalGen->AddUtilityCommand(timestampTargetName,
1577
0
                                                          true, std::move(cc));
1578
1579
0
      this->LocalGen->AddGeneratorTarget(
1580
0
        cm::make_unique<cmGeneratorTarget>(timestampTarget, this->LocalGen));
1581
1582
      // Set FOLDER property on the timestamp target, so it appears in the
1583
      // appropriate folder in an IDE or in the file api.
1584
0
      if (!this->TargetsFolder.empty()) {
1585
0
        timestampTarget->SetProperty("FOLDER", this->TargetsFolder);
1586
0
      }
1587
1588
      // Make '/timestamp' file depend on '_autogen_timestamp_deps' and on the
1589
      // moc and uic executables (whichever are enabled).
1590
0
      dependencies.clear();
1591
0
      dependencies.push_back(timestampTargetName);
1592
1593
0
      AddAutogenExecutableToDependencies(this->Moc, dependencies);
1594
0
      AddAutogenExecutableToDependencies(this->Uic, dependencies);
1595
0
      std::string outputFile;
1596
0
      std::string depFile;
1597
      // Create the custom command that outputs the timestamp file.
1598
0
      if (this->MultiConfig && this->UseBetterGraph) {
1599
        // create timestamp file with $<CONFIG> in the name so that
1600
        // every cmake_autogen target has its own timestamp file
1601
0
        std::string const configView = "$<CONFIG>";
1602
0
        std::string const timestampFileWithoutConfig = "timestamp_";
1603
0
        std::string const depFileWithoutConfig =
1604
0
          cmStrCat(this->Dir.Build, "/deps_");
1605
0
        std::string const timestampFileName =
1606
0
          timestampFileWithoutConfig + configView;
1607
0
        outputFile = cmStrCat(this->Dir.Build, '/', timestampFileName);
1608
0
        auto const depFileWithConfig =
1609
0
          cmStrCat(depFileWithoutConfig, configView);
1610
0
        depFile = depFileWithConfig;
1611
0
        commandLines.push_back(cmMakeCommandLine(
1612
0
          { cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile }));
1613
1614
0
        ConfigString outputFileWithConfig;
1615
0
        for (std::string const& config : this->ConfigsList) {
1616
0
          auto tempTimestampFileName = timestampFileWithoutConfig + config;
1617
0
          auto tempDepFile = depFileWithoutConfig + config;
1618
0
          outputFileWithConfig.Config[config] = tempTimestampFileName;
1619
0
          this->AutogenTarget.DepFileRuleName.Config[config] =
1620
0
            cmStrCat(this->Dir.RelativeBuild, '/', tempTimestampFileName);
1621
0
          this->AutogenTarget.DepFile.Config[config] = tempDepFile;
1622
0
        }
1623
0
        this->AddGeneratedSource(outputFileWithConfig, this->Moc);
1624
0
      } else {
1625
0
        cm::string_view const timestampFileName = "timestamp";
1626
0
        outputFile = cmStrCat(this->Dir.Build, '/', timestampFileName);
1627
0
        this->AutogenTarget.DepFile.Default =
1628
0
          cmStrCat(this->Dir.Build, "/deps");
1629
0
        depFile = this->AutogenTarget.DepFile.Default;
1630
0
        this->AutogenTarget.DepFileRuleName.Default =
1631
0
          cmStrCat(this->Dir.RelativeBuild, '/', timestampFileName);
1632
0
        commandLines.push_back(cmMakeCommandLine(
1633
0
          { cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile }));
1634
0
        this->AddGeneratedSource(outputFile, this->Moc);
1635
0
      }
1636
0
      cc = cm::make_unique<cmCustomCommand>();
1637
0
      cc->SetOutputs(outputFile);
1638
0
      cc->SetByproducts(timestampByproducts);
1639
0
      cc->SetDepends(dependencies);
1640
0
      cc->SetCommandLines(commandLines);
1641
0
      cc->SetComment(autogenComment.c_str());
1642
0
      cc->SetWorkingDirectory(this->Dir.Work.c_str());
1643
0
      cc->SetEscapeOldStyle(false);
1644
0
      cc->SetDepfile(depFile);
1645
0
      cc->SetStdPipesUTF8(stdPipesUTF8);
1646
0
      this->LocalGen->AddCustomCommandToOutput(std::move(cc));
1647
0
      dependencies.clear();
1648
0
      dependencies.emplace_back(std::move(outputFile));
1649
0
      commandLines.clear();
1650
0
      autogenComment.clear();
1651
0
    }
1652
1653
    // Create autogen target
1654
0
    auto cc = cm::make_unique<cmCustomCommand>();
1655
0
    cc->SetWorkingDirectory(this->Dir.Work.c_str());
1656
0
    cc->SetByproducts(autogenByproducts);
1657
0
    cc->SetDepends(dependencies);
1658
0
    cc->SetCommandLines(commandLines);
1659
0
    cc->SetEscapeOldStyle(false);
1660
0
    cc->SetComment(autogenComment.c_str());
1661
0
    cmTarget* autogenTarget = this->LocalGen->AddUtilityCommand(
1662
0
      this->AutogenTarget.Name, true, std::move(cc));
1663
    // Create autogen generator target
1664
0
    this->LocalGen->AddGeneratorTarget(
1665
0
      cm::make_unique<cmGeneratorTarget>(autogenTarget, this->LocalGen));
1666
1667
    // Order the autogen target(s) just before the original target.
1668
0
    cmTarget* orderTarget = timestampTarget ? timestampTarget : autogenTarget;
1669
    // Forward origin utilities to autogen target
1670
0
    if (this->AutogenTarget.DependOrigin) {
1671
0
      for (BT<std::pair<std::string, bool>> const& depName :
1672
0
           this->GenTarget->GetUtilities()) {
1673
0
        orderTarget->AddUtility(depName.Value.first, false, this->Makefile);
1674
0
      }
1675
0
    }
1676
1677
    // Add additional autogen target dependencies to autogen target
1678
0
    for (cmTarget const* depTarget : this->AutogenTarget.DependTargets) {
1679
0
      orderTarget->AddUtility(depTarget->GetName(), false, this->Makefile);
1680
0
    }
1681
1682
    // Set FOLDER property in autogen target
1683
0
    if (!this->TargetsFolder.empty()) {
1684
0
      autogenTarget->SetProperty("FOLDER", this->TargetsFolder);
1685
0
    }
1686
1687
    // Add autogen target to the origin target dependencies
1688
0
    this->GenTarget->Target->AddUtility(this->AutogenTarget.Name, false,
1689
0
                                        this->Makefile);
1690
1691
    // Add autogen target to the global autogen target dependencies
1692
0
    if (this->AutogenTarget.GlobalTarget) {
1693
0
      this->GlobalInitializer->AddToGlobalAutoGen(this->LocalGen,
1694
0
                                                  this->AutogenTarget.Name);
1695
0
    }
1696
0
  }
1697
1698
0
  return true;
1699
0
}
1700
1701
void cmQtAutoGenInitializer::AddCMakeProcessToCommandLines(
1702
  std::string const& infoFile, std::string const& processName,
1703
  cmCustomCommandLines& commandLines)
1704
0
{
1705
0
  std::vector<std::string> autogenConfigs;
1706
0
  this->GlobalGen->GetQtAutoGenConfigs(autogenConfigs);
1707
0
  if (this->CrossConfig && this->UseBetterGraph) {
1708
0
    commandLines.push_back(cmMakeCommandLine(
1709
0
      { cmSystemTools::GetCMakeCommand(), "-E", processName, infoFile,
1710
0
        "$<CONFIG>", "$<COMMAND_CONFIG:$<CONFIG>>" }));
1711
0
  } else if ((this->MultiConfig && this->GlobalGen->IsXcode()) ||
1712
0
             this->CrossConfig) {
1713
0
    auto const& configs =
1714
0
      processName == "cmake_autorcc" ? this->ConfigsList : autogenConfigs;
1715
0
    for (std::string const& config : configs) {
1716
0
      commandLines.push_back(
1717
0
        cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E",
1718
0
                            processName, infoFile, config }));
1719
0
    }
1720
0
  } else {
1721
0
    std::string autoInfoFileConfig;
1722
0
    if (this->MultiConfig) {
1723
0
      autoInfoFileConfig = "$<CONFIG>";
1724
0
    } else {
1725
0
      autoInfoFileConfig = autogenConfigs[0];
1726
0
    }
1727
0
    commandLines.push_back(
1728
0
      cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", processName,
1729
0
                          infoFile, autoInfoFileConfig }));
1730
0
  }
1731
0
}
1732
1733
bool cmQtAutoGenInitializer::InitRccTargets()
1734
0
{
1735
0
  for (Qrc const& qrc : this->Rcc.Qrcs) {
1736
    // Register info file as generated by CMake
1737
0
    this->Makefile->AddCMakeOutputFile(qrc.InfoFile);
1738
    // Register file at target
1739
0
    this->AddGeneratedSource(qrc.OutputFile, this->Rcc);
1740
1741
    // Set SKIP_UNITY_BUILD_INCLUSION property on generated source(s)
1742
0
    auto setSkipUnity = [this](std::string const& path) {
1743
0
      if (cmSourceFile* sf = this->Makefile->GetSource(path)) {
1744
0
        sf->SetProperty("SKIP_UNITY_BUILD_INCLUSION", "On");
1745
0
      }
1746
0
    };
1747
0
    if (!this->MultiConfig || this->GlobalGen->IsXcode()) {
1748
0
      setSkipUnity(qrc.OutputFile.Default);
1749
0
    } else {
1750
0
      for (auto const& p : qrc.OutputFile.Config) {
1751
0
        setSkipUnity(p.second);
1752
0
      }
1753
0
    }
1754
1755
0
    std::vector<std::string> ccOutput{ qrc.OutputFileGenex };
1756
1757
    // Add the .qrc and info file to the custom command dependencies
1758
0
    std::vector<std::string> ccDepends{ qrc.QrcFile, qrc.InfoFile };
1759
1760
0
    cmCustomCommandLines commandLines;
1761
0
    AddCMakeProcessToCommandLines(qrc.InfoFile, "cmake_autorcc", commandLines);
1762
1763
0
    std::string const ccComment =
1764
0
      cmStrCat("Automatic RCC for ",
1765
0
               FileProjectRelativePath(this->Makefile, qrc.QrcFile));
1766
1767
0
    auto cc = cm::make_unique<cmCustomCommand>();
1768
0
    cc->SetWorkingDirectory(this->Dir.Work.c_str());
1769
0
    cc->SetCommandLines(commandLines);
1770
0
    cc->SetComment(ccComment.c_str());
1771
0
    cc->SetStdPipesUTF8(true);
1772
1773
0
    if (qrc.Generated || this->Rcc.GlobalTarget) {
1774
      // Create custom rcc target
1775
0
      std::string ccName;
1776
0
      {
1777
0
        ccName = cmStrCat(this->GenTarget->GetName(), "_arcc_", qrc.QrcName);
1778
0
        if (!qrc.Unique) {
1779
0
          ccName += cmStrCat('_', qrc.QrcPathChecksum);
1780
0
        }
1781
1782
0
        cc->SetByproducts(ccOutput);
1783
0
        cc->SetDepends(ccDepends);
1784
0
        cc->SetEscapeOldStyle(false);
1785
0
        cmTarget* autoRccTarget =
1786
0
          this->LocalGen->AddUtilityCommand(ccName, true, std::move(cc));
1787
1788
        // Create autogen generator target
1789
0
        this->LocalGen->AddGeneratorTarget(
1790
0
          cm::make_unique<cmGeneratorTarget>(autoRccTarget, this->LocalGen));
1791
1792
        // Set FOLDER property in autogen target
1793
0
        if (!this->TargetsFolder.empty()) {
1794
0
          autoRccTarget->SetProperty("FOLDER", this->TargetsFolder);
1795
0
        }
1796
0
        if (!this->Rcc.ExecutableTargetName.empty()) {
1797
0
          autoRccTarget->AddUtility(this->Rcc.ExecutableTargetName, false,
1798
0
                                    this->Makefile);
1799
0
        }
1800
0
      }
1801
      // Add autogen target to the origin target dependencies
1802
0
      this->GenTarget->Target->AddUtility(ccName, false, this->Makefile);
1803
1804
      // Add autogen target to the global autogen target dependencies
1805
0
      if (this->Rcc.GlobalTarget) {
1806
0
        this->GlobalInitializer->AddToGlobalAutoRcc(this->LocalGen, ccName);
1807
0
      }
1808
0
    } else {
1809
      // Create custom rcc command
1810
0
      {
1811
        // Add the resource files to the dependencies
1812
0
        if (this->MultiConfig && this->UseBetterGraph) {
1813
0
          for (auto const& config : this->ConfigsList) {
1814
            // Add resource file to the custom command dependencies
1815
0
            auto resourceFilesWithConfig = cmStrCat(
1816
0
              "$<$<CONFIG:", config,
1817
0
              ">:", cmList{ qrc.Resources.Config.at(config) }.to_string(),
1818
0
              '>');
1819
0
            ccDepends.emplace_back(std::move(resourceFilesWithConfig));
1820
0
          }
1821
0
        } else {
1822
0
          for (std::string const& fileName : qrc.Resources.Default) {
1823
            // Add resource file to the custom command dependencies
1824
0
            ccDepends.push_back(fileName);
1825
0
          }
1826
0
        }
1827
1828
0
        if (!this->Rcc.ExecutableTargetName.empty()) {
1829
0
          ccDepends.push_back(this->Rcc.ExecutableTargetName);
1830
0
        }
1831
1832
0
        AddAutogenExecutableToDependencies(this->Rcc, ccDepends);
1833
1834
0
        cc->SetOutputs(ccOutput);
1835
0
        cc->SetDepends(ccDepends);
1836
0
        this->LocalGen->AddCustomCommandToOutput(std::move(cc));
1837
0
      }
1838
      // Reconfigure when .qrc file changes
1839
0
      this->Makefile->AddCMakeDependFile(qrc.QrcFile);
1840
0
    }
1841
0
  }
1842
1843
0
  return true;
1844
0
}
1845
1846
bool cmQtAutoGenInitializer::SetupCustomTargets()
1847
0
{
1848
  // Create info directory on demand
1849
0
  if (!cmSystemTools::MakeDirectory(this->Dir.Info)) {
1850
0
    cmSystemTools::Error(cmStrCat("AutoGen: Could not create directory: ",
1851
0
                                  Quoted(this->Dir.Info)));
1852
0
    return false;
1853
0
  }
1854
1855
  // Generate autogen target info file
1856
0
  if (this->MocOrUicEnabled()) {
1857
    // Write autogen target info files
1858
0
    if (!this->SetupWriteAutogenInfo()) {
1859
0
      return false;
1860
0
    }
1861
0
  }
1862
1863
  // Write AUTORCC info files
1864
0
  return !this->Rcc.Enabled || this->SetupWriteRccInfo();
1865
0
}
1866
1867
bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
1868
0
{
1869
  // Utility lambdas
1870
0
  auto MfDef = [this](std::string const& key) {
1871
0
    return this->Makefile->GetSafeDefinition(key);
1872
0
  };
1873
1874
  // Filtered headers and sources
1875
0
  std::set<std::string> moc_skip;
1876
0
  std::set<std::string> uic_skip;
1877
0
  std::vector<MUFile const*> headers;
1878
0
  std::vector<MUFile const*> sources;
1879
1880
  // Filter headers
1881
0
  {
1882
0
    headers.reserve(this->AutogenTarget.Headers.size());
1883
0
    for (auto const& pair : this->AutogenTarget.Headers) {
1884
0
      MUFile const* const muf = pair.second.get();
1885
0
      if (muf->SkipMoc) {
1886
0
        moc_skip.insert(muf->FullPath);
1887
0
      }
1888
0
      if (muf->SkipUic) {
1889
0
        uic_skip.insert(muf->FullPath);
1890
0
      }
1891
0
      if (muf->Generated && !this->CMP0071Accept) {
1892
0
        continue;
1893
0
      }
1894
0
      if (muf->MocIt || muf->UicIt) {
1895
0
        headers.emplace_back(muf);
1896
0
      }
1897
0
    }
1898
0
    std::sort(headers.begin(), headers.end(),
1899
0
              [](MUFile const* a, MUFile const* b) {
1900
0
                return (a->FullPath < b->FullPath);
1901
0
              });
1902
0
  }
1903
1904
  // Filter sources
1905
0
  {
1906
0
    sources.reserve(this->AutogenTarget.Sources.size());
1907
0
    for (auto const& pair : this->AutogenTarget.Sources) {
1908
0
      MUFile const* const muf = pair.second.get();
1909
0
      if (muf->Generated && !this->CMP0071Accept) {
1910
0
        continue;
1911
0
      }
1912
0
      if (muf->SkipMoc) {
1913
0
        moc_skip.insert(muf->FullPath);
1914
0
      }
1915
0
      if (muf->SkipUic) {
1916
0
        uic_skip.insert(muf->FullPath);
1917
0
      }
1918
0
      if (muf->MocIt || muf->UicIt) {
1919
0
        sources.emplace_back(muf);
1920
0
      }
1921
0
    }
1922
0
    std::sort(sources.begin(), sources.end(),
1923
0
              [](MUFile const* a, MUFile const* b) {
1924
0
                return (a->FullPath < b->FullPath);
1925
0
              });
1926
0
  }
1927
1928
  // Info writer
1929
0
  InfoWriter info;
1930
1931
  // General
1932
0
  info.SetBool("MULTI_CONFIG", this->MultiConfig);
1933
0
  info.SetBool("CROSS_CONFIG", this->CrossConfig);
1934
0
  info.SetBool("USE_BETTER_GRAPH", this->UseBetterGraph);
1935
0
  info.SetUInt("PARALLEL", this->AutogenTarget.Parallel);
1936
#ifdef _WIN32
1937
  info.SetUInt("AUTOGEN_COMMAND_LINE_LENGTH_MAX",
1938
               this->AutogenTarget.MaxCommandLineLength);
1939
#endif
1940
0
  info.SetUInt("VERBOSITY", this->Verbosity);
1941
1942
  // Directories
1943
0
  info.Set("CMAKE_SOURCE_DIR", MfDef("CMAKE_SOURCE_DIR"));
1944
0
  info.Set("CMAKE_BINARY_DIR", MfDef("CMAKE_BINARY_DIR"));
1945
0
  info.Set("CMAKE_CURRENT_SOURCE_DIR", MfDef("CMAKE_CURRENT_SOURCE_DIR"));
1946
0
  info.Set("CMAKE_CURRENT_BINARY_DIR", MfDef("CMAKE_CURRENT_BINARY_DIR"));
1947
0
  info.Set("BUILD_DIR", this->Dir.Build);
1948
0
  info.SetConfig("INCLUDE_DIR", this->Dir.Include);
1949
1950
0
  info.SetUInt("QT_VERSION_MAJOR", this->QtVersion.Major);
1951
0
  info.SetUInt("QT_VERSION_MINOR", this->QtVersion.Minor);
1952
0
  info.SetConfig("QT_MOC_EXECUTABLE", this->Moc.Executable);
1953
0
  info.SetConfig("QT_UIC_EXECUTABLE", this->Uic.Executable);
1954
1955
0
  info.Set("CMAKE_EXECUTABLE", cmSystemTools::GetCMakeCommand());
1956
0
  info.SetConfig("SETTINGS_FILE", this->AutogenTarget.SettingsFile);
1957
0
  info.SetConfig("PARSE_CACHE_FILE", this->AutogenTarget.ParseCacheFile);
1958
0
  info.SetConfig("DEP_FILE", this->AutogenTarget.DepFile);
1959
0
  info.SetConfig("DEP_FILE_RULE_NAME", this->AutogenTarget.DepFileRuleName);
1960
0
  info.SetArray("CMAKE_LIST_FILES", this->Makefile->GetListFiles());
1961
0
  info.SetArray("HEADER_EXTENSIONS",
1962
0
                this->Makefile->GetCMakeInstance()->GetHeaderExtensions());
1963
0
  auto cfgArray = [this](std::vector<size_t> const& configs) -> Json::Value {
1964
0
    Json::Value value;
1965
0
    if (!configs.empty()) {
1966
0
      value = Json::arrayValue;
1967
0
      for (size_t ci : configs) {
1968
0
        value.append(this->ConfigsList[ci]);
1969
0
      }
1970
0
    }
1971
0
    return value;
1972
0
  };
1973
0
  info.SetArrayArray("HEADERS", headers,
1974
0
                     [this, &cfgArray](Json::Value& jval, MUFile const* muf) {
1975
0
                       jval.resize(4u);
1976
0
                       jval[0u] = muf->FullPath;
1977
0
                       jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm',
1978
0
                                           muf->UicIt ? 'U' : 'u');
1979
0
                       jval[2u] = this->GetMocBuildPath(*muf);
1980
0
                       jval[3u] = cfgArray(muf->Configs);
1981
0
                     });
1982
0
  info.SetArrayArray(
1983
0
    "SOURCES", sources, [&cfgArray](Json::Value& jval, MUFile const* muf) {
1984
0
      jval.resize(3u);
1985
0
      jval[0u] = muf->FullPath;
1986
0
      jval[1u] = cmStrCat(muf->MocIt ? 'M' : 'm', muf->UicIt ? 'U' : 'u');
1987
0
      jval[2u] = cfgArray(muf->Configs);
1988
0
    });
1989
1990
  // Write moc settings
1991
0
  if (this->Moc.Enabled) {
1992
0
    info.SetArray("MOC_SKIP", moc_skip);
1993
0
    info.SetConfigArray("MOC_DEFINITIONS", this->Moc.Defines);
1994
0
    info.SetConfigArray("MOC_INCLUDES", this->Moc.Includes);
1995
0
    info.SetArray("MOC_OPTIONS", this->Moc.Options);
1996
0
    info.SetBool("MOC_RELAXED_MODE", this->Moc.RelaxedMode);
1997
0
    info.SetBool("MOC_PATH_PREFIX", this->Moc.PathPrefix);
1998
1999
0
    cm::EvaluatedTargetPropertyEntries InterfaceAutoMocMacroNamesEntries;
2000
2001
0
    if (this->MultiConfig) {
2002
0
      for (auto const& cfg : this->ConfigsList) {
2003
0
        if (!cfg.empty()) {
2004
0
          cm::GenEx::Context context(this->LocalGen, cfg, "CXX");
2005
0
          cmGeneratorExpressionDAGChecker dagChecker{
2006
0
            this->GenTarget, "AUTOMOC_MACRO_NAMES", nullptr, nullptr, context,
2007
0
          };
2008
0
          cm::AddInterfaceEntries(
2009
0
            this->GenTarget, "INTERFACE_AUTOMOC_MACRO_NAMES", context,
2010
0
            &dagChecker, InterfaceAutoMocMacroNamesEntries,
2011
0
            cm::IncludeRuntimeInterface::Yes);
2012
0
        }
2013
0
      }
2014
0
    } else {
2015
0
      cm::GenEx::Context context(this->LocalGen, this->ConfigDefault, "CXX");
2016
0
      cmGeneratorExpressionDAGChecker dagChecker{
2017
0
        this->GenTarget, "AUTOMOC_MACRO_NAMES", nullptr, nullptr, context,
2018
0
      };
2019
0
      AddInterfaceEntries(
2020
0
        this->GenTarget, "INTERFACE_AUTOMOC_MACRO_NAMES", context, &dagChecker,
2021
0
        InterfaceAutoMocMacroNamesEntries, cm::IncludeRuntimeInterface::Yes);
2022
0
    }
2023
2024
0
    for (auto const& entry : InterfaceAutoMocMacroNamesEntries.Entries) {
2025
0
      this->Moc.MacroNames.insert(this->Moc.MacroNames.end(),
2026
0
                                  entry.Values.begin(), entry.Values.end());
2027
0
    }
2028
0
    this->Moc.MacroNames.erase(cmRemoveDuplicates(this->Moc.MacroNames),
2029
0
                               this->Moc.MacroNames.end());
2030
2031
0
    info.SetArray("MOC_MACRO_NAMES", this->Moc.MacroNames);
2032
0
    info.SetArrayArray(
2033
0
      "MOC_DEPEND_FILTERS", this->Moc.DependFilters,
2034
0
      [](Json::Value& jval, std::pair<std::string, std::string> const& pair) {
2035
0
        jval.resize(2u);
2036
0
        jval[0u] = pair.first;
2037
0
        jval[1u] = pair.second;
2038
0
      });
2039
0
    info.SetConfig("MOC_COMPILATION_FILE", this->Moc.CompilationFile);
2040
0
    info.SetConfig("MOC_PREDEFS_FILE", this->Moc.PredefsFile);
2041
2042
0
    cmStandardLevelResolver const resolver{ this->Makefile };
2043
0
    auto const CompileOptionFlag =
2044
0
      resolver.GetCompileOptionDef(this->GenTarget, "CXX", "");
2045
2046
0
    auto const CompileOptionValue =
2047
0
      this->GenTarget->Makefile->GetSafeDefinition(CompileOptionFlag);
2048
2049
0
    if (!CompileOptionValue.empty()) {
2050
      // Determine where to insert the compile option (e.g., -std=gnu++23).
2051
      // CMAKE_CXX_COMPILER_PREDEFINES_COMMAND is built as:
2052
      //   [CMAKE_CXX_COMPILER, CMAKE_CXX_COMPILER_ARG1, predefs_flags...]
2053
      // We need to insert after all compiler elements, before predefs flags.
2054
0
      size_t compilerElements = 1; // CMAKE_CXX_COMPILER
2055
2056
0
      cmValue compilerArg1 =
2057
0
        this->Makefile->GetDefinition("CMAKE_CXX_COMPILER_ARG1");
2058
0
      if (compilerArg1 && !compilerArg1->empty()) {
2059
0
        std::vector<std::string> arg1List;
2060
0
        cmSystemTools::ParseUnixCommandLine(compilerArg1->c_str(), arg1List);
2061
0
        compilerElements += arg1List.size();
2062
0
      }
2063
2064
0
      if (this->Moc.PredefsCmd.size() > compilerElements) {
2065
0
        this->Moc.PredefsCmd.insert(
2066
0
          this->Moc.PredefsCmd.begin() + compilerElements, CompileOptionValue);
2067
0
      }
2068
0
    }
2069
0
    info.SetArray("MOC_PREDEFS_CMD", this->Moc.PredefsCmd);
2070
0
  }
2071
2072
  // Write uic settings
2073
0
  if (this->Uic.Enabled) {
2074
    // Add skipped .ui files
2075
0
    uic_skip.insert(this->Uic.SkipUi.begin(), this->Uic.SkipUi.end());
2076
2077
0
    info.SetArray("UIC_SKIP", uic_skip);
2078
0
    info.SetArrayArray("UIC_UI_FILES", this->Uic.UiFilesWithOptions,
2079
0
                       [](Json::Value& jval, UicT::UiFileT const& uiFile) {
2080
0
                         jval.resize(2u);
2081
0
                         jval[0u] = uiFile.first;
2082
0
                         InfoWriter::MakeStringArray(jval[1u], uiFile.second);
2083
0
                       });
2084
0
    info.SetConfigArray("UIC_OPTIONS", this->Uic.Options);
2085
0
    info.SetArray("UIC_SEARCH_PATHS", this->Uic.SearchPaths);
2086
0
  }
2087
2088
0
  info.Save(this->AutogenTarget.InfoFile);
2089
2090
0
  return true;
2091
0
}
2092
2093
bool cmQtAutoGenInitializer::SetupWriteRccInfo()
2094
0
{
2095
0
  for (Qrc const& qrc : this->Rcc.Qrcs) {
2096
    // Utility lambdas
2097
0
    auto MfDef = [this](std::string const& key) {
2098
0
      return this->Makefile->GetSafeDefinition(key);
2099
0
    };
2100
2101
0
    InfoWriter info;
2102
2103
    // General
2104
0
    info.SetBool("MULTI_CONFIG", this->MultiConfig);
2105
0
    info.SetBool("CROSS_CONFIG", this->CrossConfig);
2106
0
    info.SetBool("USE_BETTER_GRAPH", this->UseBetterGraph);
2107
0
    info.SetUInt("VERBOSITY", this->Verbosity);
2108
0
    info.Set("GENERATOR", this->GlobalGen->GetName());
2109
2110
    // Files
2111
0
    info.Set("LOCK_FILE", qrc.LockFile);
2112
0
    info.SetConfig("SETTINGS_FILE", qrc.SettingsFile);
2113
2114
    // Directories
2115
0
    info.Set("CMAKE_SOURCE_DIR", MfDef("CMAKE_SOURCE_DIR"));
2116
0
    info.Set("CMAKE_BINARY_DIR", MfDef("CMAKE_BINARY_DIR"));
2117
0
    info.Set("CMAKE_CURRENT_SOURCE_DIR", MfDef("CMAKE_CURRENT_SOURCE_DIR"));
2118
0
    info.Set("CMAKE_CURRENT_BINARY_DIR", MfDef("CMAKE_CURRENT_BINARY_DIR"));
2119
0
    info.Set("BUILD_DIR", this->Dir.Build);
2120
0
    info.SetConfig("INCLUDE_DIR", this->Dir.Include);
2121
2122
    // rcc executable
2123
0
    info.SetConfig("RCC_EXECUTABLE", this->Rcc.Executable);
2124
0
    info.SetConfigArray(
2125
0
      "RCC_LIST_OPTIONS",
2126
0
      generateListOptions(this->Rcc.ExecutableFeatures, this->MultiConfig));
2127
2128
    // qrc file
2129
0
    info.Set("SOURCE", qrc.QrcFile);
2130
0
    info.Set("OUTPUT_CHECKSUM", qrc.QrcPathChecksum);
2131
0
    info.Set("OUTPUT_NAME",
2132
0
             cmSystemTools::GetFilenameName(qrc.OutputFileGenex));
2133
0
    info.SetArray("OPTIONS", qrc.Options);
2134
0
    info.SetConfigArray("INPUTS", qrc.Resources);
2135
2136
0
    info.Save(qrc.InfoFile);
2137
0
  }
2138
2139
0
  return true;
2140
0
}
2141
2142
cmSourceFile* cmQtAutoGenInitializer::RegisterGeneratedSource(
2143
  std::string const& filename)
2144
0
{
2145
0
  cmSourceFile* gFile = this->Makefile->GetOrCreateSource(filename, true);
2146
0
  gFile->SetSpecialSourceType(
2147
0
    cmSourceFile::SpecialSourceType::QtAutogenSource);
2148
0
  gFile->MarkAsGenerated();
2149
0
  gFile->SetProperty("SKIP_AUTOGEN", "1");
2150
0
  gFile->SetProperty("SKIP_LINTING", "ON");
2151
0
  gFile->SetProperty("CXX_SCAN_FOR_MODULES", "0");
2152
0
  return gFile;
2153
0
}
2154
2155
cmSourceFile* cmQtAutoGenInitializer::AddGeneratedSource(
2156
  std::string const& filename, GenVarsT const& genVars, bool prepend)
2157
0
{
2158
  // Register source at makefile
2159
0
  cmSourceFile* gFile = this->RegisterGeneratedSource(filename);
2160
  // Add source file to target
2161
0
  this->GenTarget->AddSource(filename, prepend);
2162
2163
  // Add source file to source group
2164
0
  this->AddToSourceGroup(filename, genVars.GenNameUpper);
2165
2166
0
  return gFile;
2167
0
}
2168
2169
void cmQtAutoGenInitializer::AddGeneratedSource(ConfigString const& filename,
2170
                                                GenVarsT const& genVars,
2171
                                                bool prepend)
2172
0
{
2173
  // XXX(xcode-per-cfg-src): Drop the Xcode-specific part of the condition
2174
  // when the Xcode generator supports per-config sources.
2175
0
  if (!this->MultiConfig || this->GlobalGen->IsXcode()) {
2176
0
    cmSourceFile* sf =
2177
0
      this->AddGeneratedSource(filename.Default, genVars, prepend);
2178
0
    handleSkipPch(sf);
2179
0
    return;
2180
0
  }
2181
0
  for (auto const& cfg : this->ConfigsList) {
2182
0
    std::string const& filenameCfg = filename.Config.at(cfg);
2183
    // Register source at makefile
2184
0
    cmSourceFile* sf = this->RegisterGeneratedSource(filenameCfg);
2185
0
    handleSkipPch(sf);
2186
    // Add source file to target for this configuration.
2187
0
    this->GenTarget->AddSource(
2188
0
      cmStrCat("$<$<CONFIG:"_s, cfg, ">:"_s, filenameCfg, ">"_s), prepend);
2189
    // Add source file to source group
2190
0
    this->AddToSourceGroup(filenameCfg, genVars.GenNameUpper);
2191
0
  }
2192
0
}
2193
2194
void cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName,
2195
                                              cm::string_view genNameUpper)
2196
0
{
2197
0
  cmSourceGroup* sourceGroup = nullptr;
2198
  // Acquire source group
2199
0
  {
2200
0
    std::string property;
2201
0
    std::string groupName;
2202
0
    {
2203
      // Prefer generator specific source group name
2204
0
      std::initializer_list<std::string> const props{
2205
0
        cmStrCat(genNameUpper, "_SOURCE_GROUP"), "AUTOGEN_SOURCE_GROUP"
2206
0
      };
2207
0
      for (std::string const& prop : props) {
2208
0
        cmValue propName = this->Makefile->GetState()->GetGlobalProperty(prop);
2209
0
        if (cmNonempty(propName)) {
2210
0
          groupName = *propName;
2211
0
          property = prop;
2212
0
          break;
2213
0
        }
2214
0
      }
2215
0
    }
2216
    // Generate a source group on demand
2217
0
    if (!groupName.empty()) {
2218
0
      sourceGroup = this->Makefile->GetOrCreateSourceGroup(groupName);
2219
0
      if (!sourceGroup) {
2220
0
        cmSystemTools::Error(
2221
0
          cmStrCat(genNameUpper, " error in ", property,
2222
0
                   ": Could not find or create the source group ",
2223
0
                   cmQtAutoGen::Quoted(groupName)));
2224
0
      }
2225
0
    }
2226
0
  }
2227
0
  if (sourceGroup) {
2228
0
    sourceGroup->AddGroupFile(fileName);
2229
0
  }
2230
0
}
2231
2232
void cmQtAutoGenInitializer::AddCleanFile(std::string const& fileName)
2233
0
{
2234
0
  this->GenTarget->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", fileName);
2235
0
}
2236
2237
void cmQtAutoGenInitializer::ConfigFileNames(ConfigString& configString,
2238
                                             cm::string_view prefix,
2239
                                             cm::string_view suffix)
2240
0
{
2241
0
  configString.Default = cmStrCat(prefix, suffix);
2242
0
  if (this->MultiConfig) {
2243
0
    for (auto const& cfg : this->ConfigsList) {
2244
0
      configString.Config[cfg] = cmStrCat(prefix, '_', cfg, suffix);
2245
0
    }
2246
0
  }
2247
0
}
2248
2249
void cmQtAutoGenInitializer::ConfigFileNamesAndGenex(
2250
  ConfigString& configString, std::string& genex, cm::string_view const prefix,
2251
  cm::string_view const suffix)
2252
0
{
2253
0
  this->ConfigFileNames(configString, prefix, suffix);
2254
0
  if (this->MultiConfig) {
2255
0
    genex = cmStrCat(prefix, "_$<CONFIG>"_s, suffix);
2256
0
  } else {
2257
0
    genex = configString.Default;
2258
0
  }
2259
0
}
2260
2261
void cmQtAutoGenInitializer::ConfigFileNameCommon(ConfigString& configString,
2262
                                                  std::string const& fileName)
2263
0
{
2264
0
  configString.Default = fileName;
2265
0
  if (this->MultiConfig) {
2266
0
    for (auto const& cfg : this->ConfigsList) {
2267
0
      configString.Config[cfg] = fileName;
2268
0
    }
2269
0
  }
2270
0
}
2271
2272
void cmQtAutoGenInitializer::ConfigFileClean(ConfigString& configString)
2273
0
{
2274
0
  this->AddCleanFile(configString.Default);
2275
0
  if (this->MultiConfig) {
2276
0
    for (auto const& pair : configString.Config) {
2277
0
      this->AddCleanFile(pair.second);
2278
0
    }
2279
0
  }
2280
0
}
2281
2282
static cmQtAutoGen::IntegerVersion parseMocVersion(std::string str)
2283
0
{
2284
0
  cmQtAutoGen::IntegerVersion result;
2285
2286
0
  static std::string const prelude = "moc ";
2287
0
  size_t const pos = str.find(prelude);
2288
0
  if (pos == std::string::npos) {
2289
0
    return result;
2290
0
  }
2291
2292
0
  str.erase(0, prelude.size() + pos);
2293
0
  std::istringstream iss(str);
2294
0
  std::string major;
2295
0
  std::string minor;
2296
0
  if (!std::getline(iss, major, '.') || !std::getline(iss, minor, '.')) {
2297
0
    return result;
2298
0
  }
2299
2300
0
  result.Major = static_cast<unsigned int>(std::stoi(major));
2301
0
  result.Minor = static_cast<unsigned int>(std::stoi(minor));
2302
0
  return result;
2303
0
}
2304
2305
static cmQtAutoGen::IntegerVersion GetMocVersion(
2306
  std::string const& mocExecutablePath)
2307
0
{
2308
0
  std::string capturedStdOut;
2309
0
  int exitCode;
2310
0
  if (!cmSystemTools::RunSingleCommand({ mocExecutablePath, "--version" },
2311
0
                                       &capturedStdOut, nullptr, &exitCode,
2312
0
                                       nullptr, cmSystemTools::OUTPUT_NONE)) {
2313
0
    return {};
2314
0
  }
2315
2316
0
  if (exitCode != 0) {
2317
0
    return {};
2318
0
  }
2319
2320
0
  return parseMocVersion(capturedStdOut);
2321
0
}
2322
2323
static std::string FindMocExecutableFromMocTarget(cmMakefile const* makefile,
2324
                                                  unsigned int qtMajorVersion)
2325
0
{
2326
0
  std::string result;
2327
0
  std::string const mocTargetName = cmStrCat("Qt", qtMajorVersion, "::moc");
2328
0
  cmTarget const* mocTarget = makefile->FindTargetToUse(mocTargetName);
2329
0
  if (mocTarget) {
2330
0
    result = mocTarget->GetSafeProperty("IMPORTED_LOCATION");
2331
0
  }
2332
0
  return result;
2333
0
}
2334
2335
std::pair<cmQtAutoGen::IntegerVersion, unsigned int>
2336
cmQtAutoGenInitializer::GetQtVersion(cmGeneratorTarget const* target,
2337
                                     std::string mocExecutable)
2338
0
{
2339
  // Converts a char ptr to an unsigned int value
2340
0
  auto toUInt = [](char const* const input) -> unsigned int {
2341
0
    unsigned long tmp = 0;
2342
0
    if (input && cmStrToULong(input, &tmp)) {
2343
0
      return static_cast<unsigned int>(tmp);
2344
0
    }
2345
0
    return 0u;
2346
0
  };
2347
0
  auto toUInt2 = [](cmValue input) -> unsigned int {
2348
0
    unsigned long tmp = 0;
2349
0
    if (input && cmStrToULong(*input, &tmp)) {
2350
0
      return static_cast<unsigned int>(tmp);
2351
0
    }
2352
0
    return 0u;
2353
0
  };
2354
2355
  // Initialize return value to a default
2356
0
  std::pair<IntegerVersion, unsigned int> res(
2357
0
    IntegerVersion(),
2358
0
    toUInt(target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION",
2359
0
                                                           "")));
2360
2361
  // Acquire known Qt versions
2362
0
  std::vector<cmQtAutoGen::IntegerVersion> knownQtVersions;
2363
0
  {
2364
    // Qt version variable prefixes
2365
0
    static std::initializer_list<
2366
0
      std::pair<cm::string_view, cm::string_view>> const keys{
2367
0
      { "Qt6Core_VERSION_MAJOR", "Qt6Core_VERSION_MINOR" },
2368
0
      { "Qt5Core_VERSION_MAJOR", "Qt5Core_VERSION_MINOR" },
2369
0
      { "QT_VERSION_MAJOR", "QT_VERSION_MINOR" },
2370
0
    };
2371
2372
0
    knownQtVersions.reserve(keys.size() * 2);
2373
2374
    // Adds a version to the result (nullptr safe)
2375
0
    auto addVersion = [&knownQtVersions, &toUInt2](cmValue major,
2376
0
                                                   cmValue minor) {
2377
0
      cmQtAutoGen::IntegerVersion ver(toUInt2(major), toUInt2(minor));
2378
0
      if (ver.Major != 0) {
2379
0
        knownQtVersions.emplace_back(ver);
2380
0
      }
2381
0
    };
2382
2383
    // Read versions from variables
2384
0
    for (auto const& keyPair : keys) {
2385
0
      addVersion(target->Makefile->GetDefinition(std::string(keyPair.first)),
2386
0
                 target->Makefile->GetDefinition(std::string(keyPair.second)));
2387
0
    }
2388
2389
    // Read versions from directory properties
2390
0
    for (auto const& keyPair : keys) {
2391
0
      addVersion(target->Makefile->GetProperty(std::string(keyPair.first)),
2392
0
                 target->Makefile->GetProperty(std::string(keyPair.second)));
2393
0
    }
2394
0
  }
2395
2396
  // Evaluate known Qt versions
2397
0
  if (!knownQtVersions.empty()) {
2398
0
    if (res.second == 0) {
2399
      // No specific version was requested by the target:
2400
      // Use highest known Qt version.
2401
0
      res.first = knownQtVersions.at(0);
2402
0
    } else {
2403
      // Pick a version from the known versions:
2404
0
      for (auto const& it : knownQtVersions) {
2405
0
        if (it.Major == res.second) {
2406
0
          res.first = it;
2407
0
          break;
2408
0
        }
2409
0
      }
2410
0
    }
2411
0
  }
2412
2413
0
  if (res.first.Major == 0) {
2414
    // We could not get the version number from variables or directory
2415
    // properties. This might happen if the find_package call for Qt is wrapped
2416
    // in a function. Try to find the moc executable path from the available
2417
    // targets and call "moc --version" to get the Qt version.
2418
0
    if (mocExecutable.empty()) {
2419
0
      mocExecutable =
2420
0
        FindMocExecutableFromMocTarget(target->Makefile, res.second);
2421
0
    }
2422
0
    if (!mocExecutable.empty()) {
2423
0
      res.first = GetMocVersion(mocExecutable);
2424
0
    }
2425
0
  }
2426
2427
0
  return res;
2428
0
}
2429
2430
std::string cmQtAutoGenInitializer::GetMocBuildPath(MUFile const& muf)
2431
0
{
2432
0
  std::string res;
2433
0
  if (!muf.MocIt) {
2434
0
    return res;
2435
0
  }
2436
2437
0
  std::string basePath =
2438
0
    cmStrCat(this->PathCheckSum.getPart(muf.FullPath), "/moc_",
2439
0
             FileNameWithoutLastExtension(muf.FullPath));
2440
2441
0
  res = cmStrCat(basePath, ".cpp");
2442
0
  if (this->Moc.EmittedBuildPaths.emplace(res).second) {
2443
0
    return res;
2444
0
  }
2445
2446
  // File name already emitted.
2447
  // Try appending the header suffix to the base path.
2448
0
  basePath = cmStrCat(basePath, '_', muf.SF->GetExtension());
2449
0
  res = cmStrCat(basePath, ".cpp");
2450
0
  if (this->Moc.EmittedBuildPaths.emplace(res).second) {
2451
0
    return res;
2452
0
  }
2453
2454
  // File name with header extension already emitted.
2455
  // Try adding a number to the base path.
2456
0
  constexpr std::size_t number_begin = 2;
2457
0
  constexpr std::size_t number_end = 256;
2458
0
  for (std::size_t ii = number_begin; ii != number_end; ++ii) {
2459
0
    res = cmStrCat(basePath, '_', ii, ".cpp");
2460
0
    if (this->Moc.EmittedBuildPaths.emplace(res).second) {
2461
0
      return res;
2462
0
    }
2463
0
  }
2464
2465
  // Output file name conflict (unlikely, but still...)
2466
0
  cmSystemTools::Error(
2467
0
    cmStrCat("moc output file name conflict for ", muf.FullPath));
2468
2469
0
  return res;
2470
0
}
2471
2472
bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars,
2473
                                             std::string const& executable,
2474
                                             bool ignoreMissingTarget) const
2475
0
{
2476
0
  auto print_err = [this, &genVars](std::string const& err) {
2477
0
    cmSystemTools::Error(cmStrCat(genVars.GenNameUpper, " for target ",
2478
0
                                  this->GenTarget->GetName(), ": ", err));
2479
0
  };
2480
2481
  // Custom executable
2482
0
  {
2483
0
    std::string const prop = cmStrCat(genVars.GenNameUpper, "_EXECUTABLE");
2484
0
    std::string const& val = this->GenTarget->Target->GetSafeProperty(prop);
2485
0
    if (!val.empty()) {
2486
      // Evaluate generator expression
2487
0
      {
2488
0
        cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
2489
0
        cmGeneratorExpression ge(*this->Makefile->GetCMakeInstance(), lfbt);
2490
0
        std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(val);
2491
0
        if (this->MultiConfig && this->UseBetterGraph) {
2492
0
          for (auto const& config : this->ConfigsList) {
2493
0
            genVars.Executable.Config[config] =
2494
0
              cge->Evaluate(this->LocalGen, config);
2495
0
          }
2496
0
        } else {
2497
0
          genVars.Executable.Default = cge->Evaluate(this->LocalGen, "");
2498
0
        }
2499
0
      }
2500
2501
0
      if (genVars.Executable.Default.empty() &&
2502
0
          genVars.Executable.Config.empty() && !ignoreMissingTarget) {
2503
0
        print_err(prop + " evaluates to an empty value");
2504
0
        return false;
2505
0
      }
2506
2507
      // Create empty compiler features.
2508
0
      if (this->MultiConfig && this->UseBetterGraph) {
2509
0
        for (auto const& config : this->ConfigsList) {
2510
0
          genVars.ExecutableFeatures.Config[config] =
2511
0
            std::make_shared<cmQtAutoGen::CompilerFeatures>();
2512
0
        }
2513
0
      } else {
2514
0
        genVars.ExecutableFeatures.Default =
2515
0
          std::make_shared<cmQtAutoGen::CompilerFeatures>();
2516
0
      }
2517
0
      return true;
2518
0
    }
2519
0
  }
2520
2521
  // Find executable target
2522
0
  {
2523
    // Find executable target name
2524
0
    cm::string_view prefix;
2525
0
    if (this->QtVersion.Major == 4) {
2526
0
      prefix = "Qt4::";
2527
0
    } else if (this->QtVersion.Major == 5) {
2528
0
      prefix = "Qt5::";
2529
0
    } else if (this->QtVersion.Major == 6) {
2530
0
      prefix = "Qt6::";
2531
0
    }
2532
0
    std::string const targetName = cmStrCat(prefix, executable);
2533
2534
    // Find target
2535
0
    cmGeneratorTarget* genTarget =
2536
0
      this->LocalGen->FindGeneratorTargetToUse(targetName);
2537
0
    if (genTarget) {
2538
0
      genVars.ExecutableTargetName = targetName;
2539
0
      genVars.ExecutableTarget = genTarget;
2540
0
      if (genTarget->IsImported()) {
2541
0
        if (this->MultiConfig && this->UseBetterGraph) {
2542
0
          for (auto const& config : this->ConfigsList) {
2543
0
            genVars.Executable.Config[config] =
2544
0
              genTarget->ImportedGetLocation(config);
2545
0
          }
2546
0
        } else {
2547
0
          genVars.Executable.Default =
2548
0
            genTarget->ImportedGetLocation(this->ConfigDefault);
2549
0
        }
2550
2551
0
      } else {
2552
0
        if (this->MultiConfig && this->UseBetterGraph) {
2553
0
          for (auto const& config : this->ConfigsList) {
2554
0
            genVars.Executable.Config[config] = genTarget->GetLocation(config);
2555
0
          }
2556
0
        } else {
2557
0
          genVars.Executable.Default =
2558
0
            genTarget->GetLocation(this->ConfigDefault);
2559
0
        }
2560
0
      }
2561
0
    } else {
2562
0
      if (ignoreMissingTarget) {
2563
        // Create empty compiler features.
2564
0
        if (this->MultiConfig && this->UseBetterGraph) {
2565
0
          for (auto const& config : this->ConfigsList) {
2566
0
            genVars.ExecutableFeatures.Config[config] =
2567
0
              std::make_shared<cmQtAutoGen::CompilerFeatures>();
2568
0
          }
2569
0
        } else {
2570
0
          genVars.ExecutableFeatures.Default =
2571
0
            std::make_shared<cmQtAutoGen::CompilerFeatures>();
2572
0
        }
2573
2574
0
        return true;
2575
0
      }
2576
0
      print_err(cmStrCat("Could not find ", executable, " executable target ",
2577
0
                         targetName));
2578
0
      return false;
2579
0
    }
2580
0
  }
2581
2582
  // Get executable features
2583
0
  {
2584
0
    std::string err;
2585
0
    genVars.ExecutableFeatures = this->GlobalInitializer->GetCompilerFeatures(
2586
0
      executable, genVars.Executable, err, this->MultiConfig,
2587
0
      this->UseBetterGraph);
2588
0
    if (this->MultiConfig && this->UseBetterGraph) {
2589
0
      for (auto const& config : this->ConfigsList) {
2590
0
        if (!genVars.ExecutableFeatures.Config[config]) {
2591
0
          print_err(err);
2592
0
          return false;
2593
0
        }
2594
0
      }
2595
0
    } else {
2596
0
      if (!genVars.ExecutableFeatures.Default) {
2597
0
        print_err(err);
2598
0
        return false;
2599
0
      }
2600
0
    }
2601
0
  }
2602
2603
0
  return true;
2604
0
}
2605
2606
void cmQtAutoGenInitializer::handleSkipPch(cmSourceFile* sf)
2607
0
{
2608
0
  bool skipPch = true;
2609
0
  for (auto const& pair : this->AutogenTarget.Sources) {
2610
0
    if (!pair.first->GetIsGenerated() &&
2611
0
        !pair.first->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
2612
0
      skipPch = false;
2613
0
    }
2614
0
  }
2615
2616
0
  if (skipPch) {
2617
0
    sf->SetProperty("SKIP_PRECOMPILE_HEADERS", "ON");
2618
0
  }
2619
0
}