qmake/generators/win32/msvc_vcxproj.cpp
changeset 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     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