Coverage Report

Created: 2026-07-14 07:09

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