cmQtAutoGenGlobalInitializer.cxx 9.89 KB
Newer Older
1
2
3
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
#include "cmQtAutoGenGlobalInitializer.h"
4

5
#include <set>
6
7
8
9
#include <utility>

#include <cm/memory>

10
#include "cmCustomCommandLines.h"
11
#include "cmDuration.h"
12
13
#include "cmGeneratorTarget.h"
#include "cmLocalGenerator.h"
14
#include "cmMakefile.h"
15
#include "cmMessageType.h"
16
#include "cmProcessOutput.h"
17
#include "cmProperty.h"
18
19
#include "cmQtAutoGen.h"
#include "cmQtAutoGenInitializer.h"
20
21
#include "cmState.h"
#include "cmStateTypes.h"
22
#include "cmStringAlgorithms.h"
23
24
25
#include "cmSystemTools.h"
#include "cmTarget.h"

26
27
28
29
cmQtAutoGenGlobalInitializer::Keywords::Keywords()
  : AUTOMOC("AUTOMOC")
  , AUTOUIC("AUTOUIC")
  , AUTORCC("AUTORCC")
30
31
32
  , AUTOMOC_EXECUTABLE("AUTOMOC_EXECUTABLE")
  , AUTOUIC_EXECUTABLE("AUTOUIC_EXECUTABLE")
  , AUTORCC_EXECUTABLE("AUTORCC_EXECUTABLE")
33
34
35
36
37
38
39
40
  , SKIP_AUTOGEN("SKIP_AUTOGEN")
  , SKIP_AUTOMOC("SKIP_AUTOMOC")
  , SKIP_AUTOUIC("SKIP_AUTOUIC")
  , SKIP_AUTORCC("SKIP_AUTORCC")
  , AUTOUIC_OPTIONS("AUTOUIC_OPTIONS")
  , AUTORCC_OPTIONS("AUTORCC_OPTIONS")
  , qrc("qrc")
  , ui("ui")
41
42
43
{
}

44
cmQtAutoGenGlobalInitializer::cmQtAutoGenGlobalInitializer(
45
  std::vector<std::unique_ptr<cmLocalGenerator>> const& localGenerators)
