QtBase  v6.3.1
msvc_vcproj.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the qmake application of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include "msvc_vcproj.h"
30 #include "option.h"
31 #include "xmloutput.h"
32 
33 #include <ioutils.h>
34 
35 #include <qdir.h>
36 #include <qdiriterator.h>
37 #include <qcryptographichash.h>
38 #include <qhash.h>
39 #include <quuid.h>
40 #include <qregularexpression.h>
41 
42 #include <stdlib.h>
43 #include <tuple>
44 #include <utility>
45 
46 //#define DEBUG_SOLUTION_GEN
47 
48 using namespace QMakeInternal;
49 
51 // Filter GUIDs (Do NOT change these!) ------------------------------
52 const char _GUIDSourceFiles[] = "{4FC737F1-C7A5-4376-A066-2A32D752A2FF}";
53 const char _GUIDHeaderFiles[] = "{93995380-89BD-4b04-88EB-625FBE52EBFB}";
54 const char _GUIDGeneratedFiles[] = "{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}";
55 const char _GUIDResourceFiles[] = "{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}";
56 const char _GUIDLexYaccFiles[] = "{E12AE0D2-192F-4d59-BD23-7D3FA58D3183}";
57 const char _GUIDTranslationFiles[] = "{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}";
58 const char _GUIDFormFiles[] = "{99349809-55BA-4b9d-BF79-8FDBB0286EB3}";
59 const char _GUIDExtraCompilerFiles[] = "{E0D8C965-CC5F-43d7-AD63-FAEF0BBC0F85}";
60 const char _GUIDDistributionFiles[] = "{B83CAF91-C7BF-462F-B76C-EA11631F866C}";
61 
62 // Flatfile Tags ----------------------------------------------------
63 const char _slnHeader70[] = "Microsoft Visual Studio Solution File, Format Version 7.00";
64 const char _slnHeader71[] = "Microsoft Visual Studio Solution File, Format Version 8.00";
65 const char _slnHeader80[] = "Microsoft Visual Studio Solution File, Format Version 9.00"
66  "\n# Visual Studio 2005";
67 const char _slnHeader90[] = "Microsoft Visual Studio Solution File, Format Version 10.00"
68  "\n# Visual Studio 2008";
69 const char _slnHeader100[] = "Microsoft Visual Studio Solution File, Format Version 11.00"
70  "\n# Visual Studio 2010";
71 const char _slnHeader110[] = "Microsoft Visual Studio Solution File, Format Version 12.00"
72  "\n# Visual Studio 2012";
73 const char _slnHeader120[] = "Microsoft Visual Studio Solution File, Format Version 12.00"
74  "\n# Visual Studio 2013";
75 const char _slnHeader140[] = "Microsoft Visual Studio Solution File, Format Version 12.00"
76  "\n# Visual Studio 2015";
77 const char _slnHeader141[] = "Microsoft Visual Studio Solution File, Format Version 12.00"
78  "\n# Visual Studio 15";
79 const char _slnHeader142[] = "Microsoft Visual Studio Solution File, Format Version 12.00"
80  "\n# Visual Studio Version 16";
81 const char _slnHeader143[] = "Microsoft Visual Studio Solution File, Format Version 12.00"
82  "\n# Visual Studio Version 17";
83  // The following UUID _may_ change for later servicepacks...
84  // If so we need to search through the registry at
85  // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.0\Projects
86  // to find the subkey that contains a "PossibleProjectExtension"
87  // containing "vcproj"...
88  // Use the hardcoded value for now so projects generated on other
89  // platforms are actually usable.
90 const char _slnMSVCvcprojGUID[] = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}";
91 const char _slnProjectBeg[] = "\nProject(\"";
92 const char _slnProjectMid[] = "\") = ";
93 const char _slnProjectEnd[] = "\nEndProject";
94 const char _slnGlobalBeg[] = "\nGlobal";
95 const char _slnGlobalEnd[] = "\nEndGlobal";
96 const char _slnSolutionConf[] = "\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution"
97  "\n\t\tDebug|Win32 = Debug|Win32"
98  "\n\t\tRelease|Win32 = Release|Win32"
99  "\n\tEndGlobalSection";
100 
101 const char _slnProjDepBeg[] = "\n\tProjectSection(ProjectDependencies) = postProject";
102 const char _slnProjDepEnd[] = "\n\tEndProjectSection";
103 const char _slnProjConfBeg[] = "\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution";
104 const char _slnProjRelConfTag1[]= ".Release|%1.ActiveCfg = Release|";
105 const char _slnProjRelConfTag2[]= ".Release|%1.Build.0 = Release|";
106 const char _slnProjDbgConfTag1[]= ".Debug|%1.ActiveCfg = Debug|";
107 const char _slnProjDbgConfTag2[]= ".Debug|%1.Build.0 = Debug|";
108 const char _slnProjConfEnd[] = "\n\tEndGlobalSection";
109 const char _slnExtSections[] = "\n\tGlobalSection(ExtensibilityGlobals) = postSolution"
110  "\n\tEndGlobalSection"
111  "\n\tGlobalSection(ExtensibilityAddIns) = postSolution"
112  "\n\tEndGlobalSection";
113 // ------------------------------------------------------------------
114 
117  is64Bit(false),
118  customBuildToolFilterFileSuffix(QStringLiteral(".cbt")),
119  projectWriter(nullptr)
120 {
121 }
122 
124 {
125  delete projectWriter;
126 }
127 
128 bool VcprojGenerator::writeMakefile(QTextStream &t)
129 {
130  initProject(); // Fills the whole project with proper data
131 
132  // Generate solution file
133  if(project->first("TEMPLATE") == "vcsubdirs") {
134  if (!project->isActiveConfig("build_pass")) {
135  debug_msg(1, "Generator: MSVC.NET: Writing solution file");
136  writeSubDirs(t);
137  } else {
138  debug_msg(1, "Generator: MSVC.NET: Not writing solution file for build_pass configs");
139  }
140  return true;
141  } else
142  // Generate single configuration project file
143  if (project->first("TEMPLATE") == "vcapp" ||
144  project->first("TEMPLATE") == "vclib") {
145  if(!project->isActiveConfig("build_pass")) {
146  debug_msg(1, "Generator: MSVC.NET: Writing single configuration project file");
147  XmlOutput xmlOut(t);
148  projectWriter->write(xmlOut, vcProject);
149  }
150  return true;
151  }
152  return project->isActiveConfig("build_pass");
153 }
154 
155 bool VcprojGenerator::writeProjectMakefile()
156 {
158 
159  // Check if all requirements are fulfilled
160  if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
161  fprintf(stderr, "Project file not generated because all requirements not met:\n\t%s\n",
162  var("QMAKE_FAILED_REQUIREMENTS").toLatin1().constData());
163  return true;
164  }
165 
166  // Generate project file
167  if(project->first("TEMPLATE") == "vcapp" ||
168  project->first("TEMPLATE") == "vclib") {
169  if (!mergedProjects.count()) {
170  warn_msg(WarnLogic, "Generator: MSVC.NET: no single configuration created, cannot output project!");
171  return false;
172  }
173 
174  debug_msg(1, "Generator: MSVC.NET: Writing project file");
175  VCProject mergedProject;
176  for (int i = 0; i < mergedProjects.count(); ++i) {
177  VCProjectSingleConfig *singleProject = &(mergedProjects.at(i)->vcProject);
178  mergedProject.SingleProjects += *singleProject;
179  for (int j = 0; j < singleProject->ExtraCompilersFiles.count(); ++j) {
180  const QString &compilerName = singleProject->ExtraCompilersFiles.at(j).Name;
181  if (!mergedProject.ExtraCompilers.contains(compilerName))
182  mergedProject.ExtraCompilers += compilerName;
183  }
184  }
185 
186  if(mergedProjects.count() > 1 &&
190  mergedProject.Name = project->first("QMAKE_PROJECT_NAME").toQString();
191  mergedProject.Version = mergedProjects.at(0)->vcProject.Version;
192  mergedProject.SdkVersion = mergedProjects.at(0)->vcProject.SdkVersion;
193  mergedProject.ProjectGUID = project->isEmpty("QMAKE_UUID") ? getProjectUUID().toString().toUpper() : project->first("QMAKE_UUID").toQString();
194  mergedProject.Keyword = project->first("VCPROJ_KEYWORD").toQString();
198  mergedProject.WindowsTargetPlatformVersion =
199  project->first("WINDOWS_TARGET_PLATFORM_VERSION").toQString();
200  mergedProject.WindowsTargetPlatformMinVersion =
201  project->first("WINDOWS_TARGET_PLATFORM_MIN_VERSION").toQString();
202 
203  XmlOutput xmlOut(t);
204  projectWriter->write(xmlOut, mergedProject);
205  return true;
206  } else if(project->first("TEMPLATE") == "vcsubdirs") {
207  return writeMakefile(t);
208  }
209  return false;
210 }
211 
219 };
220 
221 /* Disable optimization in getProjectUUID() due to a compiler
222  * bug in MSVC 2015 that causes ASSERT: "&other != this" in the QString
223  * copy constructor for non-empty file names at:
224  * filename.isEmpty()?project->first("QMAKE_MAKEFILE"):filename */
225 
226 #if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG)
227 # pragma optimize( "g", off )
228 # pragma warning ( disable : 4748 )
229 #endif
230 
232 {
233  bool validUUID = true;
234 
235  // Read GUID from variable-space
236  auto uuid = QUuid::fromString(project->first("GUID").toQStringView());
237 
238  // If none, create one based on the MD5 of absolute project path
239  if(uuid.isNull() || !filename.isEmpty()) {
241  filename.isEmpty() ? project->first("QMAKE_MAKEFILE").toQString() : filename);
243  memcpy((unsigned char*)(&uuid), digest.constData(), sizeof(QUuid));
244  validUUID = !uuid.isNull();
245  uuid.data4[0] = (uuid.data4[0] & 0x3F) | 0x80; // UV_DCE variant
246  uuid.data3 = (uuid.data3 & 0x0FFF) | (QUuid::Name<<12);
247  }
248 
249  // If still not valid, generate new one, and suggest adding to .pro
250  if(uuid.isNull() || !validUUID) {
251  uuid = QUuid::createUuid();
252  fprintf(stderr,
253  "qmake couldn't create a GUID based on filepath, and we couldn't\nfind a valid GUID in the .pro file (Consider adding\n'GUID = %s' to the .pro file)\n",
254  uuid.toString().toUpper().toLatin1().constData());
255  }
256 
257  // Store GUID in variable-space
258  project->values("GUID") = ProStringList(uuid.toString().toUpper());
259  return uuid;
260 }
261 
262 #if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG)
263 # pragma optimize( "g", on )
264 #endif
265 
266 QUuid VcprojGenerator::increaseUUID(const QUuid &id)
267 {
268  QUuid result(id);
269  qint64 dataFirst = (result.data4[0] << 24) +
270  (result.data4[1] << 16) +
271  (result.data4[2] << 8) +
272  result.data4[3];
273  qint64 dataLast = (result.data4[4] << 24) +
274  (result.data4[5] << 16) +
275  (result.data4[6] << 8) +
276  result.data4[7];
277 
278  if(!(dataLast++))
279  dataFirst++;
280 
281  result.data4[0] = uchar((dataFirst >> 24) & 0xff);
282  result.data4[1] = uchar((dataFirst >> 16) & 0xff);
283  result.data4[2] = uchar((dataFirst >> 8) & 0xff);
284  result.data4[3] = uchar(dataFirst & 0xff);
285  result.data4[4] = uchar((dataLast >> 24) & 0xff);
286  result.data4[5] = uchar((dataLast >> 16) & 0xff);
287  result.data4[6] = uchar((dataLast >> 8) & 0xff);
288  result.data4[7] = uchar(dataLast & 0xff);
289  return result;
290 }
291 
292 QString VcprojGenerator::retrievePlatformToolSet() const
293 {
294  // The PlatformToolset string corresponds to the name of a directory in
295  // $(VCTargetsPath)\Platforms\{Win32,x64,...}\PlatformToolsets
296  // e.g. v90, v100, v110, v110_xp, v120_CTP_Nov, v120, or WindowsSDK7.1
297 
298  // This environment variable may be set by a commandline build
299  // environment such as the Windows SDK command prompt
300  QByteArray envVar = qgetenv("PlatformToolset");
301  if (!envVar.isEmpty())
302  return envVar;
303 
304  return u"v"_qs + project->first("MSVC_TOOLSET_VER");
305 }
306 
307 bool VcprojGenerator::isStandardSuffix(const QString &suffix) const
308 {
309  if (!project->values("QMAKE_APP_FLAG").isEmpty()) {
310  if (suffix.compare("exe", Qt::CaseInsensitive) == 0)
311  return true;
312  } else if (project->isActiveConfig("shared")) {
313  if (suffix.compare("dll", Qt::CaseInsensitive) == 0)
314  return true;
315  } else {
316  if (suffix.compare("lib", Qt::CaseInsensitive) == 0)
317  return true;
318  }
319  return false;
320 }
321 
322 ProString VcprojGenerator::firstInputFileName(const ProString &extraCompilerName) const
323 {
324  for (const ProString &var : project->values(ProKey(extraCompilerName + ".input"))) {
325  const ProStringList &files = project->values(var.toKey());
326  if (!files.isEmpty())
327  return files.first();
328  }
329  return ProString();
330 }
331 
332 QString VcprojGenerator::firstExpandedOutputFileName(const ProString &extraCompilerName)
333 {
334  const ProString firstOutput = project->first(ProKey(extraCompilerName + ".output"));
335  return replaceExtraCompilerVariables(firstOutput.toQString(),
336  firstInputFileName(extraCompilerName).toQString(),
337  QString(), NoShell);
338 }
339 
340 ProStringList VcprojGenerator::collectDependencies(QMakeProject *proj, QHash<QString, QString> &projLookup,
341  QHash<QString, QString> &projGuids,
343  QHash<QString, VcsolutionDepend*> &solution_depends,
344  QList<VcsolutionDepend*> &solution_cleanup,
345  QTextStream &t,
346  QHash<QString, ProStringList> &subdirProjectLookup,
347  const ProStringList &allDependencies)
348 {
349  QList<QPair<QString, ProStringList>> collectedSubdirs;
350  ProStringList tmp_proj_subdirs = proj->values("SUBDIRS");
351  ProStringList projectsInProject;
352  const int numSubdirs = tmp_proj_subdirs.size();
353  collectedSubdirs.reserve(numSubdirs);
354  for (int x = 0; x < numSubdirs; ++x) {
355  ProString tmpdir = tmp_proj_subdirs.at(x);
356  const ProKey tmpdirConfig(tmpdir + ".CONFIG");
357  if (!proj->isEmpty(tmpdirConfig)) {
358  const ProStringList config = proj->values(tmpdirConfig);
359  if (config.contains(QStringLiteral("no_default_target")))
360  continue; // Ignore this sub-dir
361  }
362  const ProKey fkey(tmpdir + ".file");
363  const ProKey skey(tmpdir + ".subdir");
364  if (!proj->isEmpty(fkey)) {
365  if (!proj->isEmpty(skey))
366  warn_msg(WarnLogic, "Cannot assign both file and subdir for subdir %s",
367  tmpdir.toLatin1().constData());
368  tmpdir = proj->first(fkey);
369  } else if (!proj->isEmpty(skey)) {
370  tmpdir = proj->first(skey);
371  }
372  projectsInProject.append(tmpdir);
373  collectedSubdirs.append(qMakePair(tmpdir.toQString(), proj->values(ProKey(tmp_proj_subdirs.at(x) + ".depends"))));
374  projLookup.insert(tmp_proj_subdirs.at(x).toQString(), tmpdir.toQString());
375  }
376  for (const auto &subdir : qAsConst(collectedSubdirs)) {
377  QString profile = subdir.first;
379  if (fi.exists()) {
380  if (fi.isDir()) {
381  if (!profile.endsWith(Option::dir_sep))
382  profile += Option::dir_sep;
383  profile += fi.baseName() + Option::pro_ext;
384  QString profileKey = fi.absoluteFilePath();
386  if (!fi.exists())
387  continue;
388  projLookup.insert(profileKey, fi.absoluteFilePath());
389  }
390  QString oldpwd = qmake_getpwd();
391  QString oldoutpwd = Option::output_dir;
392  QMakeProject tmp_proj;
394  if (!dir.isEmpty()) {
395  if (!qmake_setpwd(dir))
396  fprintf(stderr, "Cannot find directory: %s", dir.toLatin1().constData());
397  }
399  if (tmp_proj.read(fn)) {
400  // Check if all requirements are fulfilled
401  if (!tmp_proj.isEmpty("QMAKE_FAILED_REQUIREMENTS")) {
402  fprintf(stderr, "Project file(%s) not added to Solution because all requirements not met:\n\t%s\n",
403  fn.toLatin1().constData(),
404  tmp_proj.values("QMAKE_FAILED_REQUIREMENTS").join(' ').toLatin1().constData());
405  qmake_setpwd(oldpwd);
406  Option::output_dir = oldoutpwd;
407  continue;
408  }
409  if (tmp_proj.first("TEMPLATE") == "vcsubdirs") {
410  ProStringList tmpList = collectDependencies(&tmp_proj, projLookup, projGuids, extraSubdirs, solution_depends, solution_cleanup, t, subdirProjectLookup, subdir.second);
411  subdirProjectLookup.insert(subdir.first, tmpList);
412  } else {
413  ProStringList tmpList;
414  tmpList += subdir.second;
415  tmpList += allDependencies;
416  // Initialize a 'fake' project to get the correct variables
417  // and to be able to extract all the dependencies
420  VcprojGenerator tmp_vcproj;
421  tmp_vcproj.setNoIO(true);
422  tmp_vcproj.setProjectFile(&tmp_proj);
423  Option::qmake_mode = old_mode;
424 
425  // We assume project filename is [QMAKE_PROJECT_NAME].vcproj
426  const ProString projectName = tmp_vcproj.project->first("QMAKE_PROJECT_NAME");
427  const QString vcproj = projectName + project->first("VCPROJ_EXTENSION");
428  QString vcprojDir = Option::output_dir;
429 
430  // If file doesn't exsist, then maybe the users configuration
431  // doesn't allow it to be created. Skip to next...
432  if (!exists(vcprojDir + Option::dir_sep + vcproj)) {
433  warn_msg(WarnLogic, "Ignored (not found) '%s'", QString(vcprojDir + Option::dir_sep + vcproj).toLatin1().constData());
434  goto nextfile; // # Dirty!
435  }
436 
437  VcsolutionDepend *newDep = new VcsolutionDepend;
438  newDep->vcprojFile = vcprojDir + Option::dir_sep + vcproj;
439  newDep->projectName = projectName.toQString();
440  newDep->target = tmp_proj.first("MSVCPROJ_TARGET").toQString().section(Option::dir_sep, -1);
441  newDep->targetType = tmp_vcproj.projectTarget;
442  newDep->uuid = tmp_proj.isEmpty("QMAKE_UUID") ? getProjectUUID(Option::fixPathToLocalOS(vcprojDir + QDir::separator() + vcproj)).toString().toUpper(): tmp_proj.first("QMAKE_UUID").toQString();
443  // We want to store it as the .lib name.
444  if (newDep->target.endsWith(".dll"))
445  newDep->target = newDep->target.left(newDep->target.length()-3) + "lib";
446  projGuids.insert(newDep->projectName, newDep->target);
447 
448  if (tmpList.size()) {
449  const ProStringList depends = tmpList;
450  for (const ProString &dep : depends) {
451  QString depend = dep.toQString();
452  if (!projGuids[depend].isEmpty()) {
453  newDep->dependencies << projGuids[depend];
454  } else if (subdirProjectLookup[projLookup[depend]].size() > 0) {
455  const ProStringList tmpLst = subdirProjectLookup[projLookup[depend]];
456  for (const ProString &tDep : tmpLst) {
457  QString tmpDep = tDep.toQString();
458  newDep->dependencies << projGuids[projLookup[tmpDep]];
459  }
460  } else {
461  extraSubdirs.insert(newDep, tmpList.toQStringList());
462  newDep->dependencies.clear();
463  break;
464  }
465  }
466  }
467 
468  // All ActiveQt Server projects are dependent on idc.exe
469  if (tmp_proj.values("CONFIG").contains("qaxserver"))
470  newDep->dependencies << "idc.exe";
471 
472  // Add all unknown libs to the deps
473  QStringList where = QStringList() << "LIBS" << "LIBS_PRIVATE"
474  << "QMAKE_LIBS" << "QMAKE_LIBS_PRIVATE";
475  for (QStringList::ConstIterator wit = where.cbegin();
476  wit != where.cend(); ++wit) {
477  const ProStringList &l = tmp_proj.values(ProKey(*wit));
478  for (ProStringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
479  const QString opt = fixLibFlag(*it).toQString();
480  if (!opt.startsWith("/") && // Not a switch
481  opt != newDep->target && // Not self
482  opt != "opengl32.lib" && // We don't care about these libs
483  opt != "glu32.lib" && // to make depgen alittle faster
484  opt != "kernel32.lib" &&
485  opt != "user32.lib" &&
486  opt != "gdi32.lib" &&
487  opt != "comdlg32.lib" &&
488  opt != "advapi32.lib" &&
489  opt != "shell32.lib" &&
490  opt != "ole32.lib" &&
491  opt != "oleaut32.lib" &&
492  opt != "uuid.lib" &&
493  opt != "imm32.lib" &&
494  opt != "winmm.lib" &&
495  opt != "wsock32.lib" &&
496  opt != "ws2_32.lib" &&
497  opt != "winspool.lib" &&
498  opt != "delayimp.lib")
499  {
500  newDep->dependencies << opt.section(Option::dir_sep, -1);
501  }
502  }
503  }
504 #ifdef DEBUG_SOLUTION_GEN
505  qDebug("Deps for %20s: [%s]", newDep->target.toLatin1().constData(), newDep->dependencies.join(" :: ").toLatin1().constData());
506 #endif
507  solution_cleanup.append(newDep);
508  solution_depends.insert(newDep->target, newDep);
509  }
510 nextfile:
511  qmake_setpwd(oldpwd);
512  Option::output_dir = oldoutpwd;
513  }
514  }
515  }
516  return projectsInProject;
517 }
518 
520 {
521  // Check if all requirements are fulfilled
522  if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) {
523  fprintf(stderr, "Project file not generated because all requirements not met:\n\t%s\n",
524  var("QMAKE_FAILED_REQUIREMENTS").toLatin1().constData());
525  return;
526  }
527 
529  case NET2022:
530  t << _slnHeader143;
531  break;
532  case NET2019:
533  t << _slnHeader142;
534  break;
535  case NET2017:
536  t << _slnHeader141;
537  break;
538  case NET2015:
539  t << _slnHeader140;
540  break;
541  case NET2013:
542  t << _slnHeader120;
543  break;
544  case NET2012:
545  t << _slnHeader110;
546  break;
547  case NET2010:
548  t << _slnHeader100;
549  break;
550  case NET2008:
551  t << _slnHeader90;
552  break;
553  case NET2005:
554  t << _slnHeader80;
555  break;
556  case NET2003:
557  t << _slnHeader71;
558  break;
559  case NET2002:
560  t << _slnHeader70;
561  break;
562  default:
563  t << _slnHeader70;
564  warn_msg(WarnLogic, "Generator: MSVC.NET: Unknown version (%d) of MSVC detected for .sln",
566  break;
567  }
568 
569  QHash<QString, VcsolutionDepend*> solution_depends;
570  QList<VcsolutionDepend*> solution_cleanup;
571 
572  // Make sure that all temp projects are configured
573  // for release so that the depends are created
574  // without the debug <lib>dxxx.lib name mangling
576  Option::globals->extra_cmds[QMakeEvalAfter].append("\nCONFIG+=release");
577 
578  QHash<QString, QString> profileLookup;
579  QHash<QString, QString> projGuids;
581  QHash<QString, ProStringList> subdirProjectLookup;
582  collectDependencies(project, profileLookup, projGuids, extraSubdirs, solution_depends, solution_cleanup, t, subdirProjectLookup);
583 
584  // write out projects
585  for (QList<VcsolutionDepend*>::Iterator it = solution_cleanup.begin(); it != solution_cleanup.end(); ++it) {
586  // ### quoting rules?
588  << "\"" << (*it)->projectName << "\", \"" << (*it)->vcprojFile
589  << "\", \"" << (*it)->uuid << "\"";
590 
591  debug_msg(1, "Project %s has dependencies: %s", (*it)->target.toLatin1().constData(), (*it)->dependencies.join(" ").toLatin1().constData());
592 
593  bool hasDependency = false;
594  for (QStringList::iterator dit = (*it)->dependencies.begin(); dit != (*it)->dependencies.end(); ++dit) {
595  if (VcsolutionDepend *vc = solution_depends[*dit]) {
596  if (!hasDependency) {
597  hasDependency = true;
598  t << _slnProjDepBeg;
599  }
600  t << "\n\t\t" << vc->uuid << " = " << vc->uuid;
601  }
602  }
603  if (hasDependency)
604  t << _slnProjDepEnd;
605 
606  t << _slnProjectEnd;
607  }
608 
609  t << _slnGlobalBeg;
610 
611  for (auto extraIt = extraSubdirs.cbegin(), end = extraSubdirs.cend(); extraIt != end; ++extraIt) {
612  for (const QString &depend : extraIt.value()) {
613  if (!projGuids[depend].isEmpty()) {
614  extraIt.key()->dependencies << projGuids[depend];
615  } else if (!profileLookup[depend].isEmpty()) {
616  if (!projGuids[profileLookup[depend]].isEmpty())
617  extraIt.key()->dependencies << projGuids[profileLookup[depend]];
618  }
619  }
620  }
621  QString slnConf = _slnSolutionConf;
622  if (!project->isEmpty("VCPROJ_ARCH")) {
623  slnConf.replace(QLatin1String("|Win32"), "|" + project->first("VCPROJ_ARCH"));
624  } else if (is64Bit) {
625  slnConf.replace(QLatin1String("|Win32"), QLatin1String("|x64"));
626  }
627  t << slnConf;
628 
629  // Restore previous after_user_var options
630  Option::globals->extra_cmds[QMakeEvalAfter] = old_after_vars;
631 
632  t << _slnProjConfBeg;
633  for(QList<VcsolutionDepend*>::Iterator it = solution_cleanup.begin(); it != solution_cleanup.end(); ++it) {
634  QString platform = is64Bit ? "x64" : "Win32";
635  QString xplatform = platform;
636  if (!project->isEmpty("VCPROJ_ARCH")) {
637  xplatform = project->first("VCPROJ_ARCH").toQString();
638  }
639  if (!project->isHostBuild())
640  platform = xplatform;
641  t << "\n\t\t" << (*it)->uuid << QString(_slnProjDbgConfTag1).arg(xplatform) << platform;
642  t << "\n\t\t" << (*it)->uuid << QString(_slnProjDbgConfTag2).arg(xplatform) << platform;
643  t << "\n\t\t" << (*it)->uuid << QString(_slnProjRelConfTag1).arg(xplatform) << platform;
644  t << "\n\t\t" << (*it)->uuid << QString(_slnProjRelConfTag2).arg(xplatform) << platform;
645  }
646  t << _slnProjConfEnd;
647  t << _slnExtSections;
648  t << _slnGlobalEnd;
649 
650 
651  while (!solution_cleanup.isEmpty())
652  delete solution_cleanup.takeFirst();
653 }
654 
655 // ------------------------------------------------------------------------------------------------
656 // ------------------------------------------------------------------------------------------------
657 
659 {
660  // Source files
661  for (int i = 0; i < Option::cpp_ext.count(); ++i)
662  if (file.endsWith(Option::cpp_ext.at(i)))
663  return true;
664  for (int i = 0; i < Option::c_ext.count(); ++i)
665  if (file.endsWith(Option::c_ext.at(i)))
666  return true;
667  if (file.endsWith(".rc")
668  || file.endsWith(".idl"))
669  return true;
670  return false;
671 }
672 
673 void VcprojGenerator::createCustomBuildToolFakeFile(const QString &cbtFilePath,
674  const QString &realOutFilePath)
675 {
677  if (file.exists())
678  return;
680  warn_msg(WarnLogic, "Cannot create '%s'.", qPrintable(file.fileName()));
681  return;
682  }
683  file.write("This is a dummy file needed to create ");
684  file.write(qPrintable(realOutFilePath));
685  file.write("\n");
686 }
687 
688 void VcprojGenerator::init()
689 {
690  is64Bit = (project->first("QMAKE_TARGET.arch") == "x86_64");
692 
693  if(project->first("TEMPLATE") == "vcsubdirs") //too much work for subdirs
694  return;
695 
696  debug_msg(1, "Generator: MSVC.NET: Initializing variables");
697 
698  // this should probably not be here, but I'm using it to wrap the .t files
699  if (project->first("TEMPLATE") == "vcapp")
700  project->values("QMAKE_APP_FLAG").append("1");
701  else if (project->first("TEMPLATE") == "vclib")
702  project->values("QMAKE_LIB_FLAG").append("1");
703 
704  processVars();
705 
706  // set /VERSION for EXE/DLL header
707  ProString major_minor = project->first("VERSION_PE_HEADER");
708  if (major_minor.isEmpty()) {
709  ProString version = project->first("VERSION");
710  if (!version.isEmpty()) {
711  int firstDot = version.indexOf(".");
712  int secondDot = version.indexOf(".", firstDot + 1);
713  major_minor = version.left(secondDot);
714  }
715  }
716  if (!major_minor.isEmpty())
717  project->values("QMAKE_LFLAGS").append("/VERSION:" + major_minor);
718 
720 
721  // $$QMAKE.. -> $$MSVCPROJ.. -------------------------------------
722  const ProStringList &incs = project->values("INCLUDEPATH");
723  for (ProStringList::ConstIterator incit = incs.begin(); incit != incs.end(); ++incit) {
724  QString inc = (*incit).toQString();
725  project->values("MSVCPROJ_INCPATH").append("-I" + escapeFilePath(inc));
726  }
727 
728  QString dest = Option::fixPathToTargetOS(project->first("TARGET").toQString()) + project->first("TARGET_EXT");
729  project->values("MSVCPROJ_TARGET") = ProStringList(dest);
730 
731  // DLL COPY ------------------------------------------------------
732  if (project->isActiveConfig("dll") && !project->values("DLLDESTDIR").isEmpty()) {
733  const ProStringList &dlldirs = project->values("DLLDESTDIR");
734  QString copydll("");
736  for (dlldir = dlldirs.begin(); dlldir != dlldirs.end(); ++dlldir) {
737  if (!copydll.isEmpty())
738  copydll += " && ";
739  copydll += "copy \"$(TargetPath)\" " + escapeFilePath(*dlldir);
740  }
741 
742  QString deststr("Copy " + dest + " to ");
743  for (dlldir = dlldirs.begin(); dlldir != dlldirs.end();) {
744  deststr += *dlldir;
745  ++dlldir;
746  if (dlldir != dlldirs.end())
747  deststr += ", ";
748  }
749 
750  project->values("MSVCPROJ_COPY_DLL").append(copydll);
751  project->values("MSVCPROJ_COPY_DLL_DESC").append(deststr);
752  }
753 
754 #if 0
755  // Verbose output if "-d -d"...
756  qDebug("Generator: MSVC.NET: List of current variables:");
758  qDebug("Generator: MSVC.NET: %s => %s", qPrintable(it.key().toQString()), qPrintable(it.value().join(" | ")));
759 #endif
760 
761  // Figure out what we're trying to build
762  if(project->first("TEMPLATE") == "vcapp") {
764  } else if(project->first("TEMPLATE") == "vclib") {
765  if(project->isActiveConfig("staticlib")) {
766  project->values("LIBS") += project->values("RES_FILE");
768  } else
770  }
771 
772  // Setup PCH variables
773  precompH = project->first("PRECOMPILED_HEADER").toQString();
774  precompSource = project->first("PRECOMPILED_SOURCE").toQString();
775  pchIsCFile = project->isActiveConfig("precompile_header_c");
776  usePCH = !precompH.isEmpty() && (pchIsCFile || project->isActiveConfig("precompile_header"));
777  if (usePCH) {
779  // Created files
780  QString origTarget = project->first("QMAKE_ORIG_TARGET").toQString();
781  precompObj = origTarget + Option::obj_ext;
782  precompPch = origTarget + ".pch";
783  // Add PRECOMPILED_HEADER to HEADERS
784  if (!project->values("HEADERS").contains(precompH))
785  project->values("HEADERS") += precompH;
786  // Return to variable pool
787  project->values("PRECOMPILED_OBJECT") = ProStringList(precompObj);
788  project->values("PRECOMPILED_PCH") = ProStringList(precompPch);
789 
790  autogenPrecompSource = precompSource.isEmpty() && project->isActiveConfig("autogen_precompile_source");
791  if (autogenPrecompSource) {
793  + (pchIsCFile
794  ? (Option::c_ext.count() ? Option::c_ext.at(0) : QLatin1String(".c"))
795  : (Option::cpp_ext.count() ? Option::cpp_ext.at(0) : QLatin1String(".cpp")));
796  project->values("GENERATED_SOURCES") += precompSource;
797  } else if (!precompSource.isEmpty()) {
798  project->values("SOURCES") += precompSource;
799  }
800  }
801 
802  // Helper function to create a fake file foo.cbt for the project view.
803  //
804  // This prevents VS from complaining about a circular dependency from "foo -> foo".
805  //
806  // The .cbt file is added as "source" of the Custom Build Tool. This means, in the project
807  // view, this is the file the Custom Build Tool property page is attached to.
808  //
809  // This function returns a pair with
810  // - the fully resolved output file path
811  // - the file path of the .cbt file
812  auto addExtraCompilerSourceWithCustomBuildToolFakeFile
813  = [this](const QString &compilerOutput, const ProString &extraCompiler,
814  const QStringList &inputs) -> std::pair<QString, QString>
815  {
816  QString realOut = replaceExtraCompilerVariables(compilerOutput, inputs, {}, NoShell);
818  createCustomBuildToolFakeFile(out, realOut);
820  extraCompilerSources[out] += extraCompiler.toQString();
821  return { realOut, out };
822  };
823 
824  // Add all input files for a custom compiler into a map for uniqueness.
825  //
826  // Use .cbt files for the following cases:
827  // - CONFIG += combine
828  // - the input has a built-in compiler (e.g. C++ source file)
829  for (const ProString &quc : project->values("QMAKE_EXTRA_COMPILERS")) {
830  const ProStringList &invar = project->values(ProKey(quc + ".input"));
831  const QString compiler_out = project->first(ProKey(quc + ".output")).toQString();
832 
833  QStringList inputFiles;
834  for (auto it = invar.begin(); it != invar.end(); ++it)
835  inputFiles += project->values(it->toKey()).toQStringList();
836 
837  if (project->values(ProKey(quc + ".CONFIG")).contains("combine")) {
838  // Handle "CONFIG += combine" extra compilers.
839  QString realOut;
840  QString out;
841  std::tie(realOut, out)
842  = addExtraCompilerSourceWithCustomBuildToolFakeFile(compiler_out, quc, inputFiles);
843  if (hasBuiltinCompiler(realOut))
844  extraCompilerOutputs[out] = realOut;
845  } else {
846  // Handle regular 1-to-1 extra compilers.
847  for (const QString &file : inputFiles) {
848  if (verifyExtraCompiler(quc, file)) {
849  if (!hasBuiltinCompiler(file)) {
850  extraCompilerSources[file] += quc.toQString();
851  } else {
852  QString out;
853  std::tie(std::ignore, out)
854  = addExtraCompilerSourceWithCustomBuildToolFakeFile(compiler_out,
855  quc,
856  QStringList(file));
858  }
859  }
860  }
861  }
862  }
863 
864 #if 0 // Debugging
865  for (auto it = extraCompilerSources.cbegin(), end = extraCompilerSources.cend(); it != end; ++it)
866  qDebug("Extracompilers for %s are (%s)", it.key().toLatin1().constData(), it.value().join(", ").toLatin1().constData());
867  for (auto it = extraCompilerOutputs.cbegin(), end = extraCompilerOutputs.cend(); it != end; ++it)
868  qDebug("Object mapping for %s is (%s)", qPrintable(it.key()), qPrintable(it.value()));
869  qDebug("");
870 #endif
871 }
872 
874 {
875  if (!other || !other->projectFile()) {
876  warn_msg(WarnLogic, "VcprojGenerator: Cannot merge null project.");
877  return false;
878  }
879  if (other->projectFile()->first("MAKEFILE_GENERATOR") != project->first("MAKEFILE_GENERATOR")) {
880  warn_msg(WarnLogic, "VcprojGenerator: Cannot merge other types of projects! (ignored)");
881  return false;
882  }
883 
884  VcprojGenerator *otherVC = static_cast<VcprojGenerator*>(other);
885  mergedProjects += otherVC;
886  return true;
887 }
888 
890 {
891  // Initialize XML sub elements
892  // - Do this first since project elements may need
893  // - to know of certain configuration options
895  initRootFiles();
896  initSourceFiles();
897  initHeaderFiles();
901  initFormFiles();
905 
906  // Own elements -----------------------------
907  vcProject.Name = project->first("QMAKE_ORIG_TARGET").toQString();
909  case NET2022:
910  vcProject.Version = "17.00";
911  break;
912  case NET2019:
913  vcProject.Version = "16.00";
914  break;
915  case NET2017:
916  vcProject.Version = "15.00";
917  break;
918  case NET2015:
919  vcProject.Version = "14.00";
920  break;
921  case NET2013:
922  vcProject.Version = "12.00";
923  break;
924  case NET2012:
925  vcProject.Version = "11.00";
926  break;
927  case NET2010:
928  vcProject.Version = "10.00";
929  break;
930  case NET2008:
931  vcProject.Version = "9,00";
932  break;
933  case NET2005:
934  //### using ',' because of a bug in 2005 B2
935  //### VS uses '.' or ',' depending on the regional settings! Using ',' always works.
936  vcProject.Version = "8,00";
937  break;
938  case NET2003:
939  vcProject.Version = "7.10";
940  break;
941  case NET2002:
942  vcProject.Version = "7.00";
943  break;
944  default:
945  vcProject.Version = "7.00";
946  warn_msg(WarnLogic, "Generator: MSVC.NET: Unknown version (%d) of MSVC detected for .vcproj", vcProject.Configuration.CompilerVersion);
947  break;
948  }
949 
950  vcProject.Keyword = project->first("VCPROJ_KEYWORD").toQString();
951  if (!project->isEmpty("VCPROJ_ARCH")) {
952  vcProject.PlatformName = project->first("VCPROJ_ARCH").toQString();
953  } else {
954  vcProject.PlatformName = (is64Bit ? "x64" : "Win32");
955  }
956  vcProject.SdkVersion = project->first("WINSDK_VER").toQString();
957  // These are not used by Qt, but may be used by customers
958  vcProject.SccProjectName = project->first("SCCPROJECTNAME").toQString();
959  vcProject.SccLocalPath = project->first("SCCLOCALPATH").toQString();
961 
962  // Set up the full target path for target conflict checking.
963  const QChar slash = QLatin1Char('/');
964  QString destdir = QDir::fromNativeSeparators(var("DESTDIR"));
965  if (!destdir.endsWith(slash))
966  destdir.append(slash);
967  project->values("DEST_TARGET") = ProStringList(destdir
968  + project->first("TARGET")
969  + project->first("TARGET_EXT"));
970 }
971 
973 {
974  // Initialize XML sub elements
975  // - Do this first since main configuration elements may need
976  // - to know of certain compiler/linker options
978  conf.suppressUnknownOptionWarnings = project->isActiveConfig("suppress_vcproj_warnings");
979  conf.CompilerVersion = vsVersionFromString(project->first("MSVC_VER"));
980 
982 
983  // Only on configuration per build
984  bool isDebug = project->isActiveConfig("debug");
985 
986  if(projectTarget == StaticLib)
988  else {
990  initLinkerTool();
991  }
994  initIDLTool();
995 
996  // Own elements -----------------------------
997  ProString temp = project->first("BuildBrowserInformation");
998  switch (projectTarget) {
999  case SharedLib:
1001  break;
1002  case StaticLib:
1004  break;
1005  case Application:
1006  default:
1008  break;
1009  }
1010 
1011  conf.OutputDirectory = project->first("DESTDIR").toQString();
1012  if (conf.OutputDirectory.isEmpty())
1013  conf.OutputDirectory = ".\\";
1014  if (!conf.OutputDirectory.endsWith("\\"))
1015  conf.OutputDirectory += '\\';
1016  if (conf.CompilerVersion >= NET2010) {
1017  conf.PlatformToolSet = retrievePlatformToolSet();
1018 
1019  const QFileInfo targetInfo = fileInfo(project->first("MSVCPROJ_TARGET").toQString());
1020  conf.PrimaryOutput = targetInfo.completeBaseName();
1021 
1022  const QString targetSuffix = targetInfo.suffix();
1023  if (!isStandardSuffix(targetSuffix))
1024  conf.PrimaryOutputExtension = '.' + targetSuffix;
1025  }
1026 
1027  conf.Name = project->values("BUILD_NAME").join(' ');
1028  if (conf.Name.isEmpty())
1029  conf.Name = isDebug ? "Debug" : "Release";
1030  conf.ConfigurationName = conf.Name;
1031  if (!project->isEmpty("VCPROJ_ARCH")) {
1032  conf.Name += "|" + project->first("VCPROJ_ARCH");
1033  } else {
1034  conf.Name += (is64Bit ? "|x64" : "|Win32");
1035  }
1036  conf.ATLMinimizesCRunTimeLibraryUsage = (project->first("ATLMinimizesCRunTimeLibraryUsage").isEmpty() ? _False : _True);
1037  conf.BuildBrowserInformation = triState(temp.isEmpty() ? (short)unset : temp.toShort());
1038  temp = project->first("CharacterSet");
1039  conf.CharacterSet = charSet(temp.isEmpty() ? short(charSetNotSet) : temp.toShort());
1040  conf.DeleteExtensionsOnClean = project->first("DeleteExtensionsOnClean").toQString();
1041  conf.ImportLibrary = conf.linker.ImportLibrary;
1042  conf.IntermediateDirectory = project->first("OBJECTS_DIR").toQString();
1044  temp = project->first("UseOfATL");
1045  if(!temp.isEmpty())
1046  conf.UseOfATL = useOfATL(temp.toShort());
1047  temp = project->first("UseOfMfc");
1048  if(!temp.isEmpty())
1049  conf.UseOfMfc = useOfMfc(temp.toShort());
1050 
1051  // Configuration does not need parameters from
1052  // these sub XML items;
1056  // Only deploy for crosscompiled projects
1057  if (!project->isHostBuild())
1061 }
1062 
1063 // Filter from the given QMAKE_CFLAGS the options that are relevant
1064 // for the vcxproj-global VCCLCompilerTool.
1065 static ProStringList relevantCFlags(const ProStringList &flags)
1066 {
1068  static const QRegularExpression rex("^[/-]std:");
1069  for (const ProString &flag : flags) {
1070  if (rex.match(flag.toQString()).hasMatch()) {
1071  result.append(flag);
1072  }
1073  }
1074  return result;
1075 }
1076 
1078 {
1079  QString placement = project->first("OBJECTS_DIR").toQString();
1080  if(placement.isEmpty())
1081  placement = ".\\";
1082 
1084  if (conf.CompilerVersion >= NET2010) {
1085  // adjust compiler tool defaults for VS 2010 and above
1087  }
1088  conf.compiler.AssemblerListingLocation = placement ;
1089  conf.compiler.ObjectFile = placement ;
1091  // PCH
1092  if (usePCH) {
1094  conf.compiler.PrecompiledHeaderFile = "$(IntDir)\\" + precompPch;
1095  conf.compiler.PrecompiledHeaderThrough = project->first("PRECOMPILED_HEADER").toQString();
1096  conf.compiler.ForcedIncludeFiles = project->values("PRECOMPILED_HEADER").toQStringList();
1097  }
1098 
1099  conf.compiler.parseOptions(relevantCFlags(project->values("QMAKE_CFLAGS")));
1100  conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS"));
1101 
1102  if (project->isActiveConfig("windows"))
1103  conf.compiler.PreprocessorDefinitions += "_WINDOWS";
1104  else if (project->isActiveConfig("console"))
1105  conf.compiler.PreprocessorDefinitions += "_CONSOLE";
1106 
1108  conf.compiler.PreprocessorDefinitions += project->values("PRL_EXPORT_DEFINES").toQStringList();
1109  conf.compiler.parseOptions(project->values("MSVCPROJ_INCPATH"));
1110 }
1111 
1113 {
1115  conf.librarian.OutputFile = "$(OutDir)\\";
1116  conf.librarian.OutputFile += project->first("MSVCPROJ_TARGET").toQString();
1117  conf.librarian.AdditionalOptions += project->values("QMAKE_LIBFLAGS").toQStringList();
1118 }
1119 
1121 {
1123  const ProString tmplt = project->first("TEMPLATE");
1124  if ((tmplt == "vclib"
1125  && !project->isActiveConfig("embed_manifest_dll")
1126  && !project->isActiveConfig("static"))
1127  || (tmplt == "vcapp"
1128  && !project->isActiveConfig("embed_manifest_exe"))) {
1129  tool.EmbedManifest = _False;
1130  }
1131 }
1132 
1134 {
1136  conf.linker.parseOptions(project->values("QMAKE_LFLAGS"));
1137 
1138  if (!project->values("DEF_FILE").isEmpty())
1139  conf.linker.ModuleDefinitionFile = project->first("DEF_FILE").toQString();
1140 
1141  static const char * const lflags[] = { "LIBS", "LIBS_PRIVATE",
1142  "QMAKE_LIBS", "QMAKE_LIBS_PRIVATE", nullptr };
1143  for (int i = 0; lflags[i]; i++) {
1144  const auto libs = fixLibFlags(lflags[i]);
1145  for (const ProString &lib : libs) {
1146  if (lib.startsWith("/LIBPATH:"))
1147  conf.linker.AdditionalLibraryDirectories << lib.mid(9).toQString();
1148  else
1149  conf.linker.AdditionalDependencies << lib.toQString();
1150  }
1151  }
1152 
1153  conf.linker.OutputFile = "$(OutDir)\\";
1154  conf.linker.OutputFile += project->first("MSVCPROJ_TARGET").toQString();
1155 }
1156 
1158 {
1160 
1161  ProStringList rcDefines = project->values("RC_DEFINES");
1162  if (rcDefines.size() > 0)
1163  conf.resource.PreprocessorDefinitions = rcDefines.toQStringList();
1164  else
1166 
1167  for (const ProString &path : project->values("RC_INCLUDEPATH")) {
1168  QString fixedPath = fileFixify(path.toQString());
1169  if (fileInfo(fixedPath).isRelative()) {
1170  if (fixedPath == QLatin1String("."))
1171  fixedPath = QStringLiteral("$(ProjectDir)");
1172  else
1173  fixedPath.prepend(QStringLiteral("$(ProjectDir)\\"));
1174  }
1176  }
1177 
1178  // We need to add _DEBUG for the debug version of the project, since the normal compiler defines
1179  // do not contain it. (The compiler defines this symbol automatically, which is wy we don't need
1180  // to add it for the compiler) However, the resource tool does not do this.
1181  if(project->isActiveConfig("debug"))
1182  conf.resource.PreprocessorDefinitions += "_DEBUG";
1183  if (conf.CompilerVersion < NET2010 && project->isActiveConfig("staticlib"))
1184  conf.resource.ResourceOutputFileName = "$(OutDir)\\$(InputName).res";
1185 }
1186 
1188 {
1189 }
1190 
1192 {
1193 }
1194 
1196 {
1197 }
1198 
1200 {
1202  if (!project->values("QMAKE_POST_LINK").isEmpty()) {
1203  QStringList cmdline = VCToolBase::fixCommandLine(var("QMAKE_POST_LINK"));
1204  conf.postBuild.CommandLine = cmdline;
1205  conf.postBuild.Description = cmdline.join(QLatin1String("\r\n"));
1207  }
1208  if (!project->values("MSVCPROJ_COPY_DLL").isEmpty()) {
1209  conf.postBuild.Description += var("MSVCPROJ_COPY_DLL_DESC");
1210  conf.postBuild.CommandLine += var("MSVCPROJ_COPY_DLL");
1212  }
1213 }
1214 
1216 {
1218  QString targetPath;
1219  targetPath = project->values("deploy.path").join(' ');
1220  if (targetPath.isEmpty())
1221  targetPath = QString("%CSIDL_PROGRAM_FILES%\\") + project->first("TARGET");
1222  if (targetPath.endsWith("/") || targetPath.endsWith("\\"))
1223  targetPath.chop(1);
1224  conf.deployment.RemoteDirectory = targetPath;
1225  const ProStringList dllPaths = project->values("QMAKE_DLL_PATHS");
1226  // Only deploy Qt libs for shared build
1227  if (!dllPaths.isEmpty()) {
1228  // FIXME: This code should actually resolve the libraries from all Qt modules.
1229  ProStringList arg = project->values("LIBS") + project->values("LIBS_PRIVATE")
1230  + project->values("QMAKE_LIBS") + project->values("QMAKE_LIBS_PRIVATE");
1231  bool qpaPluginDeployed = false;
1232  for (ProStringList::ConstIterator it = arg.constBegin(); it != arg.constEnd(); ++it) {
1233  QString dllName = (*it).toQString();
1234  dllName.replace(QLatin1Char('\\'), QLatin1Char('/'));
1235  // LIBPATH isn't relevant for deployment
1236  if (dllName.startsWith(QLatin1String("/LIBPATH:")))
1237  continue;
1238  // We want to deploy .dlls not .libs
1239  if (dllName.endsWith(QLatin1String(".lib")))
1240  dllName.replace(dllName.length() - 3, 3, QLatin1String("dll"));
1241  // Use only the file name and check in Qt's install path and LIBPATHs to check for existence
1242  dllName.remove(0, dllName.lastIndexOf(QLatin1Char('/')) + 1);
1243  QFileInfo info;
1244  for (const ProString &dllPath : dllPaths) {
1245  QString absoluteDllFilePath = dllPath.toQString();
1246  if (!absoluteDllFilePath.endsWith(QLatin1Char('/')))
1247  absoluteDllFilePath += QLatin1Char('/');
1248  absoluteDllFilePath += dllName;
1249  info = QFileInfo(absoluteDllFilePath);
1250  if (info.exists())
1251  break;
1252  }
1253 
1254  if (!info.exists())
1255  continue;
1256 
1257  conf.deployment.AdditionalFiles += info.fileName()
1258  + "|" + QDir::toNativeSeparators(info.absolutePath())
1259  + "|" + targetPath
1260  + "|0;";
1261  if (!qpaPluginDeployed) {
1262  QString debugInfix;
1263  bool foundGuid = dllName.contains(QLatin1String("Guid"));
1264  if (foundGuid)
1265  debugInfix = QLatin1Char('d');
1266 
1267  if (foundGuid || dllName.contains(QLatin1String("Gui"))) {
1268  QFileInfo info2;
1269  for (const ProString &dllPath : dllPaths) {
1270  QString absoluteDllFilePath = dllPath.toQString();
1271  if (!absoluteDllFilePath.endsWith(QLatin1Char('/')))
1272  absoluteDllFilePath += QLatin1Char('/');
1273  absoluteDllFilePath += QLatin1String("../plugins/platforms/qwindows")
1274  + debugInfix + QLatin1String(".dll");
1275  info2 = QFileInfo(absoluteDllFilePath);
1276  if (info2.exists())
1277  break;
1278  }
1279  if (info2.exists()) {
1280  conf.deployment.AdditionalFiles += QLatin1String("qwindows") + debugInfix + QLatin1String(".dll")
1282  + QLatin1Char('|') + targetPath + QLatin1String("\\platforms")
1283  + QLatin1String("|0;");
1284  qpaPluginDeployed = true;
1285  }
1286  }
1287  }
1288  }
1289  }
1290 
1291  for (const ProString &item : project->values("INSTALLS")) {
1292  // get item.path
1293  QString devicePath = project->first(ProKey(item + ".path")).toQString();
1294  if (devicePath.isEmpty())
1295  devicePath = targetPath;
1296  // check if item.path is relative (! either /,\ or %)
1297  if (!(devicePath.at(0) == QLatin1Char('/')
1298  || devicePath.at(0) == QLatin1Char('\\')
1299  || devicePath.at(0) == QLatin1Char('%'))) {
1300  // create output path
1301  devicePath = Option::fixPathToTargetOS(targetPath + QLatin1Char('\\') + devicePath);
1302  }
1303  // foreach d in item.files
1304  for (const ProString &src : project->values(ProKey(item + ".files"))) {
1305  QString itemDevicePath = devicePath;
1306  QString source = Option::normalizePath(src.toQString());
1307  QString nameFilter;
1309  QString searchPath;
1310  if (info.isDir()) {
1311  nameFilter = QLatin1String("*");
1312  itemDevicePath += "\\" + info.fileName();
1313  searchPath = info.absoluteFilePath();
1314  } else {
1315  nameFilter = info.fileName();
1316  searchPath = info.absolutePath();
1317  }
1318 
1319  int pathSize = searchPath.size();
1320  QDirIterator iterator(searchPath, QStringList() << nameFilter
1323  // foreach dirIterator-entry in d
1324  while(iterator.hasNext()) {
1325  iterator.next();
1326 
1327  QString absoluteItemPath = Option::fixPathToTargetOS(QFileInfo(iterator.filePath()).absolutePath());
1328  // Identify if it is just another subdir
1329  int diffSize = absoluteItemPath.size() - pathSize;
1330  // write out rules
1331  conf.deployment.AdditionalFiles += iterator.fileName()
1332  + "|" + absoluteItemPath
1333  + "|" + itemDevicePath + (diffSize ? (absoluteItemPath.right(diffSize)) : QLatin1String(""))
1334  + "|0;";
1335  }
1336  }
1337  }
1338 }
1339 
1341 {
1343  conf.windeployqt.ExcludedFromBuild = true;
1344  if (project->isActiveConfig("windeployqt")) {
1345  conf.windeployqt.Record = QStringLiteral("$(TargetName).windeployqt.$(Platform).$(Configuration)");
1346  const QString commandLine = MakefileGenerator::shellQuote(QDir::toNativeSeparators(project->first("QMAKE_WINDEPLOYQT").toQString()))
1347  + QLatin1Char(' ') + project->values("WINDEPLOYQT_OPTIONS").join(QLatin1Char(' '));
1348 
1349  // Visual Studio copies all files to be deployed into the MSIL directory
1350  // and then invokes MDILXapCompile on it, which checks for managed code and
1351  // translates it into native code. The problem is that all entries of the
1352  // package will be copied into the MSIL directly, losing the subdirectory
1353  // structure (for instance for plugins). However, the MDILXapCompile call
1354  // itself contains the original subdirectories as parameters and hence the
1355  // call fails.
1356  // Hence the only way to get a build done is to recreate the directory
1357  // structure manually by invoking windeployqt a second time, so that
1358  // the MDILXapCompile call succeeds and deployment continues.
1359  conf.windeployqt.CommandLine += commandLine
1360  + QStringLiteral(" -list relative -dir \"$(MSBuildProjectDirectory)\" \"$(OutDir)\\$(TargetFileName)\" > ")
1363  conf.windeployqt.ExcludedFromBuild = false;
1364  }
1365 }
1366 
1368 {
1370  if(!project->values("QMAKE_PRE_LINK").isEmpty()) {
1371  QStringList cmdline = VCToolBase::fixCommandLine(var("QMAKE_PRE_LINK"));
1372  conf.preLink.CommandLine = cmdline;
1373  conf.preLink.Description = cmdline.join(QLatin1String("\r\n"));
1375  }
1376 }
1377 
1379 {
1380  // Note: Root files do _not_ have any filter name, filter nor GUID!
1381  vcProject.RootFiles.addFiles(project->values("RC_FILE"));
1382 
1383  vcProject.RootFiles.Project = this;
1385 }
1386 
1388 {
1389  vcProject.SourceFiles.Name = "Source Files";
1390  vcProject.SourceFiles.Filter = "cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx";
1392 
1394 
1395  vcProject.SourceFiles.Project = this;
1397 }
1398 
1400 {
1401  vcProject.HeaderFiles.Name = "Header Files";
1402  vcProject.HeaderFiles.Filter = "h;hpp;hxx;hm;inl;inc;xsd";
1404 
1406  if (usePCH) // Generated PCH cpp file
1408 
1409  vcProject.HeaderFiles.Project = this;
1411 // vcProject.HeaderFiles.CustomBuild = mocHdr;
1412 // addMocArguments(vcProject.HeaderFiles);
1413 }
1414 
1416 {
1417  vcProject.GeneratedFiles.Name = "Generated Files";
1418  vcProject.GeneratedFiles.Filter = "cpp;c;cxx;moc;h;def;odl;idl;res;";
1420 
1421  // ### These cannot have CustomBuild (mocSrc)!!
1422  vcProject.GeneratedFiles.addFiles(project->values("GENERATED_SOURCES"));
1423  vcProject.GeneratedFiles.addFiles(project->values("GENERATED_FILES"));
1425  if (project->values("RC_FILE").isEmpty())
1429 
1432 // vcProject.GeneratedFiles.CustomBuild = mocSrc;
1433 }
1434 
1436 {
1437  vcProject.LexYaccFiles.Name = "Lex / Yacc Files";
1439  vcProject.LexYaccFiles.Filter = "l;y";
1441 
1442  vcProject.LexYaccFiles.addFiles(project->values("LEXSOURCES"));
1443  vcProject.LexYaccFiles.addFiles(project->values("YACCSOURCES"));
1444 
1447 }
1448 
1450 {
1451  vcProject.TranslationFiles.Name = "Translation Files";
1453  vcProject.TranslationFiles.Filter = "ts;xlf";
1455 
1456  vcProject.TranslationFiles.addFiles(project->values("TRANSLATIONS"));
1457  vcProject.TranslationFiles.addFiles(project->values("EXTRA_TRANSLATIONS"));
1458 
1461 }
1462 
1464 {
1465  vcProject.FormFiles.Name = "Form Files";
1467  vcProject.FormFiles.Filter = "ui";
1470  vcProject.FormFiles.Project = this;
1472 }
1473 
1475 {
1476  vcProject.ResourceFiles.Name = "Resource Files";
1478  vcProject.ResourceFiles.Filter = "qrc;*"; //"rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;ts;xlf;qrc";
1480 
1481  // Bad hack, please look away -------------------------------------
1482  QString rcc_dep_cmd = project->values("rcc.depend_command").join(' ');
1483  if(!rcc_dep_cmd.isEmpty()) {
1484  const QStringList qrc_files = project->values("RESOURCES").toQStringList();
1485  QStringList deps;
1486  for (const QString &qrc_file : qrc_files) {
1488  rcc_dep_cmd,
1489  qrc_file,
1490  QString(),
1491  true, // dep_lines
1492  &deps,
1493  false, // existingDepsOnly
1494  true // checkCommandavailability
1495  );
1496  }
1498  }
1499  // You may look again --------------------------------------------
1500 
1502 
1505 }
1506 
1508 {
1509  vcProject.DistributionFiles.Name = "Distribution Files";
1516 }
1517 
1519  const QStringList &inputs,
1520  const QStringList &outputs)
1521 {
1522  QString name = project->values(ProKey(extraCompiler + ".name")).join(' ');
1523  if (name.isEmpty())
1524  name = extraCompiler.toQString();
1525  else
1526  name = replaceExtraCompilerVariables(name, inputs, outputs, NoShell);
1527  return name;
1528 }
1529 
1531 {
1532  ProStringList otherFilters;
1533  otherFilters << "FORMS"
1534  << "GENERATED_FILES"
1535  << "GENERATED_SOURCES"
1536  << "HEADERS"
1537  << "IDLSOURCES"
1538  << "LEXSOURCES"
1539  << "RC_FILE"
1540  << "RESOURCES"
1541  << "RES_FILE"
1542  << "SOURCES"
1543  << "TRANSLATIONS"
1544  << "YACCSOURCES";
1545  const ProStringList &quc = project->values("QMAKE_EXTRA_COMPILERS");
1546  for (ProStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) {
1547  const ProStringList &inputVars = project->values(ProKey(*it + ".input"));
1548  ProStringList inputFiles;
1549  for (auto var : inputVars)
1550  inputFiles.append(project->values(var.toKey()));
1551  const ProStringList &outputs = project->values(ProKey(*it + ".output"));
1552 
1553  // Create an extra compiler filter and add the files
1554  VCFilter extraCompile;
1555  extraCompile.Name = extraCompilerName(it->toQString(), inputFiles.toQStringList(),
1556  outputs.toQStringList());
1557  extraCompile.ParseFiles = _False;
1558  extraCompile.Filter = "";
1559  extraCompile.Guid = QString(_GUIDExtraCompilerFiles) + "-" + (*it);
1560 
1561  bool addOnInput = hasBuiltinCompiler(firstExpandedOutputFileName(*it));
1562  if (!addOnInput) {
1563  // If the extra compiler has a variable_out set that is already handled
1564  // some other place, ignore it.
1565  const ProString &outputVar = project->first(ProKey(*it + ".variable_out"));
1566  if (!outputVar.isEmpty() && otherFilters.contains(outputVar))
1567  continue;
1568 
1569  QString tmp_out;
1570  if (!outputs.isEmpty())
1571  tmp_out = outputs.first().toQString();
1572  if (project->values(ProKey(*it + ".CONFIG")).indexOf("combine") != -1) {
1573  // Combined output, only one file result. Use .cbt file.
1574  extraCompile.addFile(Option::fixPathToTargetOS(
1576  QString(), QString(), NoShell), false));
1577  } else if (!inputVars.isEmpty()) {
1578  // One output file per input
1579  const ProStringList &tmp_in = project->values(inputVars.first().toKey());
1580  for (int i = 0; i < tmp_in.count(); ++i) {
1581  const QString &filename = tmp_in.at(i).toQString();
1582  if (extraCompilerSources.contains(filename) && !otherFiltersContain(filename))
1583  extraCompile.addFile(Option::fixPathToTargetOS(
1584  replaceExtraCompilerVariables(filename, tmp_out, QString(), NoShell), false));
1585  }
1586  }
1587  } else {
1588  // In this case we the outputs have a built-in compiler, so we cannot add the custom
1589  // build steps there. So, we turn it around and add it to the input files instead,
1590  // provided that the input file variable is not handled already (those in otherFilters
1591  // are handled, so we avoid them).
1592  for (const ProString &inputVar : inputVars) {
1593  if (!otherFilters.contains(inputVar)) {
1594  const ProStringList &tmp_in = project->values(inputVar.toKey());
1595  for (int i = 0; i < tmp_in.count(); ++i) {
1596  const QString &filename = tmp_in.at(i).toQString();
1597  if (extraCompilerSources.contains(filename) && !otherFiltersContain(filename))
1598  extraCompile.addFile(Option::fixPathToTargetOS(
1600  }
1601  }
1602  }
1603  }
1604  extraCompile.Project = this;
1605  extraCompile.Config = &(vcProject.Configuration);
1606 
1607  vcProject.ExtraCompilersFiles.append(extraCompile);
1608  }
1609 }
1610 
1611 bool VcprojGenerator::otherFiltersContain(const QString &fileName) const
1612 {
1613  auto filterFileMatches = [&fileName] (const VCFilterFile &ff)
1614  {
1615  return ff.file == fileName;
1616  };
1617  for (const VCFilter *filter : { &vcProject.RootFiles,
1627  if (std::any_of(filter->Files.cbegin(), filter->Files.cend(), filterFileMatches))
1628  return true;
1629  }
1630  return false;
1631 }
1632 
1633 // ------------------------------------------------------------------------------------------------
1634 // ------------------------------------------------------------------------------------------------
1635 
1637 {
1638  return new VCProjectWriter;
1639 }
1640 
1642  const QString &var, const QStringList &in, const QStringList &out, ReplaceFor forShell)
1643 {
1645 
1646  ProStringList &defines = project->values("VCPROJ_MAKEFILE_DEFINES");
1647  if(defines.isEmpty())
1648  defines.append(varGlue("PRL_EXPORT_DEFINES"," -D"," -D","") +
1649  varGlue("DEFINES"," -D"," -D",""));
1650  ret.replace(QLatin1String("$(DEFINES)"), defines.first().toQString());
1651 
1652  ProStringList &incpath = project->values("VCPROJ_MAKEFILE_INCPATH");
1653  if(incpath.isEmpty() && !this->var("MSVCPROJ_INCPATH").isEmpty())
1654  incpath.append(this->var("MSVCPROJ_INCPATH"));
1655  ret.replace(QLatin1String("$(INCPATH)"), incpath.join(' '));
1656 
1657  return ret;
1658 }
1659 
1660 bool VcprojGenerator::openOutput(QFile &file, const QString &/*build*/) const
1661 {
1663  ProString extension = project->first("TEMPLATE") == "vcsubdirs"
1664  ? project->first("VCSOLUTION_EXTENSION") : project->first("VCPROJ_EXTENSION");
1665  if (!fileName.endsWith(extension)) {
1666  if (fileName.isEmpty()) {
1667  fileName = !project->first("MAKEFILE").isEmpty()
1668  ? project->first("MAKEFILE") : project->first("TARGET");
1669  }
1670  file.setFileName(fileName + extension);
1671  }
1673 }
1674 
small capitals from c petite p scientific f u
Definition: afcover.h:88
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
bool exists(QString file) const
Definition: makefile.h:288
void callExtraCompilerDependCommand(const ProString &extraCompiler, const QString &tmp_dep_cmd, const QString &inpf, const QString &tmp_out, bool dep_lines, QStringList *deps, bool existingDepsOnly, bool checkCommandAvailability=false)
Definition: makefile.cpp:1883
QString shellQuote(const QString &str) const
Definition: makefile.cpp:3481
virtual QString var(const ProKey &var) const
Definition: makefile.cpp:1417
QFileInfo fileInfo(QString file) const
Definition: makefile.cpp:2827
void setNoIO(bool o)
Definition: makefile.h:305
QString varGlue(const ProKey &var, const QString &before, const QString &glue, const QString &after) const
Definition: makefile.cpp:1453
void setProjectFile(QMakeProject *p)
Definition: makefile.cpp:241
ProStringList fixLibFlags(const ProKey &var)
Definition: makefile.cpp:2863
virtual QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &, ReplaceFor forShell)
Definition: makefile.cpp:1596
virtual void init()
Definition: makefile.cpp:372
bool verifyExtraCompiler(const ProString &c, const QString &f)
Definition: makefile.cpp:1721
QString fileFixify(const QString &file, FileFixifyTypes fix=FileFixifyDefault, bool canon=true) const
Definition: makefile.cpp:2982
virtual bool openOutput(QFile &, const QString &build) const
Definition: makefile.cpp:3214
QMakeProject * project
Definition: makefile.h:139
bool isEmpty() const
Definition: proitems.h:121
QByteArray toLatin1() const
Definition: proitems.h:169
ALWAYS_INLINE ProKey & toKey()
Definition: proitems.h:163
QString toQString() const
Definition: proitems.cpp:153
ALWAYS_INLINE QStringView toQStringView() const
Definition: proitems.h:161
short toShort(bool *ok=nullptr, int base=10) const
Definition: proitems.h:156
QString join(const ProString &sep) const
Definition: proitems.cpp:359
bool contains(const ProString &str, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: proitems.cpp:434
QStringList toQStringList() const
Definition: proitems.cpp:425
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
const char * constData() const noexcept
Definition: qbytearray.h:144
bool isEmpty() const noexcept
Definition: qbytearray.h:129
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:84
static QByteArray hash(QByteArrayView data, Algorithm method)
static QString fromNativeSeparators(const QString &pathName)
Definition: qdir.cpp:949
static QChar separator()
Definition: qdir.h:234
static QString cleanPath(const QString &path)
Definition: qdir.cpp:2350
static QString toNativeSeparators(const QString &pathName)
Definition: qdir.cpp:916
@ Files
Definition: qdir.h:58
@ NoSymLinks
Definition: qdir.h:60
@ NoDotAndDotDot
Definition: qdir.h:79
The QDirIterator class provides an iterator for directory entrylists.
Definition: qdiriterator.h:49
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:94
bool open(OpenMode flags) override
Definition: qfile.cpp:897
void setFileName(const QString &name)
Definition: qfile.cpp:327
QString fileName() const override
Definition: qfile.cpp:302
bool exists() const
Definition: qfile.cpp:376
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:57
QString baseName() const
Definition: qfileinfo.cpp:816
QString suffix() const
Definition: qfileinfo.cpp:877
QString fileName() const
Definition: qfileinfo.cpp:772
QString absoluteFilePath() const
Definition: qfileinfo.cpp:556
QString completeBaseName() const
Definition: qfileinfo.cpp:835
bool isDir() const
Definition: qfileinfo.cpp:1048
QString absolutePath() const
Definition: qfileinfo.cpp:599
bool exists() const
Definition: qfileinfo.cpp:697
const_iterator cbegin() const noexcept
Definition: qhash.h:1157
QList< Key > keys() const
Definition: qhash.h:1029
bool contains(const Key &key) const noexcept
Definition: qhash.h:944
const_iterator cend() const noexcept
Definition: qhash.h:1161
Key key(const T &value) const noexcept
Definition: qhash.h:971
bool isEmpty() const noexcept
Definition: qhash.h:881
iterator insert(const Key &key, const T &value)
Definition: qhash.h:1228
qint64 write(const char *data, qint64 len)
Definition: qiodevice.cpp:1681
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
Definition: qlist.h:108
qsizetype size() const noexcept
Definition: qlist.h:414
bool isEmpty() const noexcept
Definition: qlist.h:418
iterator end()
Definition: qlist.h:624
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
value_type takeFirst()
Definition: qlist.h:564
qsizetype count() const noexcept
Definition: qlist.h:415
iterator begin()
Definition: qlist.h:623
void reserve(qsizetype size)
Definition: qlist.h:757
T & first()
Definition: qlist.h:643
void append(parameter_type t)
Definition: qlist.h:469
const_iterator ConstIterator
Definition: qlist.h:280
QString extra_cmds[4]
Definition: qmakeglobals.h:116
QString shadowedPath(const QString &fileName) const
bool isEmpty(const ProKey &v) const
Definition: project.cpp:147
bool isActiveConfig(const QString &config, bool regex=false)
Definition: project.h:67
ProString first(const ProKey &variableName) const
ProStringList & values(const ProKey &v)
Definition: project.h:63
bool read(const QString &project, LoadFlags what=LoadAll)
Definition: project.cpp:64
const ProValueMap & variables() const
Definition: project.h:65
bool isHostBuild() const
const_iterator ConstIterator
Definition: qmap.h:670
iterator begin()
Definition: qmap.h:633
iterator end()
Definition: qmap.h:637
The QRegularExpression class provides pattern matching using regular expressions.
The QString class provides a Unicode character string.
Definition: qstring.h:388
QString right(qsizetype n) const
Definition: qstring.cpp:4970
QByteArray toLatin1() const &
Definition: qstring.h:745
QString & prepend(QChar c)
Definition: qstring.h:656
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition: qstring.h:514
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:5092
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition: qstring.cpp:3450
void chop(qsizetype n)
Definition: qstring.cpp:5955
qsizetype size() const
Definition: qstring.h:413
QString section(QChar sep, qsizetype start, qsizetype end=-1, SectionFlags flags=SectionDefault) const
Definition: qstring.h:1272
QString first(qsizetype n) const
Definition: qstring.h:576
const QChar at(qsizetype i) const
Definition: qstring.h:1212
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:5143
bool isEmpty() const
Definition: qstring.h:1216
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition: qstring.cpp:6263
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.h:1353
QString & append(QChar c)
Definition: qstring.cpp:3152
QString left(qsizetype n) const
Definition: qstring.cpp:4951
QString & remove(qsizetype i, qsizetype len)
Definition: qstring.cpp:3252
QByteArray toUtf8() const &
Definition: qstring.h:749
QString toUpper() const &
Definition: qstring.h:615
qsizetype length() const
Definition: qstring.h:415
The QStringList class provides a list of strings.
The QTextStream class provides a convenient interface for reading and writing text.
Definition: qtextstream.h:62
The QUuid class stores a Universally Unique Identifier (UUID).
Definition: quuid.h:67
@ Name
Definition: quuid.h:83
static QUuid createUuid()
Definition: quuid.cpp:936
QString toString(StringFormat mode=WithBraces) const
Definition: quuid.cpp:583
static QUuid fromString(QAnyStringView string) noexcept
Definition: quuid.cpp:437
pchOption UsePrecompiledHeader
optimizeOption Optimization
QStringList PreprocessorDefinitions
triState WholeProgramOptimization
exceptionHandling ExceptionHandling
QString AssemblerListingLocation
QString PrecompiledHeaderThrough
QString PrecompiledHeaderFile
QStringList ForcedIncludeFiles
VCWinDeployQtTool windeployqt
VCResourceCompilerTool resource
ConfigurationTypes ConfigurationType
VCLibrarianTool librarian
triState WholeProgramOptimization
VCLinkerTool linker
VCManifestTool manifestTool
triState BuildBrowserInformation
triState ATLMinimizesCRunTimeLibraryUsage
VCPostBuildEventTool postBuild
QString IntermediateDirectory
QString DeleteExtensionsOnClean
bool suppressUnknownOptionWarnings
VCDeploymentTool deployment
QString PrimaryOutputExtension
VCCLCompilerTool compiler
VCPreLinkEventTool preLink
QStringList CommandLine
QString Description
triState ExcludedFromBuild
triState ParseFiles
QString Filter
VcprojGenerator * Project
void addFiles(const QStringList &fileList)
VCConfiguration * Config
QString Name
QString Guid
void addFile(const QString &filename)
QStringList AdditionalOptions
QStringList AdditionalDependencies
QString ImportLibrary
QString ModuleDefinitionFile
QStringList AdditionalLibraryDirectories
triState GenerateDebugInformation
triState EmbedManifest
QString WindowsTargetPlatformMinVersion
QList< VCProjectSingleConfig > SingleProjects
QString ProjectGUID
QString SccLocalPath
QString PlatformName
QStringList ExtraCompilers
QString WindowsTargetPlatformVersion
QString SdkVersion
QString SccProjectName
VCFilterList ExtraCompilersFiles
VCConfiguration Configuration
virtual void write(XmlOutput &, VCProjectSingleConfig &)
QStringList AdditionalIncludeDirectories
QStringList PreprocessorDefinitions
static QStringList fixCommandLine(const QString &input)
void parseOptions(const ProStringList &options)
VCConfiguration * config
QString extraCompilerName(const ProString &extraCompiler, const QStringList &inputs, const QStringList &outputs)
bool autogenPrecompSource
Definition: msvc_vcproj.h:62
void initPreLinkEventTools()
QHash< QString, QStringList > extraCompilerSources
Definition: msvc_vcproj.h:65
void initCustomBuildTool()
void initConfiguration()
VCProjectSingleConfig vcProject
Definition: msvc_vcproj.h:119
void initDistributionFiles()
bool openOutput(QFile &file, const QString &build) const override
QUuid getProjectUUID(const QString &filename=QString())
QString precompPch
Definition: msvc_vcproj.h:61
QString precompHFilename
Definition: msvc_vcproj.h:60
void initExtraCompilerOutputs()
void initPreBuildEventTools()
bool mergeBuildProject(MakefileGenerator *other) override
virtual VCProjectWriter * createProjectWriter()
void initWinDeployQtTool()
QString replaceExtraCompilerVariables(const QString &, const QStringList &, const QStringList &, ReplaceFor) override
virtual void initProject()
Target projectTarget
Definition: msvc_vcproj.h:116
void initGeneratedFiles()
QString precompObj
Definition: msvc_vcproj.h:61
void initDeploymentTool()
void initResourceFiles()
void initLibrarianTool()
void writeSubDirs(QTextStream &t)
QList< VcprojGenerator * > mergedProjects
Definition: msvc_vcproj.h:122
QString precompSource
Definition: msvc_vcproj.h:60
void initTranslationFiles()
QHash< QString, QString > extraCompilerOutputs
Definition: msvc_vcproj.h:66
static bool hasBuiltinCompiler(const QString &file)
const QString customBuildToolFilterFileSuffix
Definition: msvc_vcproj.h:67
void initPostBuildEventTools()
VCProjectWriter * projectWriter
Definition: msvc_vcproj.h:70
QString precompH
Definition: msvc_vcproj.h:60
ProString fixLibFlag(const ProString &lib) override
Definition: winmakefile.cpp:45
virtual QString escapeFilePath(const QString &path) const=0
#define this
Definition: dialogs.cpp:56
set contains("Julia")
QStyleOptionButton opt
int const char * version
Definition: zlib.h:814
backing_store_ptr info
[4]
Definition: jmemsys.h:161
QT_BEGIN_NAMESPACE DotNET vsVersionFromString(const ProString &versionString)
@ typeDynamicLibrary
@ typeStaticLibrary
@ typeApplication
triState
@ _False
@ _True
@ unset
@ pchUseUsingSpecific
useOfMfc
@ NET2015
@ NET2003
@ NET2005
@ NET2002
@ NET2008
@ NET2013
@ NET2022
@ NET2012
@ NET2017
@ NET2010
@ NET2019
@ optimizeDisabled
@ charSetNotSet
@ ehNone
useOfATL
const char _GUIDGeneratedFiles[]
Definition: msvc_vcproj.cpp:54
const char _slnHeader80[]
Definition: msvc_vcproj.cpp:65
const char _GUIDExtraCompilerFiles[]
Definition: msvc_vcproj.cpp:59
const char _slnHeader143[]
Definition: msvc_vcproj.cpp:81
const char _slnHeader140[]
Definition: msvc_vcproj.cpp:75
const char _slnProjectBeg[]
Definition: msvc_vcproj.cpp:91
const char _GUIDHeaderFiles[]
Definition: msvc_vcproj.cpp:53
const char _slnHeader120[]
Definition: msvc_vcproj.cpp:73
const char _slnHeader142[]
Definition: msvc_vcproj.cpp:79
const char _slnGlobalEnd[]
Definition: msvc_vcproj.cpp:95
const char _slnGlobalBeg[]
Definition: msvc_vcproj.cpp:94
const char _GUIDLexYaccFiles[]
Definition: msvc_vcproj.cpp:56
const char _slnHeader100[]
Definition: msvc_vcproj.cpp:69
const char _slnProjConfBeg[]
const char _slnHeader70[]
Definition: msvc_vcproj.cpp:63
const char _slnMSVCvcprojGUID[]
Definition: msvc_vcproj.cpp:90
const char _slnSolutionConf[]
Definition: msvc_vcproj.cpp:96
const char _slnHeader110[]
Definition: msvc_vcproj.cpp:71
const char _slnProjDepBeg[]
const char _slnHeader71[]
Definition: msvc_vcproj.cpp:64
const char _GUIDDistributionFiles[]
Definition: msvc_vcproj.cpp:60
const char _slnProjRelConfTag2[]
const char _slnHeader90[]
Definition: msvc_vcproj.cpp:67
const char _slnProjRelConfTag1[]
const char _GUIDTranslationFiles[]
Definition: msvc_vcproj.cpp:57
const char _slnProjDepEnd[]
const char _slnProjDbgConfTag1[]
const char _slnHeader141[]
Definition: msvc_vcproj.cpp:77
const char _slnProjectMid[]
Definition: msvc_vcproj.cpp:92
const char _slnProjConfEnd[]
const char _slnExtSections[]
const char _GUIDFormFiles[]
Definition: msvc_vcproj.cpp:58
const char _slnProjDbgConfTag2[]
const char _GUIDResourceFiles[]
Definition: msvc_vcproj.cpp:55
const char _slnProjectEnd[]
Definition: msvc_vcproj.cpp:93
QT_BEGIN_NAMESPACE const char _GUIDSourceFiles[]
Definition: msvc_vcproj.cpp:52
Target
Definition: msvc_vcproj.h:37
@ SharedLib
Definition: msvc_vcproj.h:39
@ StaticLib
Definition: msvc_vcproj.h:40
@ Application
Definition: msvc_vcproj.h:38
typename C::iterator iterator
@ CaseInsensitive
Definition: qnamespace.h:1283
constexpr struct q20::ranges::@309 any_of
void warn_msg(QMakeWarn type, const char *fmt,...)
Definition: option.cpp:565
#define QString()
Definition: parse-defines.h:51
QList< QString > QStringList
Definition: qcontainerfwd.h:64
QT_BEGIN_INCLUDE_NAMESPACE typedef unsigned char uchar
Definition: qglobal.h:332
long long qint64
Definition: qglobal.h:298
#define qDebug
[1]
Definition: qlogging.h:177
bool qmake_setpwd(const QString &p)
Definition: main.cpp:440
QString qmake_getpwd()
Definition: main.cpp:434
#define debug_msg
Definition: option.h:46
@ WarnLogic
Definition: option.h:51
@ QMakeEvalAfter
Definition: qmakeglobals.h:53
GLint GLint GLint GLint GLint x
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLenum GLenum GLsizei count
GLenum src
GLbitfield flags
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLuint name
GLsizei GLsizei GLchar * source
GLdouble GLdouble t
[9]
Definition: qopenglext.h:243
GLuint in
Definition: qopenglext.h:8870
GLsizei const GLchar *const * path
Definition: qopenglext.h:4283
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition: qpair.h:55
SSL_CTX int(*) void arg)
#define QStringLiteral(str)
QFile file
[0]
QFileInfo fi("c:/temp/foo")
[newstuff]
QTextStream out(stdout)
[7]
QObject::connect nullptr
QSharedPointer< T > other(t)
[5]
QString dir
[11]
QStringList files
[8]
QGraphicsItem * item
QStringList::Iterator it
static QMakeGlobals * globals
Definition: option.h:73
static QStringList cpp_ext
Definition: option.h:85
static QString fixPathToLocalOS(const QString &in, bool fix_env=true, bool canonical=true)
Definition: option.h:124
static QString obj_ext
Definition: option.h:90
static QStringList c_ext
Definition: option.h:86
static QMAKE_MODE qmake_mode
Definition: option.h:164
static QString pro_ext
Definition: option.h:97
static QString dir_sep
Definition: option.h:96
static QString fixPathToTargetOS(const QString &in, bool fix_env=true, bool canonical=true)
Definition: option.h:133
QMAKE_MODE
Definition: option.h:161
@ QMAKE_GENERATE_NOTHING
Definition: option.h:161
static QString output_dir
Definition: option.h:168
static QFile output
Definition: option.h:167
static QString normalizePath(const QString &in, bool fix_env=true, bool canonical=true)
Definition: option.h:142
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:53
QStringList dependencies
QString toQString(const T &t)
int fn(int &i)