Coverage Report

Created: 2026-03-12 06:35

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