46
{
47
  for (const auto& localGen : localGenerators) {
48
49
50
51
52
53
    // Detect global autogen and autorcc target names
    bool globalAutoGenTarget = false;
    bool globalAutoRccTarget = false;
    {
      cmMakefile* makefile = localGen->GetMakefile();
      // Detect global autogen target name
54
      if (makefile->IsOn("CMAKE_GLOBAL_AUTOGEN_TARGET")) {
55
56
57
58
59
        std::string targetName =
          makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTOGEN_TARGET_NAME");
        if (targetName.empty()) {
          targetName = "autogen";
        }
60
        GlobalAutoGenTargets_.emplace(localGen.get(), std::move(targetName));
61
62
63
64
        globalAutoGenTarget = true;
      }

      // Detect global autorcc target name
65
      if (makefile->IsOn("CMAKE_GLOBAL_AUTORCC_TARGET")) {
66
67
68
69
70
        std::string targetName =
          makefile->GetSafeDefinition("CMAKE_GLOBAL_AUTORCC_TARGET_NAME");
        if (targetName.empty()) {
          targetName = "autorcc";
        }
71
        GlobalAutoRccTargets_.emplace(localGen.get(), std::move(targetName));
72
73
74
75
        globalAutoRccTarget = true;
      }
    }

76
    // Find targets that require AUTOMOC/UIC/RCC processing
77
    for (const auto& target : localGen->GetGeneratorTargets()) {
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
      // Process only certain target types
      switch (target->GetType()) {
        case cmStateEnums::EXECUTABLE:
        case cmStateEnums::STATIC_LIBRARY:
        case cmStateEnums::SHARED_LIBRARY:
        case cmStateEnums::MODULE_LIBRARY:
        case cmStateEnums::OBJECT_LIBRARY:
          // Process target
          break;
        default:
          // Don't process target
          continue;
      }
      if (target->IsImported()) {
        // Don't process target
        continue;
      }
95
96
97
98
99
100
      std::set<std::string> const& languages =
        target->GetAllConfigCompileLanguages();
      if (languages.count("CSharp")) {
        // Don't process target if it's a CSharp target
        continue;
      }
101

102
103
104
      bool const moc = target->GetPropertyAsBool(kw().AUTOMOC);
      bool const uic = target->GetPropertyAsBool(kw().AUTOUIC);
      bool const rcc = target->GetPropertyAsBool(kw().AUTORCC);
105
      if (moc || uic || rcc) {
106
        std::string const& mocExec =
107
          target->GetSafeProperty(kw().AUTOMOC_EXECUTABLE);
108
        std::string const& uicExec =
109
          target->GetSafeProperty(kw().AUTOUIC_EXECUTABLE);
110
        std::string const& rccExec =
111
          target->GetSafeProperty(kw().AUTORCC_EXECUTABLE);
112
113

        // We support Qt4, Qt5 and Qt6
114
        auto qtVersion = cmQtAutoGenInitializer::GetQtVersion(target.get());
115
116
        bool const validQt = (qtVersion.first.Major == 4) ||
          (qtVersion.first.Major == 5) || (qtVersion.first.Major == 6);
117

118
119
120
121
122
        bool const mocAvailable = (validQt || !mocExec.empty());
        bool const uicAvailable = (validQt || !uicExec.empty());
        bool const rccAvailable = (validQt || !rccExec.empty());
        bool const mocIsValid = (moc && mocAvailable);
        bool const uicIsValid = (uic && uicAvailable);
123
        bool const rccIsValid = (rcc && rccAvailable);
124
125
126
127
128
        // Disabled AUTOMOC/UIC/RCC warning
        bool const mocDisabled = (moc && !mocAvailable);
        bool const uicDisabled = (uic && !uicAvailable);
        bool const rccDisabled = (rcc && !rccAvailable);
        if (mocDisabled || uicDisabled || rccDisabled) {
129
130
131
132
133
134
135
136
137
138
139
          cmAlphaNum version = (qtVersion.second == 0)
            ? cmAlphaNum("<QTVERSION>")
            : cmAlphaNum(qtVersion.second);
          cmAlphaNum component = uicDisabled ? "Widgets" : "Core";

          std::string const msg = cmStrCat(
            "AUTOGEN: No valid Qt version found for target ",
            target->GetName(), ".  ",
            cmQtAutoGen::Tools(mocDisabled, uicDisabled, rccDisabled),
            " disabled.  Consider adding:\n", "  find_package(Qt", version,
            " COMPONENTS ", component, ")\n", "to your CMakeLists.txt file.");
140
          target->Makefile->IssueMessage(MessageType::AUTHOR_WARNING, msg);
141
        }
142
        if (mocIsValid || uicIsValid || rccIsValid) {
143
144
          // Create autogen target initializer
          Initializers_.emplace_back(cm::make_unique<cmQtAutoGenInitializer>(
145
146
            this, target.get(), qtVersion.first, mocIsValid, uicIsValid,
            rccIsValid, globalAutoGenTarget, globalAutoRccTarget));
147
148
149
150
151
152
        }
      }
    }
  }
}

wahikihiki's avatar
wahikihiki committed
153
cmQtAutoGenGlobalInitializer::~cmQtAutoGenGlobalInitializer() = default;
154

155
156
157
158
159
160
161
162
163
void cmQtAutoGenGlobalInitializer::GetOrCreateGlobalTarget(
  cmLocalGenerator* localGen, std::string const& name,
  std::string const& comment)
{
  // Test if the target already exists
  if (localGen->FindGeneratorTargetToUse(name) == nullptr) {
    cmMakefile* makefile = localGen->GetMakefile();

    // Create utility target
164
165
166
167
168
169
    std::vector<std::string> no_byproducts;
    std::vector<std::string> no_depends;
    cmCustomCommandLines no_commands;
    cmTarget* target = localGen->AddUtilityCommand(
      name, true, makefile->GetHomeOutputDirectory().c_str(), no_byproducts,
      no_depends, no_commands, false, comment.c_str());
170
171
    localGen->AddGeneratorTarget(
      cm::make_unique<cmGeneratorTarget>(target, localGen));
172
173
174

    // Set FOLDER property in the target
    {
175
      cmProp folder =
176
177
        makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER");
      if (folder != nullptr) {
178
        target->SetProperty("FOLDER", *folder);
179
180
181
182
183
184
185
186
187
188
189
190
      }
    }
  }
}

