|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the qmake application of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "msvc_vcxproj.h" |
|
43 #include "msbuild_objectmodel.h" |
|
44 #include <qdir.h> |
|
45 #include <qdiriterator.h> |
|
46 #include <quuid.h> |
|
47 |
|
48 |
|
49 QT_BEGIN_NAMESPACE |
|
50 // Filter GUIDs (Do NOT change these!) ------------------------------ |
|
51 const char _GUIDSourceFiles[] = "{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"; |
|
52 const char _GUIDHeaderFiles[] = "{93995380-89BD-4b04-88EB-625FBE52EBFB}"; |
|
53 const char _GUIDGeneratedFiles[] = "{71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11}"; |
|
54 const char _GUIDResourceFiles[] = "{D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}"; |
|
55 const char _GUIDLexYaccFiles[] = "{E12AE0D2-192F-4d59-BD23-7D3FA58D3183}"; |
|
56 const char _GUIDTranslationFiles[] = "{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}"; |
|
57 const char _GUIDFormFiles[] = "{99349809-55BA-4b9d-BF79-8FDBB0286EB3}"; |
|
58 const char _GUIDExtraCompilerFiles[] = "{E0D8C965-CC5F-43d7-AD63-FAEF0BBC0F85}"; |
|
59 QT_END_NAMESPACE |
|
60 |
|
61 QT_BEGIN_NAMESPACE |
|
62 |
|
63 |
|
64 VcxprojGenerator::VcxprojGenerator() : VcprojGenerator() |
|
65 { |
|
66 } |
|
67 bool VcxprojGenerator::writeMakefile(QTextStream &t) |
|
68 { |
|
69 initProject(); // Fills the whole project with proper data |
|
70 |
|
71 // Generate solution file |
|
72 if(project->first("TEMPLATE") == "vcsubdirs") { |
|
73 if (!project->isActiveConfig("build_pass")) { |
|
74 debug_msg(1, "Generator: MSVC.NET: Writing solution file"); |
|
75 writeSubDirs(t); |
|
76 } else { |
|
77 debug_msg(1, "Generator: MSVC.NET: Not writing solution file for build_pass configs"); |
|
78 } |
|
79 return true; |
|
80 } else |
|
81 // Generate single configuration project file |
|
82 if (project->first("TEMPLATE") == "vcapp" || |
|
83 project->first("TEMPLATE") == "vclib") { |
|
84 if(!project->isActiveConfig("build_pass")) { |
|
85 debug_msg(1, "Generator: MSVC.NET: Writing single configuration project file"); |
|
86 XmlOutput xmlOut(t); |
|
87 xmlOut << vcxProject; |
|
88 } |
|
89 return true; |
|
90 } |
|
91 return project->isActiveConfig("build_pass"); |
|
92 } |
|
93 |
|
94 |
|
95 void VcxprojGenerator::initProject() |
|
96 { |
|
97 // Initialize XML sub elements |
|
98 // - Do this first since project elements may need |
|
99 // - to know of certain configuration options |
|
100 initConfiguration(); |
|
101 initRootFiles(); |
|
102 initSourceFiles(); |
|
103 initHeaderFiles(); |
|
104 initGeneratedFiles(); |
|
105 initLexYaccFiles(); |
|
106 initTranslationFiles(); |
|
107 initFormFiles(); |
|
108 initResourceFiles(); |
|
109 initExtraCompilerOutputs(); |
|
110 |
|
111 // Own elements ----------------------------- |
|
112 vcxProject.Name = unescapeFilePath(project->first("QMAKE_ORIG_TARGET")); |
|
113 |
|
114 vcxProject.Keyword = project->first("VCPROJ_KEYWORD"); |
|
115 if (project->isEmpty("CE_SDK") || project->isEmpty("CE_ARCH")) { |
|
116 vcxProject.PlatformName = vcxProject.Configuration.idl.TargetEnvironment; |
|
117 if ( vcxProject.Configuration.idl.TargetEnvironment.isEmpty() ) |
|
118 vcxProject.PlatformName = "Win32"; |
|
119 } else { |
|
120 vcxProject.PlatformName = project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")"; |
|
121 } |
|
122 // These are not used by Qt, but may be used by customers |
|
123 vcxProject.SccProjectName = project->first("SCCPROJECTNAME"); |
|
124 vcxProject.SccLocalPath = project->first("SCCLOCALPATH"); |
|
125 vcxProject.flat_files = project->isActiveConfig("flat"); |
|
126 } |
|
127 |
|
128 |
|
129 void VcxprojGenerator::initConfiguration() |
|
130 { |
|
131 // Initialize XML sub elements |
|
132 // - Do this first since main configuration elements may need |
|
133 // - to know of certain compiler/linker options |
|
134 VCXConfiguration &conf = vcxProject.Configuration; |
|
135 |
|
136 initCompilerTool(); |
|
137 |
|
138 // Only on configuration per build |
|
139 bool isDebug = project->isActiveConfig("debug"); |
|
140 |
|
141 if(projectTarget == StaticLib) |
|
142 initLibrarianTool(); |
|
143 else { |
|
144 conf.linker.GenerateDebugInformation = isDebug ? _True : _False; |
|
145 initLinkerTool(); |
|
146 } |
|
147 initResourceTool(); |
|
148 initIDLTool(); |
|
149 |
|
150 // Own elements ----------------------------- |
|
151 QString temp = project->first("BuildBrowserInformation"); |
|
152 switch (projectTarget) { |
|
153 case SharedLib: |
|
154 conf.ConfigurationType = "DynamicLibrary"; |
|
155 break; |
|
156 case StaticLib: |
|
157 conf.ConfigurationType = "StaticLibrary"; |
|
158 break; |
|
159 case Application: |
|
160 default: |
|
161 conf.ConfigurationType = "Application"; |
|
162 break; |
|
163 } |
|
164 |
|
165 conf.OutputDirectory = project->first("DESTDIR"); |
|
166 |
|
167 if(conf.OutputDirectory.isEmpty()) |
|
168 conf.OutputDirectory = ".\\"; |
|
169 |
|
170 if(!conf.OutputDirectory.endsWith("\\")) |
|
171 conf.OutputDirectory += '\\'; |
|
172 |
|
173 // The target name could have been changed. |
|
174 conf.TargetName = project->first("TARGET"); |
|
175 if ( !conf.TargetName.isEmpty() && !project->first("TARGET_VERSION_EXT").isEmpty() && project->isActiveConfig("shared")) |
|
176 conf.TargetName.append(project->first("TARGET_VERSION_EXT")); |
|
177 |
|
178 conf.Name = project->values("BUILD_NAME").join(" "); |
|
179 if (conf.Name.isEmpty()) |
|
180 conf.Name = isDebug ? "Debug" : "Release"; |
|
181 conf.ConfigurationName = conf.Name; |
|
182 if (project->isEmpty("CE_SDK") || project->isEmpty("CE_ARCH")) { |
|
183 conf.Name += (conf.idl.TargetEnvironment == "Win64" ? "|Win64" : "|Win32"); |
|
184 } else { |
|
185 conf.Name += "|" + project->values("CE_SDK").join(" ") + " (" + project->first("CE_ARCH") + ")"; |
|
186 } |
|
187 conf.ATLMinimizesCRunTimeLibraryUsage = (project->first("ATLMinimizesCRunTimeLibraryUsage").isEmpty() ? _False : _True); |
|
188 conf.BuildBrowserInformation = triState(temp.isEmpty() ? (short)unset : temp.toShort()); |
|
189 temp = project->first("CharacterSet"); |
|
190 if (!temp.isEmpty()) |
|
191 { |
|
192 switch (charSet(temp.toShort())) { |
|
193 |
|
194 case charSetMBCS: |
|
195 conf.CharacterSet = "MultiByte"; |
|
196 break; |
|
197 case charSetUnicode: |
|
198 conf.CharacterSet = "Unicode"; |
|
199 break; |
|
200 case charSetNotSet: |
|
201 default: |
|
202 conf.CharacterSet = "NotSet"; |
|
203 break; |
|
204 } |
|
205 conf.CharacterSet = charSet(temp.isEmpty() ? (short)charSetNotSet : temp.toShort()); |
|
206 } |
|
207 conf.DeleteExtensionsOnClean = project->first("DeleteExtensionsOnClean"); |
|
208 conf.ImportLibrary = conf.linker.ImportLibrary; |
|
209 conf.IntermediateDirectory = project->first("OBJECTS_DIR"); |
|
210 //conf.OutputDirectory = "."; |
|
211 conf.PrimaryOutput = project->first("PrimaryOutput"); |
|
212 conf.WholeProgramOptimization = conf.compiler.WholeProgramOptimization; |
|
213 temp = project->first("UseOfATL"); |
|
214 if(!temp.isEmpty()) |
|
215 { |
|
216 switch (useOfATL(temp.toShort())) { |
|
217 |
|
218 case useATLStatic: |
|
219 conf.UseOfATL = "Static"; |
|
220 break; |
|
221 case useATLDynamic: |
|
222 conf.UseOfATL = "Dynamic"; |
|
223 break; |
|
224 case useATLNotSet: |
|
225 default: |
|
226 conf.UseOfATL = "false"; |
|
227 break; |
|
228 } |
|
229 } |
|
230 temp = project->first("UseOfMfc"); |
|
231 if(!temp.isEmpty()) |
|
232 { |
|
233 switch (useOfMfc(temp.toShort())) { |
|
234 |
|
235 case useMfcStatic: |
|
236 conf.UseOfMfc = "Static"; |
|
237 break; |
|
238 case useMfcDynamic: |
|
239 conf.UseOfMfc = "Dynamic"; |
|
240 break; |
|
241 case useMfcStdWin: |
|
242 default: |
|
243 conf.UseOfMfc = "false"; |
|
244 break; |
|
245 } |
|
246 } |
|
247 |
|
248 // Configuration does not need parameters from |
|
249 // these sub XML items; |
|
250 initCustomBuildTool(); |
|
251 initPreBuildEventTools(); |
|
252 initPostBuildEventTools(); |
|
253 // Only deploy for CE projects |
|
254 if (!project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH")) |
|
255 initDeploymentTool(); |
|
256 initPreLinkEventTools(); |
|
257 |
|
258 // Set definite values in both configurations |
|
259 if (isDebug) { |
|
260 conf.compiler.PreprocessorDefinitions.removeAll("NDEBUG"); |
|
261 } else { |
|
262 conf.compiler.PreprocessorDefinitions += "NDEBUG"; |
|
263 } |
|
264 } |
|
265 |
|
266 |
|
267 void VcxprojGenerator::initCompilerTool() |
|
268 { |
|
269 QString placement = project->first("OBJECTS_DIR"); |
|
270 if(placement.isEmpty()) |
|
271 placement = ".\\"; |
|
272 |
|
273 VCXConfiguration &conf = vcxProject.Configuration; |
|
274 conf.compiler.AssemblerListingLocation = placement ; |
|
275 conf.compiler.ProgramDataBaseFileName = ".\\" ; |
|
276 conf.compiler.ObjectFileName = placement ; |
|
277 // PCH |
|
278 if (usePCH) { |
|
279 conf.compiler.PrecompiledHeader = "Use"; |
|
280 conf.compiler.PrecompiledHeaderOutputFile = "$(IntDir)\\" + precompPch; |
|
281 conf.compiler.PrecompiledHeaderFile = project->first("PRECOMPILED_HEADER"); |
|
282 conf.compiler.ForcedIncludeFiles = project->values("PRECOMPILED_HEADER"); |
|
283 conf.compiler.PreprocessToFile = _False; |
|
284 conf.compiler.PreprocessSuppressLineNumbers = _False; |
|
285 // Minimal build option triggers an Internal Compiler Error |
|
286 // when used in conjunction with /FI and /Yu, so remove it |
|
287 project->values("QMAKE_CFLAGS_DEBUG").removeAll("-Gm"); |
|
288 project->values("QMAKE_CFLAGS_DEBUG").removeAll("/Gm"); |
|
289 project->values("QMAKE_CXXFLAGS_DEBUG").removeAll("-Gm"); |
|
290 project->values("QMAKE_CXXFLAGS_DEBUG").removeAll("/Gm"); |
|
291 } |
|
292 |
|
293 conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS")); |
|
294 if(project->isActiveConfig("debug")){ |
|
295 // Debug version |
|
296 if((projectTarget == Application) || (projectTarget == StaticLib)) |
|
297 conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_MT_DBG")); |
|
298 else |
|
299 conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_MT_DLLDBG")); |
|
300 } else { |
|
301 // Release version |
|
302 conf.compiler.PreprocessorDefinitions += "QT_NO_DEBUG"; |
|
303 conf.compiler.PreprocessorDefinitions += "NDEBUG"; |
|
304 if((projectTarget == Application) || (projectTarget == StaticLib)) |
|
305 conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_MT")); |
|
306 else |
|
307 conf.compiler.parseOptions(project->values("QMAKE_CXXFLAGS_MT_DLL")); |
|
308 } |
|
309 |
|
310 // Common for both release and debug |
|
311 if(project->isActiveConfig("windows")) |
|
312 conf.compiler.PreprocessorDefinitions += project->values("MSVCPROJ_WINCONDEF"); |
|
313 |
|
314 // Can this be set for ALL configs? |
|
315 // If so, use qmake.conf! |
|
316 if(projectTarget == SharedLib) |
|
317 conf.compiler.PreprocessorDefinitions += "_WINDOWS"; |
|
318 |
|
319 conf.compiler.PreprocessorDefinitions += project->values("DEFINES"); |
|
320 conf.compiler.PreprocessorDefinitions += project->values("PRL_EXPORT_DEFINES"); |
|
321 conf.compiler.parseOptions(project->values("MSVCPROJ_INCPATH")); |
|
322 } |
|
323 |
|
324 void VcxprojGenerator::initLinkerTool() |
|
325 { |
|
326 findLibraries(); // Need to add the highest version of the libs |
|
327 VCXConfiguration &conf = vcxProject.Configuration; |
|
328 conf.linker.parseOptions(project->values("MSVCPROJ_LFLAGS")); |
|
329 |
|
330 foreach(QString libs, project->values("MSVCPROJ_LIBS")) { |
|
331 if (libs.left(9).toUpper() == "/LIBPATH:") { |
|
332 QStringList l = QStringList(libs); |
|
333 conf.linker.parseOptions(l); |
|
334 } else { |
|
335 conf.linker.AdditionalDependencies += libs; |
|
336 } |
|
337 } |
|
338 |
|
339 switch (projectTarget) { |
|
340 case Application: |
|
341 conf.linker.OutputFile = project->first("DESTDIR"); |
|
342 break; |
|
343 case SharedLib: |
|
344 conf.linker.parseOptions(project->values("MSVCPROJ_LIBOPTIONS")); |
|
345 conf.linker.OutputFile = project->first("DESTDIR"); |
|
346 break; |
|
347 case StaticLib: //unhandled - added to remove warnings.. |
|
348 break; |
|
349 } |
|
350 |
|
351 if(conf.linker.OutputFile.isEmpty()) |
|
352 conf.linker.OutputFile = ".\\"; |
|
353 |
|
354 if(!conf.linker.OutputFile.endsWith("\\")) |
|
355 conf.linker.OutputFile += '\\'; |
|
356 |
|
357 conf.linker.OutputFile += project->first("MSVCPROJ_TARGET"); |
|
358 |
|
359 if(project->isActiveConfig("dll")){ |
|
360 conf.linker.parseOptions(project->values("QMAKE_LFLAGS_QT_DLL")); |
|
361 } |
|
362 } |
|
363 |
|
364 void VcxprojGenerator::initResourceTool() |
|
365 { |
|
366 VCXConfiguration &conf = vcxProject.Configuration; |
|
367 conf.resource.PreprocessorDefinitions = conf.compiler.PreprocessorDefinitions; |
|
368 |
|
369 // We need to add _DEBUG for the debug version of the project, since the normal compiler defines |
|
370 // do not contain it. (The compiler defines this symbol automatically, which is wy we don't need |
|
371 // to add it for the compiler) However, the resource tool does not do this. |
|
372 if(project->isActiveConfig("debug")) |
|
373 conf.resource.PreprocessorDefinitions += "_DEBUG"; |
|
374 if(project->isActiveConfig("staticlib")) |
|
375 conf.resource.ResourceOutputFileName = project->first("DESTDIR") + "/$(InputName).res"; |
|
376 } |
|
377 |
|
378 |
|
379 void VcxprojGenerator::initPostBuildEventTools() |
|
380 { |
|
381 VCXConfiguration &conf = vcxProject.Configuration; |
|
382 if(!project->values("QMAKE_POST_LINK").isEmpty()) { |
|
383 QString cmdline = var("QMAKE_POST_LINK"); |
|
384 conf.postBuild.CommandLine = cmdline; |
|
385 conf.postBuild.Description = cmdline; |
|
386 conf.postBuild.UseInBuild = _True; |
|
387 } |
|
388 |
|
389 QString signature = !project->isEmpty("SIGNATURE_FILE") ? var("SIGNATURE_FILE") : var("DEFAULT_SIGNATURE"); |
|
390 bool useSignature = !signature.isEmpty() && !project->isActiveConfig("staticlib") && |
|
391 !project->isEmpty("CE_SDK") && !project->isEmpty("CE_ARCH"); |
|
392 if(useSignature) { |
|
393 conf.postBuild.CommandLine.prepend(QLatin1String("signtool sign /F ") + signature + " \"$(TargetPath)\"\n" + |
|
394 (!conf.postBuild.CommandLine.isEmpty() ? " && " : "")); |
|
395 conf.postBuild.UseInBuild = _True; |
|
396 } |
|
397 |
|
398 if(!project->values("MSVCPROJ_COPY_DLL").isEmpty()) { |
|
399 if(!conf.postBuild.CommandLine.isEmpty()) |
|
400 conf.postBuild.CommandLine += " && "; |
|
401 conf.postBuild.Description += var("MSVCPROJ_COPY_DLL_DESC"); |
|
402 conf.postBuild.CommandLine += var("MSVCPROJ_COPY_DLL"); |
|
403 conf.postBuild.UseInBuild = _True; |
|
404 } |
|
405 } |
|
406 |
|
407 |
|
408 void VcxprojGenerator::initDeploymentTool() |
|
409 { |
|
410 VCXConfiguration &conf = vcxProject.Configuration; |
|
411 QString targetPath = project->values("deploy.path").join(" "); |
|
412 if (targetPath.isEmpty()) |
|
413 targetPath = QString("%CSIDL_PROGRAM_FILES%\\") + project->first("TARGET"); |
|
414 if (targetPath.endsWith("/") || targetPath.endsWith("\\")) |
|
415 targetPath.chop(1); |
|
416 |
|
417 // Only deploy Qt libs for shared build |
|
418 if (!project->values("QMAKE_QT_DLL").isEmpty()) { |
|
419 QStringList& arg = project->values("MSVCPROJ_LIBS"); |
|
420 for (QStringList::ConstIterator it = arg.constBegin(); it != arg.constEnd(); ++it) { |
|
421 if (it->contains(project->first("QMAKE_LIBDIR"))) { |
|
422 QString dllName = *it; |
|
423 |
|
424 if (dllName.contains(QLatin1String("QAxContainer")) |
|
425 || dllName.contains(QLatin1String("qtmain")) |
|
426 || dllName.contains(QLatin1String("QtUiTools"))) |
|
427 continue; |
|
428 dllName.replace(QLatin1String(".lib") , QLatin1String(".dll")); |
|
429 QFileInfo info(dllName); |
|
430 conf.deployment.AdditionalFiles += info.fileName() |
|
431 + "|" + QDir::toNativeSeparators(info.absolutePath()) |
|
432 + "|" + targetPath |
|
433 + "|0;"; |
|
434 } |
|
435 } |
|
436 } |
|
437 |
|
438 // C-runtime deployment |
|
439 QString runtime = project->values("QT_CE_C_RUNTIME").join(QLatin1String(" ")); |
|
440 if (!runtime.isEmpty() && (runtime != QLatin1String("no"))) { |
|
441 QString runtimeVersion = QLatin1String("msvcr"); |
|
442 QString mkspec = project->first("QMAKESPEC"); |
|
443 // If no .qmake.cache has been found, we fallback to the original mkspec |
|
444 if (mkspec.isEmpty()) |
|
445 mkspec = project->first("QMAKESPEC_ORIGINAL"); |
|
446 |
|
447 if (!mkspec.isEmpty()) { |
|
448 if (mkspec.endsWith("2010")) |
|
449 runtimeVersion.append("100"); |
|
450 else if (mkspec.endsWith("2008")) |
|
451 runtimeVersion.append("90"); |
|
452 else |
|
453 runtimeVersion.append("80"); |
|
454 if (project->isActiveConfig("debug")) |
|
455 runtimeVersion.append("d"); |
|
456 runtimeVersion.append(".dll"); |
|
457 |
|
458 if (runtime == "yes") { |
|
459 // Auto-find C-runtime |
|
460 QString vcInstallDir = qgetenv("VCINSTALLDIR"); |
|
461 if (!vcInstallDir.isEmpty()) { |
|
462 vcInstallDir += "\\ce\\dll\\"; |
|
463 vcInstallDir += project->values("CE_ARCH").join(QLatin1String(" ")); |
|
464 if (!QFileInfo(vcInstallDir + QDir::separator() + runtimeVersion).exists()) |
|
465 runtime.clear(); |
|
466 else |
|
467 runtime = vcInstallDir; |
|
468 } |
|
469 } |
|
470 } |
|
471 |
|
472 if (!runtime.isEmpty() && runtime != QLatin1String("yes")) { |
|
473 conf.deployment.AdditionalFiles += runtimeVersion |
|
474 + "|" + QDir::toNativeSeparators(runtime) |
|
475 + "|" + targetPath |
|
476 + "|0;"; |
|
477 } |
|
478 } |
|
479 |
|
480 // foreach item in DEPLOYMENT |
|
481 foreach(QString item, project->values("DEPLOYMENT")) { |
|
482 // get item.path |
|
483 QString devicePath = project->first(item + ".path"); |
|
484 if (devicePath.isEmpty()) |
|
485 devicePath = targetPath; |
|
486 // check if item.path is relative (! either /,\ or %) |
|
487 if (!(devicePath.at(0) == QLatin1Char('/') |
|
488 || devicePath.at(0) == QLatin1Char('\\') |
|
489 || devicePath.at(0) == QLatin1Char('%'))) { |
|
490 // create output path |
|
491 devicePath = Option::fixPathToLocalOS(QDir::cleanPath(targetPath + QLatin1Char('\\') + devicePath)); |
|
492 } |
|
493 // foreach d in item.sources |
|
494 foreach(QString source, project->values(item + ".sources")) { |
|
495 QString itemDevicePath = devicePath; |
|
496 source = Option::fixPathToLocalOS(source); |
|
497 QString nameFilter; |
|
498 QFileInfo info(source); |
|
499 QString searchPath; |
|
500 if (info.isDir()) { |
|
501 nameFilter = QLatin1String("*"); |
|
502 itemDevicePath += "\\" + info.fileName(); |
|
503 searchPath = info.absoluteFilePath(); |
|
504 } else { |
|
505 nameFilter = source.split('\\').last(); |
|
506 searchPath = info.absolutePath(); |
|
507 } |
|
508 |
|
509 int pathSize = searchPath.size(); |
|
510 QDirIterator iterator(searchPath, QStringList() << nameFilter |
|
511 , QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks |
|
512 , QDirIterator::Subdirectories); |
|
513 // foreach dirIterator-entry in d |
|
514 while(iterator.hasNext()) { |
|
515 iterator.next(); |
|
516 QString absoluteItemPath = Option::fixPathToLocalOS(QFileInfo(iterator.filePath()).absolutePath()); |
|
517 // Identify if it is just another subdir |
|
518 int diffSize = absoluteItemPath.size() - pathSize; |
|
519 // write out rules |
|
520 conf.deployment.AdditionalFiles += iterator.fileName() |
|
521 + "|" + absoluteItemPath |
|
522 + "|" + itemDevicePath + (diffSize ? (absoluteItemPath.right(diffSize)) : QLatin1String("")) |
|
523 + "|0;"; |
|
524 } |
|
525 } |
|
526 } |
|
527 } |
|
528 |
|
529 void VcxprojGenerator::initPreLinkEventTools() |
|
530 { |
|
531 VCXConfiguration &conf = vcxProject.Configuration; |
|
532 if(!project->values("QMAKE_PRE_LINK").isEmpty()) { |
|
533 QString cmdline = var("QMAKE_PRE_LINK"); |
|
534 conf.preLink.Description = cmdline; |
|
535 conf.preLink.CommandLine = cmdline; |
|
536 conf.preLink.UseInBuild = _True; |
|
537 } |
|
538 } |
|
539 |
|
540 void VcxprojGenerator::initRootFiles() |
|
541 { |
|
542 vcxProject.RootFiles.addFiles(project->values("RC_FILE")); |
|
543 vcxProject.RootFiles.Project = this; |
|
544 vcxProject.RootFiles.Config = &(vcxProject.Configuration); |
|
545 vcxProject.RootFiles.CustomBuild = none; |
|
546 } |
|
547 |
|
548 void VcxprojGenerator::initSourceFiles() |
|
549 { |
|
550 vcxProject.SourceFiles.Name = "Source Files"; |
|
551 vcxProject.SourceFiles.Filter = "cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"; |
|
552 vcxProject.SourceFiles.Guid = _GUIDSourceFiles; |
|
553 |
|
554 vcxProject.SourceFiles.addFiles(project->values("SOURCES")); |
|
555 |
|
556 vcxProject.SourceFiles.Project = this; |
|
557 vcxProject.SourceFiles.Config = &(vcxProject.Configuration); |
|
558 vcxProject.SourceFiles.CustomBuild = none; |
|
559 } |
|
560 |
|
561 void VcxprojGenerator::initHeaderFiles() |
|
562 { |
|
563 vcxProject.HeaderFiles.Name = "Header Files"; |
|
564 vcxProject.HeaderFiles.Filter = "h;hpp;hxx;hm;inl;inc;xsd"; |
|
565 vcxProject.HeaderFiles.Guid = _GUIDHeaderFiles; |
|
566 |
|
567 vcxProject.HeaderFiles.addFiles(project->values("HEADERS")); |
|
568 if (usePCH) // Generated PCH cpp file |
|
569 vcxProject.HeaderFiles.addFile(precompH); |
|
570 |
|
571 vcxProject.HeaderFiles.Project = this; |
|
572 vcxProject.HeaderFiles.Config = &(vcxProject.Configuration); |
|
573 } |
|
574 |
|
575 void VcxprojGenerator::initGeneratedFiles() |
|
576 { |
|
577 vcxProject.GeneratedFiles.Name = "Generated Files"; |
|
578 vcxProject.GeneratedFiles.Filter = "cpp;c;cxx;moc;h;def;odl;idl;res"; |
|
579 vcxProject.GeneratedFiles.Guid = _GUIDGeneratedFiles; |
|
580 |
|
581 // ### These cannot have CustomBuild (mocSrc)!! |
|
582 vcxProject.GeneratedFiles.addFiles(project->values("GENERATED_SOURCES")); |
|
583 vcxProject.GeneratedFiles.addFiles(project->values("GENERATED_FILES")); |
|
584 vcxProject.GeneratedFiles.addFiles(project->values("IDLSOURCES")); |
|
585 vcxProject.GeneratedFiles.addFiles(project->values("RES_FILE")); |
|
586 vcxProject.GeneratedFiles.addFiles(project->values("QMAKE_IMAGE_COLLECTION")); // compat |
|
587 if(!extraCompilerOutputs.isEmpty()) |
|
588 vcxProject.GeneratedFiles.addFiles(extraCompilerOutputs.keys()); |
|
589 |
|
590 vcxProject.GeneratedFiles.Project = this; |
|
591 vcxProject.GeneratedFiles.Config = &(vcxProject.Configuration); |
|
592 } |
|
593 |
|
594 void VcxprojGenerator::initLexYaccFiles() |
|
595 { |
|
596 vcxProject.LexYaccFiles.Name = "Lex / Yacc Files"; |
|
597 vcxProject.LexYaccFiles.ParseFiles = _False; |
|
598 vcxProject.LexYaccFiles.Filter = "l;y"; |
|
599 vcxProject.LexYaccFiles.Guid = _GUIDLexYaccFiles; |
|
600 |
|
601 vcxProject.LexYaccFiles.addFiles(project->values("LEXSOURCES")); |
|
602 vcxProject.LexYaccFiles.addFiles(project->values("YACCSOURCES")); |
|
603 |
|
604 vcxProject.LexYaccFiles.Project = this; |
|
605 vcxProject.LexYaccFiles.Config = &(vcxProject.Configuration); |
|
606 vcxProject.LexYaccFiles.CustomBuild = lexyacc; |
|
607 } |
|
608 |
|
609 void VcxprojGenerator::initTranslationFiles() |
|
610 { |
|
611 vcxProject.TranslationFiles.Name = "Translation Files"; |
|
612 vcxProject.TranslationFiles.ParseFiles = _False; |
|
613 vcxProject.TranslationFiles.Filter = "ts;xlf"; |
|
614 vcxProject.TranslationFiles.Guid = _GUIDTranslationFiles; |
|
615 |
|
616 vcxProject.TranslationFiles.addFiles(project->values("TRANSLATIONS")); |
|
617 |
|
618 vcxProject.TranslationFiles.Project = this; |
|
619 vcxProject.TranslationFiles.Config = &(vcxProject.Configuration); |
|
620 vcxProject.TranslationFiles.CustomBuild = none; |
|
621 } |
|
622 |
|
623 |
|
624 void VcxprojGenerator::initFormFiles() |
|
625 { |
|
626 vcxProject.FormFiles.Name = "Form Files"; |
|
627 vcxProject.FormFiles.ParseFiles = _False; |
|
628 vcxProject.FormFiles.Filter = "ui"; |
|
629 vcxProject.FormFiles.Guid = _GUIDFormFiles; |
|
630 |
|
631 vcxProject.FormFiles.addFiles(project->values("FORMS")); |
|
632 vcxProject.FormFiles.addFiles(project->values("FORMS3")); |
|
633 |
|
634 vcxProject.FormFiles.Project = this; |
|
635 vcxProject.FormFiles.Config = &(vcxProject.Configuration); |
|
636 vcxProject.FormFiles.CustomBuild = none; |
|
637 } |
|
638 |
|
639 |
|
640 void VcxprojGenerator::initResourceFiles() |
|
641 { |
|
642 vcxProject.ResourceFiles.Name = "Resource Files"; |
|
643 vcxProject.ResourceFiles.ParseFiles = _False; |
|
644 vcxProject.ResourceFiles.Filter = "qrc;*"; //"rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;ts;xlf;qrc"; |
|
645 vcxProject.ResourceFiles.Guid = _GUIDResourceFiles; |
|
646 |
|
647 // Bad hack, please look away ------------------------------------- |
|
648 QString rcc_dep_cmd = project->values("rcc.depend_command").join(" "); |
|
649 if(!rcc_dep_cmd.isEmpty()) { |
|
650 QStringList qrc_files = project->values("RESOURCES"); |
|
651 QStringList deps; |
|
652 if(!qrc_files.isEmpty()) { |
|
653 for (int i = 0; i < qrc_files.count(); ++i) { |
|
654 char buff[256]; |
|
655 QString dep_cmd = replaceExtraCompilerVariables(rcc_dep_cmd, qrc_files.at(i),""); |
|
656 |
|
657 dep_cmd = Option::fixPathToLocalOS(dep_cmd, true, false); |
|
658 if(canExecute(dep_cmd)) { |
|
659 if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) { |
|
660 QString indeps; |
|
661 while(!feof(proc)) { |
|
662 int read_in = (int)fread(buff, 1, 255, proc); |
|
663 if(!read_in) |
|
664 break; |
|
665 indeps += QByteArray(buff, read_in); |
|
666 } |
|
667 QT_PCLOSE(proc); |
|
668 if(!indeps.isEmpty()) |
|
669 deps += fileFixify(indeps.replace('\n', ' ').simplified().split(' ')); |
|
670 } |
|
671 } |
|
672 } |
|
673 vcxProject.ResourceFiles.addFiles(deps); |
|
674 } |
|
675 } |
|
676 // You may look again -------------------------------------------- |
|
677 |
|
678 vcxProject.ResourceFiles.addFiles(project->values("RESOURCES")); |
|
679 vcxProject.ResourceFiles.addFiles(project->values("IMAGES")); |
|
680 |
|
681 vcxProject.ResourceFiles.Project = this; |
|
682 vcxProject.ResourceFiles.Config = &(vcxProject.Configuration); |
|
683 vcxProject.ResourceFiles.CustomBuild = none; |
|
684 } |
|
685 |
|
686 void VcxprojGenerator::initExtraCompilerOutputs() |
|
687 { |
|
688 QStringList otherFilters; |
|
689 otherFilters << "FORMS" |
|
690 << "FORMS3" |
|
691 << "GENERATED_FILES" |
|
692 << "GENERATED_SOURCES" |
|
693 << "HEADERS" |
|
694 << "IDLSOURCES" |
|
695 << "IMAGES" |
|
696 << "LEXSOURCES" |
|
697 << "QMAKE_IMAGE_COLLECTION" |
|
698 << "RC_FILE" |
|
699 << "RESOURCES" |
|
700 << "RES_FILE" |
|
701 << "SOURCES" |
|
702 << "TRANSLATIONS" |
|
703 << "YACCSOURCES"; |
|
704 const QStringList &quc = project->values("QMAKE_EXTRA_COMPILERS"); |
|
705 for(QStringList::ConstIterator it = quc.begin(); it != quc.end(); ++it) { |
|
706 QString extracompilerName = project->first((*it) + ".name"); |
|
707 if (extracompilerName.isEmpty()) |
|
708 extracompilerName = (*it); |
|
709 |
|
710 // Create an extra compiler filter and add the files |
|
711 VCXFilter extraCompile; |
|
712 extraCompile.Name = extracompilerName; |
|
713 extraCompile.ParseFiles = _False; |
|
714 extraCompile.Filter = ""; |
|
715 extraCompile.Guid = QString(_GUIDExtraCompilerFiles) + "-" + (*it); |
|
716 |
|
717 // If the extra compiler has a variable_out set the output file |
|
718 // is added to an other file list, and does not need its own.. |
|
719 bool addOnInput = hasBuiltinCompiler(project->first((*it) + ".output")); |
|
720 QString tmp_other_out = project->first((*it) + ".variable_out"); |
|
721 if (!tmp_other_out.isEmpty() && !addOnInput) |
|
722 continue; |
|
723 |
|
724 if (!addOnInput) { |
|
725 QString tmp_out = project->first((*it) + ".output"); |
|
726 if (project->values((*it) + ".CONFIG").indexOf("combine") != -1) { |
|
727 // Combined output, only one file result |
|
728 extraCompile.addFile( |
|
729 Option::fixPathToTargetOS(replaceExtraCompilerVariables(tmp_out, QString(), QString()), false)); |
|
730 } else { |
|
731 // One output file per input |
|
732 QStringList tmp_in = project->values(project->first((*it) + ".input")); |
|
733 for (int i = 0; i < tmp_in.count(); ++i) { |
|
734 const QString &filename = tmp_in.at(i); |
|
735 if (extraCompilerSources.contains(filename)) |
|
736 extraCompile.addFile( |
|
737 Option::fixPathToTargetOS(replaceExtraCompilerVariables(filename, tmp_out, QString()), false)); |
|
738 } |
|
739 } |
|
740 } else { |
|
741 // In this case we the outputs have a built-in compiler, so we cannot add the custom |
|
742 // build steps there. So, we turn it around and add it to the input files instead, |
|
743 // provided that the input file variable is not handled already (those in otherFilters |
|
744 // are handled, so we avoid them). |
|
745 QStringList inputVars = project->values((*it) + ".input"); |
|
746 foreach(QString inputVar, inputVars) { |
|
747 if (!otherFilters.contains(inputVar)) { |
|
748 QStringList tmp_in = project->values(inputVar); |
|
749 for (int i = 0; i < tmp_in.count(); ++i) { |
|
750 const QString &filename = tmp_in.at(i); |
|
751 if (extraCompilerSources.contains(filename)) |
|
752 extraCompile.addFile( |
|
753 Option::fixPathToTargetOS(replaceExtraCompilerVariables(filename, QString(), QString()), false)); |
|
754 } |
|
755 } |
|
756 } |
|
757 } |
|
758 extraCompile.Project = this; |
|
759 extraCompile.Config = &(vcxProject.Configuration); |
|
760 extraCompile.CustomBuild = none; |
|
761 |
|
762 vcxProject.ExtraCompilersFiles.append(extraCompile); |
|
763 } |
|
764 } |
|
765 |
|
766 |
|
767 |
|
768 bool VcxprojGenerator::writeProjectMakefile() |
|
769 { |
|
770 usePlatformDir(); |
|
771 QTextStream t(&Option::output); |
|
772 |
|
773 // Check if all requirements are fulfilled |
|
774 if(!project->values("QMAKE_FAILED_REQUIREMENTS").isEmpty()) { |
|
775 fprintf(stderr, "Project file not generated because all requirements not met:\n\t%s\n", |
|
776 var("QMAKE_FAILED_REQUIREMENTS").toLatin1().constData()); |
|
777 return true; |
|
778 } |
|
779 |
|
780 // Generate project file |
|
781 if(project->first("TEMPLATE") == "vcapp" || |
|
782 project->first("TEMPLATE") == "vclib") { |
|
783 if (!mergedProjects.count()) { |
|
784 warn_msg(WarnLogic, "Generator: MSVC.NET: no single configuration created, cannot output project!"); |
|
785 return false; |
|
786 } |
|
787 |
|
788 debug_msg(1, "Generator: MSVC.NET: Writing project file"); |
|
789 VCXProject mergedProject; |
|
790 for (int i = 0; i < mergedProjects.count(); ++i) { |
|
791 VCXProjectSingleConfig *singleProject = &(mergedProjects.at(i)->vcxProject); |
|
792 mergedProject.SingleProjects += *singleProject; |
|
793 for (int j = 0; j < singleProject->ExtraCompilersFiles.count(); ++j) { |
|
794 const QString &compilerName = singleProject->ExtraCompilersFiles.at(j).Name; |
|
795 if (!mergedProject.ExtraCompilers.contains(compilerName)) |
|
796 mergedProject.ExtraCompilers += compilerName; |
|
797 } |
|
798 } |
|
799 |
|
800 if(mergedProjects.count() > 1 && |
|
801 mergedProjects.at(0)->vcxProject.Name == |
|
802 mergedProjects.at(1)->vcxProject.Name) |
|
803 mergedProjects.at(0)->writePrlFile(); |
|
804 mergedProject.Name = unescapeFilePath(project->first("QMAKE_ORIG_TARGET")); |
|
805 mergedProject.Version = mergedProjects.at(0)->vcxProject.Version; |
|
806 mergedProject.ProjectGUID = project->isEmpty("QMAKE_UUID") ? getProjectUUID().toString().toUpper() : project->first("QMAKE_UUID"); |
|
807 mergedProject.Keyword = project->first("VCPROJ_KEYWORD"); |
|
808 mergedProject.SccProjectName = mergedProjects.at(0)->vcxProject.SccProjectName; |
|
809 mergedProject.SccLocalPath = mergedProjects.at(0)->vcxProject.SccLocalPath; |
|
810 mergedProject.PlatformName = mergedProjects.at(0)->vcxProject.PlatformName; |
|
811 |
|
812 XmlOutput xmlOut(t); |
|
813 xmlOut << mergedProject; |
|
814 return true; |
|
815 } else if(project->first("TEMPLATE") == "vcsubdirs") { |
|
816 return writeMakefile(t); |
|
817 } |
|
818 return false; |
|
819 } |
|
820 |
|
821 |
|
822 |
|
823 |
|
824 bool VcxprojGenerator::mergeBuildProject(MakefileGenerator *other) |
|
825 { |
|
826 VcxprojGenerator *otherVC = static_cast<VcxprojGenerator*>(other); |
|
827 if (!otherVC) { |
|
828 warn_msg(WarnLogic, "VcxprojGenerator: Cannot merge other types of projects! (ignored)"); |
|
829 return false; |
|
830 } |
|
831 mergedProjects += otherVC; |
|
832 return true; |
|
833 } |
|
834 |
|
835 QT_END_NAMESPACE |
|
836 |