void cmQtAutoGenGlobalInitializer::AddToGlobalAutoGen(
  cmLocalGenerator* localGen, std::string const& targetName)
{
  auto it = GlobalAutoGenTargets_.find(localGen);
  if (it != GlobalAutoGenTargets_.end()) {
    cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second);
    if (target != nullptr) {
191
      target->Target->AddUtility(targetName, false, localGen->GetMakefile());
192
193
194
195
196
197
198
199
200
201
202
    }
  }
}

void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc(
  cmLocalGenerator* localGen, std::string const& targetName)
{
  auto it = GlobalAutoRccTargets_.find(localGen);
  if (it != GlobalAutoRccTargets_.end()) {
    cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(it->second);
    if (target != nullptr) {
203
      target->Target->AddUtility(targetName, false, localGen->GetMakefile());
204
205
206
207
    }
  }
}

208
209
cmQtAutoGen::CompilerFeaturesHandle
cmQtAutoGenGlobalInitializer::GetCompilerFeatures(
210
  std::string const& generator, std::string const& executable,
211
  std::string& error)
212
{
213
  // Check if we have cached features
214
  {
215
216
217
    auto it = this->CompilerFeatures_.find(executable);
    if (it != this->CompilerFeatures_.end()) {
      return it->second;
218
219
220
221
222
    }
  }

  // Check if the executable exists
  if (!cmSystemTools::FileExists(executable, true)) {
223
224
    error = cmStrCat("The \"", generator, "\" executable ",
                     cmQtAutoGen::Quoted(executable), " does not exist.");
225
    return cmQtAutoGen::CompilerFeaturesHandle();
226
227
228
229
230
231
232
  }

  // Test the executable
  std::string stdOut;
  {
    std::string stdErr;
    std::vector<std::string> command;
233
    command.emplace_back(executable);
234
235
236
237
238
239
    command.emplace_back("-h");
    int retVal = 0;
    const bool runResult = cmSystemTools::RunSingleCommand(
      command, &stdOut, &stdErr, &retVal, nullptr, cmSystemTools::OUTPUT_NONE,
      cmDuration::zero(), cmProcessOutput::Auto);
    if (!runResult) {
240
241
242
243
      error = cmStrCat("Test run of \"", generator, "\" executable ",
                       cmQtAutoGen::Quoted(executable), " failed.\n",
                       cmQtAutoGen::QuotedCommand(command), '\n', stdOut, '\n',
                       stdErr);
244
      return cmQtAutoGen::CompilerFeaturesHandle();
245
246
247
    }
  }

248
249
250
251
  // Create valid handle
  cmQtAutoGen::CompilerFeaturesHandle res =
    std::make_shared<cmQtAutoGen::CompilerFeatures>();
  res->HelpOutput = std::move(stdOut);
252

253
254
  // Register compiler features
  this->CompilerFeatures_.emplace(executable, res);
255

256
  return res;
257
258
}

259
260
261
262
263
264
265
bool cmQtAutoGenGlobalInitializer::generate()
{
  return (InitializeCustomTargets() && SetupCustomTargets());
}

bool cmQtAutoGenGlobalInitializer::InitializeCustomTargets()
{
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  // Initialize global autogen targets
  {
    std::string const comment = "Global AUTOGEN target";
    for (auto const& pair : GlobalAutoGenTargets_) {
      GetOrCreateGlobalTarget(pair.first, pair.second, comment);
    }
  }
  // Initialize global autorcc targets
  {
    std::string const comment = "Global AUTORCC target";
    for (auto const& pair : GlobalAutoRccTargets_) {
      GetOrCreateGlobalTarget(pair.first, pair.second, comment);
    }
  }
  // Initialize per target autogen targets
  for (auto& initializer : Initializers_) {
    if (!initializer->InitCustomTargets()) {
283
284
285
286
287
288
289
290
      return false;
    }
  }
  return true;
}

bool cmQtAutoGenGlobalInitializer::SetupCustomTargets()
{
291
292
  for (auto& initializer : Initializers_) {
    if (!initializer->SetupCustomTargets()) {
293
294
295
296
297
      return false;
    }
  }
  return true;
}