2011-04-27 10:05:43 +00:00
/****************************************************************************
* *
2016-01-15 12:36:27 +00:00
* * Copyright ( C ) 2016 The Qt Company Ltd .
* * Contact : https : //www.qt.io/licensing/
2011-04-27 10:05:43 +00:00
* *
* * This file is part of the qmake application of the Qt Toolkit .
* *
2016-01-15 12:36:27 +00:00
* * $ QT_BEGIN_LICENSE : GPL - EXCEPT $
2012-09-19 12:28:29 +00:00
* * Commercial License Usage
* * Licensees holding valid commercial Qt licenses may use this file in
* * accordance with the commercial license agreement provided with the
* * Software or , alternatively , in accordance with the terms contained in
2015-01-28 08:44:43 +00:00
* * a written agreement between you and The Qt Company . For licensing terms
2016-01-15 12:36:27 +00:00
* * and conditions see https : //www.qt.io/terms-conditions. For further
* * information use the contact form at https : //www.qt.io/contact-us.
2012-09-19 12:28:29 +00:00
* *
2016-01-15 12:36:27 +00:00
* * GNU General Public License Usage
* * Alternatively , this file may be used under the terms of the GNU
* * General Public License version 3 as published by the Free Software
* * Foundation with exceptions as appearing in the file LICENSE . GPL3 - EXCEPT
* * included in the packaging of this file . Please review the following
* * information to ensure the GNU General Public License requirements will
* * be met : https : //www.gnu.org/licenses/gpl-3.0.html.
2011-04-27 10:05:43 +00:00
* *
* * $ QT_END_LICENSE $
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "msvc_vcproj.h"
# include "option.h"
# include "xmloutput.h"
2016-11-28 13:26:40 +00:00
# include <ioutils.h>
2011-04-27 10:05:43 +00:00
# include <qdir.h>
# include <qdiriterator.h>
# include <qcryptographichash.h>
# include <qhash.h>
# include <quuid.h>
2021-08-25 09:52:59 +00:00
# include <qregularexpression.h>
2016-11-28 13:26:40 +00:00
2011-04-27 10:05:43 +00:00
# include <stdlib.h>
2021-10-18 13:09:46 +00:00
# include <tuple>
# include <utility>
2011-04-27 10:05:43 +00:00
//#define DEBUG_SOLUTION_GEN
2016-11-28 13:26:40 +00:00
using namespace QMakeInternal ;
2022-03-18 09:31:16 +00:00
using namespace Qt : : StringLiterals ;
2016-11-28 13:26:40 +00:00
2011-04-27 10:05:43 +00:00
QT_BEGIN_NAMESPACE
// Filter GUIDs (Do NOT change these!) ------------------------------
const char _GUIDSourceFiles [ ] = " {4FC737F1-C7A5-4376-A066-2A32D752A2FF} " ;
const char _GUIDHeaderFiles [ ] = " {93995380-89BD-4b04-88EB-625FBE52EBFB} " ;
const char _GUIDGeneratedFiles [ ] = " {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} " ;
const char _GUIDResourceFiles [ ] = " {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} " ;
const char _GUIDLexYaccFiles [ ] = " {E12AE0D2-192F-4d59-BD23-7D3FA58D3183} " ;
const char _GUIDTranslationFiles [ ] = " {639EADAA-A684-42e4-A9AD-28FC9BCB8F7C} " ;
const char _GUIDFormFiles [ ] = " {99349809-55BA-4b9d-BF79-8FDBB0286EB3} " ;
const char _GUIDExtraCompilerFiles [ ] = " {E0D8C965-CC5F-43d7-AD63-FAEF0BBC0F85} " ;
2015-03-20 09:58:02 +00:00
const char _GUIDDistributionFiles [ ] = " {B83CAF91-C7BF-462F-B76C-EA11631F866C} " ;
2011-04-27 10:05:43 +00:00
// Flatfile Tags ----------------------------------------------------
const char _slnHeader70 [ ] = " Microsoft Visual Studio Solution File, Format Version 7.00 " ;
const char _slnHeader71 [ ] = " Microsoft Visual Studio Solution File, Format Version 8.00 " ;
const char _slnHeader80 [ ] = " Microsoft Visual Studio Solution File, Format Version 9.00 "
" \n # Visual Studio 2005 " ;
const char _slnHeader90 [ ] = " Microsoft Visual Studio Solution File, Format Version 10.00 "
" \n # Visual Studio 2008 " ;
const char _slnHeader100 [ ] = " Microsoft Visual Studio Solution File, Format Version 11.00 "
" \n # Visual Studio 2010 " ;
2012-09-21 14:28:11 +00:00
const char _slnHeader110 [ ] = " Microsoft Visual Studio Solution File, Format Version 12.00 "
" \n # Visual Studio 2012 " ;
2013-07-02 11:48:08 +00:00
const char _slnHeader120 [ ] = " Microsoft Visual Studio Solution File, Format Version 12.00 "
" \n # Visual Studio 2013 " ;
2015-04-17 09:53:28 +00:00
const char _slnHeader140 [ ] = " Microsoft Visual Studio Solution File, Format Version 12.00 "
" \n # Visual Studio 2015 " ;
2016-11-17 09:40:44 +00:00
const char _slnHeader141 [ ] = " Microsoft Visual Studio Solution File, Format Version 12.00 "
2019-02-12 09:37:10 +00:00
" \n # Visual Studio 15 " ;
2019-02-12 08:23:28 +00:00
const char _slnHeader142 [ ] = " Microsoft Visual Studio Solution File, Format Version 12.00 "
" \n # Visual Studio Version 16 " ;
2021-11-09 13:05:04 +00:00
const char _slnHeader143 [ ] = " Microsoft Visual Studio Solution File, Format Version 12.00 "
" \n # Visual Studio Version 17 " ;
2011-04-27 10:05:43 +00:00
// The following UUID _may_ change for later servicepacks...
// If so we need to search through the registry at
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.0\Projects
// to find the subkey that contains a "PossibleProjectExtension"
// containing "vcproj"...
// Use the hardcoded value for now so projects generated on other
// platforms are actually usable.
const char _slnMSVCvcprojGUID [ ] = " {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} " ;
const char _slnProjectBeg [ ] = " \n Project( \" " ;
const char _slnProjectMid [ ] = " \" ) = " ;
const char _slnProjectEnd [ ] = " \n EndProject " ;
const char _slnGlobalBeg [ ] = " \n Global " ;
const char _slnGlobalEnd [ ] = " \n EndGlobal " ;
2013-10-08 06:22:51 +00:00
const char _slnSolutionConf [ ] = " \n \t GlobalSection(SolutionConfigurationPlatforms) = preSolution "
" \n \t \t Debug|Win32 = Debug|Win32 "
" \n \t \t Release|Win32 = Release|Win32 "
2011-04-27 10:05:43 +00:00
" \n \t EndGlobalSection " ;
2013-05-13 12:02:39 +00:00
const char _slnProjDepBeg [ ] = " \n \t ProjectSection(ProjectDependencies) = postProject " ;
const char _slnProjDepEnd [ ] = " \n \t EndProjectSection " ;
2013-10-08 06:22:51 +00:00
const char _slnProjConfBeg [ ] = " \n \t GlobalSection(ProjectConfigurationPlatforms) = postSolution " ;
2011-04-27 10:05:43 +00:00
const char _slnProjRelConfTag1 [ ] = " .Release|%1.ActiveCfg = Release| " ;
const char _slnProjRelConfTag2 [ ] = " .Release|%1.Build.0 = Release| " ;
const char _slnProjDbgConfTag1 [ ] = " .Debug|%1.ActiveCfg = Debug| " ;
const char _slnProjDbgConfTag2 [ ] = " .Debug|%1.Build.0 = Debug| " ;
const char _slnProjConfEnd [ ] = " \n \t EndGlobalSection " ;
const char _slnExtSections [ ] = " \n \t GlobalSection(ExtensibilityGlobals) = postSolution "
" \n \t EndGlobalSection "
" \n \t GlobalSection(ExtensibilityAddIns) = postSolution "
" \n \t EndGlobalSection " ;
// ------------------------------------------------------------------
VcprojGenerator : : VcprojGenerator ( )
: Win32MakefileGenerator ( ) ,
2011-05-05 08:51:27 +00:00
is64Bit ( false ) ,
2017-06-08 08:30:30 +00:00
customBuildToolFilterFileSuffix ( QStringLiteral ( " .cbt " ) ) ,
2018-08-02 22:22:24 +00:00
projectWriter ( nullptr )
2011-04-27 10:05:43 +00:00
{
}
VcprojGenerator : : ~ VcprojGenerator ( )
{
delete projectWriter ;
}
bool VcprojGenerator : : writeMakefile ( QTextStream & t )
{
initProject ( ) ; // Fills the whole project with proper data
// Generate solution file
if ( project - > first ( " TEMPLATE " ) = = " vcsubdirs " ) {
if ( ! project - > isActiveConfig ( " build_pass " ) ) {
debug_msg ( 1 , " Generator: MSVC.NET: Writing solution file " ) ;
writeSubDirs ( t ) ;
} else {
debug_msg ( 1 , " Generator: MSVC.NET: Not writing solution file for build_pass configs " ) ;
}
return true ;
} else
// Generate single configuration project file
if ( project - > first ( " TEMPLATE " ) = = " vcapp " | |
project - > first ( " TEMPLATE " ) = = " vclib " ) {
if ( ! project - > isActiveConfig ( " build_pass " ) ) {
debug_msg ( 1 , " Generator: MSVC.NET: Writing single configuration project file " ) ;
XmlOutput xmlOut ( t ) ;
projectWriter - > write ( xmlOut , vcProject ) ;
}
return true ;
}
return project - > isActiveConfig ( " build_pass " ) ;
}
bool VcprojGenerator : : writeProjectMakefile ( )
{
QTextStream t ( & Option : : output ) ;
// Check if all requirements are fulfilled
if ( ! project - > values ( " QMAKE_FAILED_REQUIREMENTS " ) . isEmpty ( ) ) {
fprintf ( stderr , " Project file not generated because all requirements not met: \n \t %s \n " ,
var ( " QMAKE_FAILED_REQUIREMENTS " ) . toLatin1 ( ) . constData ( ) ) ;
return true ;
}
// Generate project file
if ( project - > first ( " TEMPLATE " ) = = " vcapp " | |
project - > first ( " TEMPLATE " ) = = " vclib " ) {
if ( ! mergedProjects . count ( ) ) {
warn_msg ( WarnLogic , " Generator: MSVC.NET: no single configuration created, cannot output project! " ) ;
return false ;
}
debug_msg ( 1 , " Generator: MSVC.NET: Writing project file " ) ;
VCProject mergedProject ;
for ( int i = 0 ; i < mergedProjects . count ( ) ; + + i ) {
VCProjectSingleConfig * singleProject = & ( mergedProjects . at ( i ) - > vcProject ) ;
mergedProject . SingleProjects + = * singleProject ;
for ( int j = 0 ; j < singleProject - > ExtraCompilersFiles . count ( ) ; + + j ) {
const QString & compilerName = singleProject - > ExtraCompilersFiles . at ( j ) . Name ;
if ( ! mergedProject . ExtraCompilers . contains ( compilerName ) )
mergedProject . ExtraCompilers + = compilerName ;
}
}
if ( mergedProjects . count ( ) > 1 & &
mergedProjects . at ( 0 ) - > vcProject . Name = =
mergedProjects . at ( 1 ) - > vcProject . Name )
mergedProjects . at ( 0 ) - > writePrlFile ( ) ;
2012-09-06 10:21:38 +00:00
mergedProject . Name = project - > first ( " QMAKE_PROJECT_NAME " ) . toQString ( ) ;
2011-04-27 10:05:43 +00:00
mergedProject . Version = mergedProjects . at ( 0 ) - > vcProject . Version ;
2013-12-29 12:54:48 +00:00
mergedProject . SdkVersion = mergedProjects . at ( 0 ) - > vcProject . SdkVersion ;
2012-09-06 10:21:38 +00:00
mergedProject . ProjectGUID = project - > isEmpty ( " QMAKE_UUID " ) ? getProjectUUID ( ) . toString ( ) . toUpper ( ) : project - > first ( " QMAKE_UUID " ) . toQString ( ) ;
mergedProject . Keyword = project - > first ( " VCPROJ_KEYWORD " ) . toQString ( ) ;
2011-04-27 10:05:43 +00:00
mergedProject . SccProjectName = mergedProjects . at ( 0 ) - > vcProject . SccProjectName ;
mergedProject . SccLocalPath = mergedProjects . at ( 0 ) - > vcProject . SccLocalPath ;
mergedProject . PlatformName = mergedProjects . at ( 0 ) - > vcProject . PlatformName ;
2018-07-20 07:21:08 +00:00
mergedProject . WindowsTargetPlatformVersion =
project - > first ( " WINDOWS_TARGET_PLATFORM_VERSION " ) . toQString ( ) ;
mergedProject . WindowsTargetPlatformMinVersion =
project - > first ( " WINDOWS_TARGET_PLATFORM_MIN_VERSION " ) . toQString ( ) ;
2011-04-27 10:05:43 +00:00
XmlOutput xmlOut ( t ) ;
projectWriter - > write ( xmlOut , mergedProject ) ;
return true ;
} else if ( project - > first ( " TEMPLATE " ) = = " vcsubdirs " ) {
return writeMakefile ( t ) ;
}
return false ;
}
struct VcsolutionDepend {
QString uuid ;
2019-08-19 07:42:21 +00:00
QString vcprojFile ;
QString projectName ;
QString target ;
2011-04-27 10:05:43 +00:00
Target targetType ;
QStringList dependencies ;
} ;
2018-11-05 10:16:28 +00:00
/* Disable optimization in getProjectUUID() due to a compiler
* bug in MSVC 2015 that causes ASSERT : " &other != this " in the QString
* copy constructor for non - empty file names at :
* filename . isEmpty ( ) ? project - > first ( " QMAKE_MAKEFILE " ) : filename */
# if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG)
# pragma optimize( "g", off )
# pragma warning ( disable : 4748 )
# endif
2011-04-27 10:05:43 +00:00
QUuid VcprojGenerator : : getProjectUUID ( const QString & filename )
{
bool validUUID = true ;
// Read GUID from variable-space
2017-04-10 08:17:34 +00:00
auto uuid = QUuid : : fromString ( project - > first ( " GUID " ) . toQStringView ( ) ) ;
2011-04-27 10:05:43 +00:00
// If none, create one based on the MD5 of absolute project path
if ( uuid . isNull ( ) | | ! filename . isEmpty ( ) ) {
2014-11-24 15:02:38 +00:00
QString abspath = Option : : fixPathToTargetOS (
filename . isEmpty ( ) ? project - > first ( " QMAKE_MAKEFILE " ) . toQString ( ) : filename ) ;
2013-08-13 20:38:45 +00:00
QByteArray digest = QCryptographicHash : : hash ( abspath . toUtf8 ( ) , QCryptographicHash : : Sha1 ) ;
2011-04-27 10:05:43 +00:00
memcpy ( ( unsigned char * ) ( & uuid ) , digest . constData ( ) , sizeof ( QUuid ) ) ;
validUUID = ! uuid . isNull ( ) ;
uuid . data4 [ 0 ] = ( uuid . data4 [ 0 ] & 0x3F ) | 0x80 ; // UV_DCE variant
uuid . data3 = ( uuid . data3 & 0x0FFF ) | ( QUuid : : Name < < 12 ) ;
}
// If still not valid, generate new one, and suggest adding to .pro
if ( uuid . isNull ( ) | | ! validUUID ) {
uuid = QUuid : : createUuid ( ) ;
fprintf ( stderr ,
" qmake couldn't create a GUID based on filepath, and we couldn't \n find a valid GUID in the .pro file (Consider adding \n 'GUID = %s' to the .pro file) \n " ,
uuid . toString ( ) . toUpper ( ) . toLatin1 ( ) . constData ( ) ) ;
}
// Store GUID in variable-space
2012-09-06 10:21:38 +00:00
project - > values ( " GUID " ) = ProStringList ( uuid . toString ( ) . toUpper ( ) ) ;
2011-04-27 10:05:43 +00:00
return uuid ;
}
2018-11-05 10:16:28 +00:00
# if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG)
# pragma optimize( "g", on )
# endif
2011-04-27 10:05:43 +00:00
QUuid VcprojGenerator : : increaseUUID ( const QUuid & id )
{
QUuid result ( id ) ;
qint64 dataFirst = ( result . data4 [ 0 ] < < 24 ) +
( result . data4 [ 1 ] < < 16 ) +
( result . data4 [ 2 ] < < 8 ) +
result . data4 [ 3 ] ;
qint64 dataLast = ( result . data4 [ 4 ] < < 24 ) +
( result . data4 [ 5 ] < < 16 ) +
( result . data4 [ 6 ] < < 8 ) +
result . data4 [ 7 ] ;
if ( ! ( dataLast + + ) )
dataFirst + + ;
result . data4 [ 0 ] = uchar ( ( dataFirst > > 24 ) & 0xff ) ;
result . data4 [ 1 ] = uchar ( ( dataFirst > > 16 ) & 0xff ) ;
result . data4 [ 2 ] = uchar ( ( dataFirst > > 8 ) & 0xff ) ;
result . data4 [ 3 ] = uchar ( dataFirst & 0xff ) ;
result . data4 [ 4 ] = uchar ( ( dataLast > > 24 ) & 0xff ) ;
result . data4 [ 5 ] = uchar ( ( dataLast > > 16 ) & 0xff ) ;
result . data4 [ 6 ] = uchar ( ( dataLast > > 8 ) & 0xff ) ;
result . data4 [ 7 ] = uchar ( dataLast & 0xff ) ;
return result ;
}
2014-04-02 15:16:33 +00:00
QString VcprojGenerator : : retrievePlatformToolSet ( ) const
{
// The PlatformToolset string corresponds to the name of a directory in
// $(VCTargetsPath)\Platforms\{Win32,x64,...}\PlatformToolsets
// e.g. v90, v100, v110, v110_xp, v120_CTP_Nov, v120, or WindowsSDK7.1
// This environment variable may be set by a commandline build
// environment such as the Windows SDK command prompt
QByteArray envVar = qgetenv ( " PlatformToolset " ) ;
if ( ! envVar . isEmpty ( ) )
return envVar ;
2022-03-18 09:31:16 +00:00
return u " v " _s + project - > first ( " MSVC_TOOLSET_VER " ) ;
2014-04-02 15:16:33 +00:00
}
2014-10-21 11:47:16 +00:00
bool VcprojGenerator : : isStandardSuffix ( const QString & suffix ) const
{
if ( ! project - > values ( " QMAKE_APP_FLAG " ) . isEmpty ( ) ) {
if ( suffix . compare ( " exe " , Qt : : CaseInsensitive ) = = 0 )
return true ;
} else if ( project - > isActiveConfig ( " shared " ) ) {
if ( suffix . compare ( " dll " , Qt : : CaseInsensitive ) = = 0 )
return true ;
} else {
if ( suffix . compare ( " lib " , Qt : : CaseInsensitive ) = = 0 )
return true ;
}
return false ;
}
2015-04-21 13:43:29 +00:00
ProString VcprojGenerator : : firstInputFileName ( const ProString & extraCompilerName ) const
{
2016-01-26 13:38:54 +00:00
for ( const ProString & var : project - > values ( ProKey ( extraCompilerName + " .input " ) ) ) {
2015-04-21 13:43:29 +00:00
const ProStringList & files = project - > values ( var . toKey ( ) ) ;
if ( ! files . isEmpty ( ) )
return files . first ( ) ;
}
return ProString ( ) ;
}
QString VcprojGenerator : : firstExpandedOutputFileName ( const ProString & extraCompilerName )
{
const ProString firstOutput = project - > first ( ProKey ( extraCompilerName + " .output " ) ) ;
return replaceExtraCompilerVariables ( firstOutput . toQString ( ) ,
firstInputFileName ( extraCompilerName ) . toQString ( ) ,
QString ( ) , NoShell ) ;
}
2012-04-25 14:55:28 +00:00
ProStringList VcprojGenerator : : collectDependencies ( QMakeProject * proj , QHash < QString , QString > & projLookup ,
QHash < QString , QString > & projGuids ,
QHash < VcsolutionDepend * , QStringList > & extraSubdirs ,
QHash < QString , VcsolutionDepend * > & solution_depends ,
QList < VcsolutionDepend * > & solution_cleanup ,
QTextStream & t ,
QHash < QString , ProStringList > & subdirProjectLookup ,
const ProStringList & allDependencies )
2011-04-27 10:05:43 +00:00
{
2020-07-06 09:11:44 +00:00
QList < QPair < QString , ProStringList > > collectedSubdirs ;
2012-04-25 14:55:28 +00:00
ProStringList tmp_proj_subdirs = proj - > values ( " SUBDIRS " ) ;
ProStringList projectsInProject ;
2016-01-28 15:09:46 +00:00
const int numSubdirs = tmp_proj_subdirs . size ( ) ;
collectedSubdirs . reserve ( numSubdirs ) ;
for ( int x = 0 ; x < numSubdirs ; + + x ) {
2012-09-06 10:21:38 +00:00
ProString tmpdir = tmp_proj_subdirs . at ( x ) ;
const ProKey tmpdirConfig ( tmpdir + " .CONFIG " ) ;
2011-11-01 09:40:31 +00:00
if ( ! proj - > isEmpty ( tmpdirConfig ) ) {
2012-09-06 10:21:38 +00:00
const ProStringList config = proj - > values ( tmpdirConfig ) ;
2011-11-01 09:40:31 +00:00
if ( config . contains ( QStringLiteral ( " no_default_target " ) ) )
continue ; // Ignore this sub-dir
}
2012-09-06 10:21:38 +00:00
const ProKey fkey ( tmpdir + " .file " ) ;
const ProKey skey ( tmpdir + " .subdir " ) ;
if ( ! proj - > isEmpty ( fkey ) ) {
if ( ! proj - > isEmpty ( skey ) )
2011-04-27 10:05:43 +00:00
warn_msg ( WarnLogic , " Cannot assign both file and subdir for subdir %s " ,
tmpdir . toLatin1 ( ) . constData ( ) ) ;
2012-09-06 10:21:38 +00:00
tmpdir = proj - > first ( fkey ) ;
} else if ( ! proj - > isEmpty ( skey ) ) {
tmpdir = proj - > first ( skey ) ;
2011-04-27 10:05:43 +00:00
}
2012-04-25 14:55:28 +00:00
projectsInProject . append ( tmpdir ) ;
collectedSubdirs . append ( qMakePair ( tmpdir . toQString ( ) , proj - > values ( ProKey ( tmp_proj_subdirs . at ( x ) + " .depends " ) ) ) ) ;
projLookup . insert ( tmp_proj_subdirs . at ( x ) . toQString ( ) , tmpdir . toQString ( ) ) ;
2011-04-27 10:05:43 +00:00
}
2016-01-28 15:09:46 +00:00
for ( const auto & subdir : qAsConst ( collectedSubdirs ) ) {
2012-04-25 14:55:28 +00:00
QString profile = subdir . first ;
2014-11-24 15:02:38 +00:00
QFileInfo fi ( fileInfo ( Option : : normalizePath ( profile ) ) ) ;
2012-04-25 14:55:28 +00:00
if ( fi . exists ( ) ) {
if ( fi . isDir ( ) ) {
if ( ! profile . endsWith ( Option : : dir_sep ) )
profile + = Option : : dir_sep ;
profile + = fi . baseName ( ) + Option : : pro_ext ;
QString profileKey = fi . absoluteFilePath ( ) ;
2014-11-24 15:02:38 +00:00
fi = QFileInfo ( fileInfo ( Option : : normalizePath ( profile ) ) ) ;
2012-04-25 14:55:28 +00:00
if ( ! fi . exists ( ) )
continue ;
projLookup . insert ( profileKey , fi . absoluteFilePath ( ) ) ;
}
QString oldpwd = qmake_getpwd ( ) ;
2013-02-27 18:12:02 +00:00
QString oldoutpwd = Option : : output_dir ;
2012-04-25 14:55:28 +00:00
QMakeProject tmp_proj ;
QString dir = fi . absolutePath ( ) , fn = fi . fileName ( ) ;
if ( ! dir . isEmpty ( ) ) {
if ( ! qmake_setpwd ( dir ) )
fprintf ( stderr , " Cannot find directory: %s " , dir . toLatin1 ( ) . constData ( ) ) ;
}
2013-10-07 16:53:49 +00:00
Option : : output_dir = Option : : globals - > shadowedPath ( QDir : : cleanPath ( dir ) ) ;
2012-04-25 14:55:28 +00:00
if ( tmp_proj . read ( fn ) ) {
// Check if all requirements are fulfilled
if ( ! tmp_proj . isEmpty ( " QMAKE_FAILED_REQUIREMENTS " ) ) {
fprintf ( stderr , " Project file(%s) not added to Solution because all requirements not met: \n \t %s \n " ,
2016-05-13 13:21:05 +00:00
fn . toLatin1 ( ) . constData ( ) ,
tmp_proj . values ( " QMAKE_FAILED_REQUIREMENTS " ) . join ( ' ' ) . toLatin1 ( ) . constData ( ) ) ;
2012-04-25 14:55:28 +00:00
qmake_setpwd ( oldpwd ) ;
2013-02-27 18:12:02 +00:00
Option : : output_dir = oldoutpwd ;
2012-04-25 14:55:28 +00:00
continue ;
}
if ( tmp_proj . first ( " TEMPLATE " ) = = " vcsubdirs " ) {
ProStringList tmpList = collectDependencies ( & tmp_proj , projLookup , projGuids , extraSubdirs , solution_depends , solution_cleanup , t , subdirProjectLookup , subdir . second ) ;
subdirProjectLookup . insert ( subdir . first , tmpList ) ;
} else {
ProStringList tmpList ;
tmpList + = subdir . second ;
tmpList + = allDependencies ;
// Initialize a 'fake' project to get the correct variables
// and to be able to extract all the dependencies
Option : : QMAKE_MODE old_mode = Option : : qmake_mode ;
Option : : qmake_mode = Option : : QMAKE_GENERATE_NOTHING ;
VcprojGenerator tmp_vcproj ;
tmp_vcproj . setNoIO ( true ) ;
tmp_vcproj . setProjectFile ( & tmp_proj ) ;
Option : : qmake_mode = old_mode ;
// We assume project filename is [QMAKE_PROJECT_NAME].vcproj
2019-08-19 07:42:21 +00:00
const ProString projectName = tmp_vcproj . project - > first ( " QMAKE_PROJECT_NAME " ) ;
const QString vcproj = projectName + project - > first ( " VCPROJ_EXTENSION " ) ;
2015-11-27 18:03:37 +00:00
QString vcprojDir = Option : : output_dir ;
2012-04-25 14:55:28 +00:00
// If file doesn't exsist, then maybe the users configuration
// doesn't allow it to be created. Skip to next...
if ( ! exists ( vcprojDir + Option : : dir_sep + vcproj ) ) {
2015-11-27 18:03:37 +00:00
warn_msg ( WarnLogic , " Ignored (not found) '%s' " , QString ( vcprojDir + Option : : dir_sep + vcproj ) . toLatin1 ( ) . constData ( ) ) ;
goto nextfile ; // # Dirty!
2012-04-25 14:55:28 +00:00
}
VcsolutionDepend * newDep = new VcsolutionDepend ;
newDep - > vcprojFile = vcprojDir + Option : : dir_sep + vcproj ;
2019-08-19 07:42:21 +00:00
newDep - > projectName = projectName . toQString ( ) ;
2012-04-25 14:55:28 +00:00
newDep - > target = tmp_proj . first ( " MSVCPROJ_TARGET " ) . toQString ( ) . section ( Option : : dir_sep , - 1 ) ;
newDep - > targetType = tmp_vcproj . projectTarget ;
newDep - > uuid = tmp_proj . isEmpty ( " QMAKE_UUID " ) ? getProjectUUID ( Option : : fixPathToLocalOS ( vcprojDir + QDir : : separator ( ) + vcproj ) ) . toString ( ) . toUpper ( ) : tmp_proj . first ( " QMAKE_UUID " ) . toQString ( ) ;
// We want to store it as the .lib name.
if ( newDep - > target . endsWith ( " .dll " ) )
newDep - > target = newDep - > target . left ( newDep - > target . length ( ) - 3 ) + " lib " ;
2019-08-19 07:42:21 +00:00
projGuids . insert ( newDep - > projectName , newDep - > target ) ;
2012-04-25 14:55:28 +00:00
2015-12-04 11:25:12 +00:00
if ( tmpList . size ( ) ) {
const ProStringList depends = tmpList ;
2016-01-26 13:38:54 +00:00
for ( const ProString & dep : depends ) {
2012-04-25 14:55:28 +00:00
QString depend = dep . toQString ( ) ;
if ( ! projGuids [ depend ] . isEmpty ( ) ) {
newDep - > dependencies < < projGuids [ depend ] ;
} else if ( subdirProjectLookup [ projLookup [ depend ] ] . size ( ) > 0 ) {
2016-01-26 13:38:54 +00:00
const ProStringList tmpLst = subdirProjectLookup [ projLookup [ depend ] ] ;
for ( const ProString & tDep : tmpLst ) {
2012-04-25 14:55:28 +00:00
QString tmpDep = tDep . toQString ( ) ;
newDep - > dependencies < < projGuids [ projLookup [ tmpDep ] ] ;
}
} else {
2015-12-04 11:25:12 +00:00
extraSubdirs . insert ( newDep , tmpList . toQStringList ( ) ) ;
2012-04-25 14:55:28 +00:00
newDep - > dependencies . clear ( ) ;
break ;
}
}
}
// All ActiveQt Server projects are dependent on idc.exe
if ( tmp_proj . values ( " CONFIG " ) . contains ( " qaxserver " ) )
newDep - > dependencies < < " idc.exe " ;
// Add all unknown libs to the deps
2018-10-08 16:24:14 +00:00
QStringList where = QStringList ( ) < < " LIBS " < < " LIBS_PRIVATE "
< < " QMAKE_LIBS " < < " QMAKE_LIBS_PRIVATE " ;
2018-10-18 19:43:59 +00:00
for ( QStringList : : ConstIterator wit = where . cbegin ( ) ;
wit ! = where . cend ( ) ; + + wit ) {
2012-04-25 14:55:28 +00:00
const ProStringList & l = tmp_proj . values ( ProKey ( * wit ) ) ;
for ( ProStringList : : ConstIterator it = l . begin ( ) ; it ! = l . end ( ) ; + + it ) {
2015-12-04 11:15:54 +00:00
const QString opt = fixLibFlag ( * it ) . toQString ( ) ;
2012-04-25 14:55:28 +00:00
if ( ! opt . startsWith ( " / " ) & & // Not a switch
opt ! = newDep - > target & & // Not self
opt ! = " opengl32.lib " & & // We don't care about these libs
opt ! = " glu32.lib " & & // to make depgen alittle faster
opt ! = " kernel32.lib " & &
opt ! = " user32.lib " & &
opt ! = " gdi32.lib " & &
opt ! = " comdlg32.lib " & &
opt ! = " advapi32.lib " & &
opt ! = " shell32.lib " & &
opt ! = " ole32.lib " & &
opt ! = " oleaut32.lib " & &
opt ! = " uuid.lib " & &
opt ! = " imm32.lib " & &
opt ! = " winmm.lib " & &
opt ! = " wsock32.lib " & &
opt ! = " ws2_32.lib " & &
opt ! = " winspool.lib " & &
opt ! = " delayimp.lib " )
{
newDep - > dependencies < < opt . section ( Option : : dir_sep , - 1 ) ;
}
}
}
# ifdef DEBUG_SOLUTION_GEN
qDebug ( " Deps for %20s: [%s] " , newDep - > target . toLatin1 ( ) . constData ( ) , newDep - > dependencies . join ( " :: " ) . toLatin1 ( ) . constData ( ) ) ;
# endif
solution_cleanup . append ( newDep ) ;
solution_depends . insert ( newDep - > target , newDep ) ;
}
nextfile :
qmake_setpwd ( oldpwd ) ;
2013-02-27 18:12:02 +00:00
Option : : output_dir = oldoutpwd ;
2012-04-25 14:55:28 +00:00
}
}
}
return projectsInProject ;
2011-04-27 10:05:43 +00:00
}
void VcprojGenerator : : writeSubDirs ( QTextStream & t )
{
// Check if all requirements are fulfilled
if ( ! project - > values ( " QMAKE_FAILED_REQUIREMENTS " ) . isEmpty ( ) ) {
fprintf ( stderr , " Project file not generated because all requirements not met: \n \t %s \n " ,
var ( " QMAKE_FAILED_REQUIREMENTS " ) . toLatin1 ( ) . constData ( ) ) ;
return ;
}
2016-11-10 08:12:38 +00:00
switch ( vcProject . Configuration . CompilerVersion ) {
2021-11-09 13:05:04 +00:00
case NET2022 :
t < < _slnHeader143 ;
break ;
2019-02-12 08:23:28 +00:00
case NET2019 :
t < < _slnHeader142 ;
break ;
2016-11-17 09:40:44 +00:00
case NET2017 :
t < < _slnHeader141 ;
break ;
2015-04-17 09:53:28 +00:00
case NET2015 :
t < < _slnHeader140 ;
2015-09-05 09:38:56 +00:00
break ;
2013-07-02 11:48:08 +00:00
case NET2013 :
t < < _slnHeader120 ;
break ;
2012-09-21 14:28:11 +00:00
case NET2012 :
t < < _slnHeader110 ;
break ;
2011-04-27 10:05:43 +00:00
case NET2010 :
t < < _slnHeader100 ;
break ;
case NET2008 :
t < < _slnHeader90 ;
break ;
case NET2005 :
t < < _slnHeader80 ;
break ;
case NET2003 :
t < < _slnHeader71 ;
break ;
case NET2002 :
t < < _slnHeader70 ;
break ;
default :
t < < _slnHeader70 ;
2016-11-10 08:12:38 +00:00
warn_msg ( WarnLogic , " Generator: MSVC.NET: Unknown version (%d) of MSVC detected for .sln " ,
vcProject . Configuration . CompilerVersion ) ;
2011-04-27 10:05:43 +00:00
break ;
}
QHash < QString , VcsolutionDepend * > solution_depends ;
QList < VcsolutionDepend * > solution_cleanup ;
// Make sure that all temp projects are configured
// for release so that the depends are created
// without the debug <lib>dxxx.lib name mangling
2017-02-03 17:12:52 +00:00
QString old_after_vars = Option : : globals - > extra_cmds [ QMakeEvalAfter ] ;
Option : : globals - > extra_cmds [ QMakeEvalAfter ] . append ( " \n CONFIG+=release " ) ;
2011-04-27 10:05:43 +00:00
2012-04-25 14:55:28 +00:00
QHash < QString , QString > profileLookup ;
QHash < QString , QString > projGuids ;
QHash < VcsolutionDepend * , QStringList > extraSubdirs ;
QHash < QString , ProStringList > subdirProjectLookup ;
collectDependencies ( project , profileLookup , projGuids , extraSubdirs , solution_depends , solution_cleanup , t , subdirProjectLookup ) ;
2011-04-27 10:05:43 +00:00
2013-05-13 12:02:39 +00:00
// write out projects
for ( QList < VcsolutionDepend * > : : Iterator it = solution_cleanup . begin ( ) ; it ! = solution_cleanup . end ( ) ; + + it ) {
2015-02-06 14:30:02 +00:00
// ### quoting rules?
2013-05-13 12:02:39 +00:00
t < < _slnProjectBeg < < _slnMSVCvcprojGUID < < _slnProjectMid
2019-08-19 07:42:21 +00:00
< < " \" " < < ( * it ) - > projectName < < " \" , \" " < < ( * it ) - > vcprojFile
2013-05-13 12:02:39 +00:00
< < " \" , \" " < < ( * it ) - > uuid < < " \" " ;
debug_msg ( 1 , " Project %s has dependencies: %s " , ( * it ) - > target . toLatin1 ( ) . constData ( ) , ( * it ) - > dependencies . join ( " " ) . toLatin1 ( ) . constData ( ) ) ;
bool hasDependency = false ;
for ( QStringList : : iterator dit = ( * it ) - > dependencies . begin ( ) ; dit ! = ( * it ) - > dependencies . end ( ) ; + + dit ) {
if ( VcsolutionDepend * vc = solution_depends [ * dit ] ) {
if ( ! hasDependency ) {
hasDependency = true ;
t < < _slnProjDepBeg ;
}
t < < " \n \t \t " < < vc - > uuid < < " = " < < vc - > uuid ;
}
}
if ( hasDependency )
t < < _slnProjDepEnd ;
t < < _slnProjectEnd ;
}
2012-04-25 14:55:28 +00:00
t < < _slnGlobalBeg ;
2011-04-27 10:05:43 +00:00
2016-01-28 15:48:36 +00:00
for ( auto extraIt = extraSubdirs . cbegin ( ) , end = extraSubdirs . cend ( ) ; extraIt ! = end ; + + extraIt ) {
2016-01-26 13:38:54 +00:00
for ( const QString & depend : extraIt . value ( ) ) {
2012-04-25 14:55:28 +00:00
if ( ! projGuids [ depend ] . isEmpty ( ) ) {
extraIt . key ( ) - > dependencies < < projGuids [ depend ] ;
} else if ( ! profileLookup [ depend ] . isEmpty ( ) ) {
if ( ! projGuids [ profileLookup [ depend ] ] . isEmpty ( ) )
extraIt . key ( ) - > dependencies < < projGuids [ profileLookup [ depend ] ] ;
2011-04-27 10:05:43 +00:00
}
}
}
2011-05-05 08:51:27 +00:00
QString slnConf = _slnSolutionConf ;
2013-02-11 22:44:39 +00:00
if ( ! project - > isEmpty ( " VCPROJ_ARCH " ) ) {
2016-02-04 14:12:03 +00:00
slnConf . replace ( QLatin1String ( " |Win32 " ) , " | " + project - > first ( " VCPROJ_ARCH " ) ) ;
2011-05-05 08:51:27 +00:00
} else if ( is64Bit ) {
2016-02-04 14:12:03 +00:00
slnConf . replace ( QLatin1String ( " |Win32 " ) , QLatin1String ( " |x64 " ) ) ;
2011-04-27 10:05:43 +00:00
}
2011-05-05 08:51:27 +00:00
t < < slnConf ;
2011-04-27 10:05:43 +00:00
// Restore previous after_user_var options
2017-02-03 17:12:52 +00:00
Option : : globals - > extra_cmds [ QMakeEvalAfter ] = old_after_vars ;
2011-04-27 10:05:43 +00:00
t < < _slnProjConfBeg ;
for ( QList < VcsolutionDepend * > : : Iterator it = solution_cleanup . begin ( ) ; it ! = solution_cleanup . end ( ) ; + + it ) {
2011-05-05 08:51:27 +00:00
QString platform = is64Bit ? " x64 " : " Win32 " ;
2012-01-31 17:36:18 +00:00
QString xplatform = platform ;
2013-02-11 22:44:39 +00:00
if ( ! project - > isEmpty ( " VCPROJ_ARCH " ) ) {
xplatform = project - > first ( " VCPROJ_ARCH " ) . toQString ( ) ;
}
2012-01-31 17:36:18 +00:00
if ( ! project - > isHostBuild ( ) )
platform = xplatform ;
t < < " \n \t \t " < < ( * it ) - > uuid < < QString ( _slnProjDbgConfTag1 ) . arg ( xplatform ) < < platform ;
t < < " \n \t \t " < < ( * it ) - > uuid < < QString ( _slnProjDbgConfTag2 ) . arg ( xplatform ) < < platform ;
t < < " \n \t \t " < < ( * it ) - > uuid < < QString ( _slnProjRelConfTag1 ) . arg ( xplatform ) < < platform ;
t < < " \n \t \t " < < ( * it ) - > uuid < < QString ( _slnProjRelConfTag2 ) . arg ( xplatform ) < < platform ;
2011-04-27 10:05:43 +00:00
}
t < < _slnProjConfEnd ;
t < < _slnExtSections ;
t < < _slnGlobalEnd ;
while ( ! solution_cleanup . isEmpty ( ) )
delete solution_cleanup . takeFirst ( ) ;
}
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
bool VcprojGenerator : : hasBuiltinCompiler ( const QString & file )
{
// Source files
for ( int i = 0 ; i < Option : : cpp_ext . count ( ) ; + + i )
if ( file . endsWith ( Option : : cpp_ext . at ( i ) ) )
return true ;
for ( int i = 0 ; i < Option : : c_ext . count ( ) ; + + i )
if ( file . endsWith ( Option : : c_ext . at ( i ) ) )
return true ;
if ( file . endsWith ( " .rc " )
| | file . endsWith ( " .idl " ) )
return true ;
return false ;
}
2016-12-19 17:56:43 +00:00
void VcprojGenerator : : createCustomBuildToolFakeFile ( const QString & cbtFilePath ,
const QString & realOutFilePath )
{
QFile file ( fileFixify ( cbtFilePath , FileFixifyFromOutdir | FileFixifyAbsolute ) ) ;
if ( file . exists ( ) )
return ;
if ( ! file . open ( QIODevice : : WriteOnly | QIODevice : : Text ) ) {
warn_msg ( WarnLogic , " Cannot create '%s'. " , qPrintable ( file . fileName ( ) ) ) ;
return ;
}
file . write ( " This is a dummy file needed to create " ) ;
file . write ( qPrintable ( realOutFilePath ) ) ;
file . write ( " \n " ) ;
}
2011-04-27 10:05:43 +00:00
void VcprojGenerator : : init ( )
{
2011-05-05 08:51:27 +00:00
is64Bit = ( project - > first ( " QMAKE_TARGET.arch " ) = = " x86_64 " ) ;
2011-04-27 10:05:43 +00:00
projectWriter = createProjectWriter ( ) ;
if ( project - > first ( " TEMPLATE " ) = = " vcsubdirs " ) //too much work for subdirs
return ;
debug_msg ( 1 , " Generator: MSVC.NET: Initializing variables " ) ;
// this should probably not be here, but I'm using it to wrap the .t files
if ( project - > first ( " TEMPLATE " ) = = " vcapp " )
project - > values ( " QMAKE_APP_FLAG " ) . append ( " 1 " ) ;
else if ( project - > first ( " TEMPLATE " ) = = " vclib " )
project - > values ( " QMAKE_LIB_FLAG " ) . append ( " 1 " ) ;
processVars ( ) ;
2015-03-31 15:34:18 +00:00
// set /VERSION for EXE/DLL header
ProString major_minor = project - > first ( " VERSION_PE_HEADER " ) ;
if ( major_minor . isEmpty ( ) ) {
ProString version = project - > first ( " VERSION " ) ;
if ( ! version . isEmpty ( ) ) {
int firstDot = version . indexOf ( " . " ) ;
int secondDot = version . indexOf ( " . " , firstDot + 1 ) ;
major_minor = version . left ( secondDot ) ;
}
2011-04-27 10:05:43 +00:00
}
2015-03-31 15:34:18 +00:00
if ( ! major_minor . isEmpty ( ) )
project - > values ( " QMAKE_LFLAGS " ) . append ( " /VERSION: " + major_minor ) ;
2011-04-27 10:05:43 +00:00
MakefileGenerator : : init ( ) ;
2014-11-12 17:11:43 +00:00
// $$QMAKE.. -> $$MSVCPROJ.. -------------------------------------
const ProStringList & incs = project - > values ( " INCLUDEPATH " ) ;
for ( ProStringList : : ConstIterator incit = incs . begin ( ) ; incit ! = incs . end ( ) ; + + incit ) {
QString inc = ( * incit ) . toQString ( ) ;
2015-02-06 14:30:02 +00:00
project - > values ( " MSVCPROJ_INCPATH " ) . append ( " -I " + escapeFilePath ( inc ) ) ;
2014-11-12 17:11:43 +00:00
}
QString dest = Option : : fixPathToTargetOS ( project - > first ( " TARGET " ) . toQString ( ) ) + project - > first ( " TARGET_EXT " ) ;
project - > values ( " MSVCPROJ_TARGET " ) = ProStringList ( dest ) ;
// DLL COPY ------------------------------------------------------
if ( project - > isActiveConfig ( " dll " ) & & ! project - > values ( " DLLDESTDIR " ) . isEmpty ( ) ) {
const ProStringList & dlldirs = project - > values ( " DLLDESTDIR " ) ;
QString copydll ( " " ) ;
ProStringList : : ConstIterator dlldir ;
for ( dlldir = dlldirs . begin ( ) ; dlldir ! = dlldirs . end ( ) ; + + dlldir ) {
if ( ! copydll . isEmpty ( ) )
copydll + = " && " ;
2015-02-06 14:30:02 +00:00
copydll + = " copy \" $(TargetPath) \" " + escapeFilePath ( * dlldir ) ;
2014-11-12 17:11:43 +00:00
}
QString deststr ( " Copy " + dest + " to " ) ;
for ( dlldir = dlldirs . begin ( ) ; dlldir ! = dlldirs . end ( ) ; ) {
deststr + = * dlldir ;
+ + dlldir ;
if ( dlldir ! = dlldirs . end ( ) )
deststr + = " , " ;
}
project - > values ( " MSVCPROJ_COPY_DLL " ) . append ( copydll ) ;
project - > values ( " MSVCPROJ_COPY_DLL_DESC " ) . append ( deststr ) ;
}
2011-04-27 10:05:43 +00:00
2014-11-12 13:14:59 +00:00
#if 0
// Verbose output if "-d -d"...
qDebug ( " Generator: MSVC.NET: List of current variables: " ) ;
for ( ProValueMap : : ConstIterator it = project - > variables ( ) . begin ( ) ; it ! = project - > variables ( ) . end ( ) ; + + it )
qDebug ( " Generator: MSVC.NET: %s => %s " , qPrintable ( it . key ( ) . toQString ( ) ) , qPrintable ( it . value ( ) . join ( " | " ) ) ) ;
# endif
2011-04-27 10:05:43 +00:00
// Figure out what we're trying to build
if ( project - > first ( " TEMPLATE " ) = = " vcapp " ) {
projectTarget = Application ;
} else if ( project - > first ( " TEMPLATE " ) = = " vclib " ) {
if ( project - > isActiveConfig ( " staticlib " ) ) {
2018-10-08 16:24:14 +00:00
project - > values ( " LIBS " ) + = project - > values ( " RES_FILE " ) ;
2011-04-27 10:05:43 +00:00
projectTarget = StaticLib ;
} else
projectTarget = SharedLib ;
}
// Setup PCH variables
2012-09-06 10:21:38 +00:00
precompH = project - > first ( " PRECOMPILED_HEADER " ) . toQString ( ) ;
2018-11-22 08:26:09 +00:00
precompSource = project - > first ( " PRECOMPILED_SOURCE " ) . toQString ( ) ;
2018-11-22 08:35:38 +00:00
pchIsCFile = project - > isActiveConfig ( " precompile_header_c " ) ;
usePCH = ! precompH . isEmpty ( ) & & ( pchIsCFile | | project - > isActiveConfig ( " precompile_header " ) ) ;
2011-04-27 10:05:43 +00:00
if ( usePCH ) {
precompHFilename = fileInfo ( precompH ) . fileName ( ) ;
// Created files
2015-02-06 14:30:02 +00:00
QString origTarget = project - > first ( " QMAKE_ORIG_TARGET " ) . toQString ( ) ;
2011-04-27 10:05:43 +00:00
precompObj = origTarget + Option : : obj_ext ;
precompPch = origTarget + " .pch " ;
// Add PRECOMPILED_HEADER to HEADERS
if ( ! project - > values ( " HEADERS " ) . contains ( precompH ) )
project - > values ( " HEADERS " ) + = precompH ;
// Return to variable pool
2012-09-06 10:21:38 +00:00
project - > values ( " PRECOMPILED_OBJECT " ) = ProStringList ( precompObj ) ;
project - > values ( " PRECOMPILED_PCH " ) = ProStringList ( precompPch ) ;
2011-04-27 10:05:43 +00:00
2018-11-22 08:26:09 +00:00
autogenPrecompSource = precompSource . isEmpty ( ) & & project - > isActiveConfig ( " autogen_precompile_source " ) ;
if ( autogenPrecompSource ) {
precompSource = precompH
2018-11-22 08:35:38 +00:00
+ ( pchIsCFile
? ( Option : : c_ext . count ( ) ? Option : : c_ext . at ( 0 ) : QLatin1String ( " .c " ) )
: ( Option : : cpp_ext . count ( ) ? Option : : cpp_ext . at ( 0 ) : QLatin1String ( " .cpp " ) ) ) ;
2018-11-22 08:26:09 +00:00
project - > values ( " GENERATED_SOURCES " ) + = precompSource ;
} else if ( ! precompSource . isEmpty ( ) ) {
project - > values ( " SOURCES " ) + = precompSource ;
2011-04-27 10:05:43 +00:00
}
}
2021-10-18 13:09:46 +00:00
// Helper function to create a fake file foo.cbt for the project view.
//
// This prevents VS from complaining about a circular dependency from "foo -> foo".
//
// The .cbt file is added as "source" of the Custom Build Tool. This means, in the project
// view, this is the file the Custom Build Tool property page is attached to.
//
// This function returns a pair with
// - the fully resolved output file path
// - the file path of the .cbt file
auto addExtraCompilerSourceWithCustomBuildToolFakeFile
= [ this ] ( const QString & compilerOutput , const ProString & extraCompiler ,
const QStringList & inputs ) - > std : : pair < QString , QString >
{
QString realOut = replaceExtraCompilerVariables ( compilerOutput , inputs , { } , NoShell ) ;
QString out = realOut + customBuildToolFilterFileSuffix ;
createCustomBuildToolFakeFile ( out , realOut ) ;
out = Option : : fixPathToTargetOS ( out , false ) ;
extraCompilerSources [ out ] + = extraCompiler . toQString ( ) ;
return { realOut , out } ;
} ;
// Add all input files for a custom compiler into a map for uniqueness.
//
// Use .cbt files for the following cases:
// - CONFIG += combine
// - the input has a built-in compiler (e.g. C++ source file)
2016-01-26 13:38:54 +00:00
for ( const ProString & quc : project - > values ( " QMAKE_EXTRA_COMPILERS " ) ) {
2012-09-06 10:21:38 +00:00
const ProStringList & invar = project - > values ( ProKey ( quc + " .input " ) ) ;
const QString compiler_out = project - > first ( ProKey ( quc + " .output " ) ) . toQString ( ) ;
2021-10-18 13:09:46 +00:00
QStringList inputFiles ;
for ( auto it = invar . begin ( ) ; it ! = invar . end ( ) ; + + it )
inputFiles + = project - > values ( it - > toKey ( ) ) . toQStringList ( ) ;
if ( project - > values ( ProKey ( quc + " .CONFIG " ) ) . contains ( " combine " ) ) {
// Handle "CONFIG += combine" extra compilers.
QString realOut ;
QString out ;
std : : tie ( realOut , out )
= addExtraCompilerSourceWithCustomBuildToolFakeFile ( compiler_out , quc , inputFiles ) ;
if ( hasBuiltinCompiler ( realOut ) )
extraCompilerOutputs [ out ] = realOut ;
} else {
// Handle regular 1-to-1 extra compilers.
for ( const QString & file : inputFiles ) {
if ( verifyExtraCompiler ( quc , file ) ) {
if ( ! hasBuiltinCompiler ( file ) ) {
extraCompilerSources [ file ] + = quc . toQString ( ) ;
} else {
QString out ;
std : : tie ( std : : ignore , out )
= addExtraCompilerSourceWithCustomBuildToolFakeFile ( compiler_out ,
quc ,
QStringList ( file ) ) ;
extraCompilerOutputs [ out ] = file ;
2011-04-27 10:05:43 +00:00
}
}
}
}
}
#if 0 // Debugging
2016-01-26 18:45:58 +00:00
for ( auto it = extraCompilerSources . cbegin ( ) , end = extraCompilerSources . cend ( ) ; it ! = end ; + + it )
qDebug ( " Extracompilers for %s are (%s) " , it . key ( ) . toLatin1 ( ) . constData ( ) , it . value ( ) . join ( " , " ) . toLatin1 ( ) . constData ( ) ) ;
for ( auto it = extraCompilerOutputs . cbegin ( ) , end = extraCompilerOutputs . cend ( ) ; it ! = end ; + + it )
2021-10-18 13:27:05 +00:00
qDebug ( " Object mapping for %s is (%s) " , qPrintable ( it . key ( ) ) , qPrintable ( it . value ( ) ) ) ;
2011-04-27 10:05:43 +00:00
qDebug ( " " ) ;
# endif
}
bool VcprojGenerator : : mergeBuildProject ( MakefileGenerator * other )
{
if ( ! other | | ! other - > projectFile ( ) ) {
warn_msg ( WarnLogic , " VcprojGenerator: Cannot merge null project. " ) ;
return false ;
}
if ( other - > projectFile ( ) - > first ( " MAKEFILE_GENERATOR " ) ! = project - > first ( " MAKEFILE_GENERATOR " ) ) {
warn_msg ( WarnLogic , " VcprojGenerator: Cannot merge other types of projects! (ignored) " ) ;
return false ;
}
VcprojGenerator * otherVC = static_cast < VcprojGenerator * > ( other ) ;
mergedProjects + = otherVC ;
return true ;
}
void VcprojGenerator : : initProject ( )
{
// Initialize XML sub elements
// - Do this first since project elements may need
// - to know of certain configuration options
initConfiguration ( ) ;
initRootFiles ( ) ;
initSourceFiles ( ) ;
initHeaderFiles ( ) ;
initGeneratedFiles ( ) ;
initLexYaccFiles ( ) ;
initTranslationFiles ( ) ;
initFormFiles ( ) ;
initResourceFiles ( ) ;
2015-03-20 09:58:02 +00:00
initDistributionFiles ( ) ;
2011-04-27 10:05:43 +00:00
initExtraCompilerOutputs ( ) ;
// Own elements -----------------------------
2015-02-06 14:30:02 +00:00
vcProject . Name = project - > first ( " QMAKE_ORIG_TARGET " ) . toQString ( ) ;
2016-11-10 08:12:38 +00:00
switch ( vcProject . Configuration . CompilerVersion ) {
2021-11-09 13:05:04 +00:00
case NET2022 :
vcProject . Version = " 17.00 " ;
break ;
2019-02-12 08:23:28 +00:00
case NET2019 :
vcProject . Version = " 16.00 " ;
break ;
2016-11-17 09:40:44 +00:00
case NET2017 :
vcProject . Version = " 15.00 " ;
break ;
2015-04-17 09:53:28 +00:00
case NET2015 :
vcProject . Version = " 14.00 " ;
break ;
2013-07-02 11:48:08 +00:00
case NET2013 :
2014-01-06 20:48:48 +00:00
vcProject . Version = " 12.00 " ;
2013-07-02 11:48:08 +00:00
break ;
2012-09-21 14:28:11 +00:00
case NET2012 :
2014-01-06 20:48:48 +00:00
vcProject . Version = " 11.00 " ;
2012-09-21 14:28:11 +00:00
break ;
2011-04-27 10:05:43 +00:00
case NET2010 :
vcProject . Version = " 10.00 " ;
break ;
case NET2008 :
vcProject . Version = " 9,00 " ;
break ;
case NET2005 :
//### using ',' because of a bug in 2005 B2
//### VS uses '.' or ',' depending on the regional settings! Using ',' always works.
vcProject . Version = " 8,00 " ;
break ;
case NET2003 :
vcProject . Version = " 7.10 " ;
break ;
case NET2002 :
vcProject . Version = " 7.00 " ;
break ;
default :
vcProject . Version = " 7.00 " ;
2016-11-10 08:12:38 +00:00
warn_msg ( WarnLogic , " Generator: MSVC.NET: Unknown version (%d) of MSVC detected for .vcproj " , vcProject . Configuration . CompilerVersion ) ;
2011-04-27 10:05:43 +00:00
break ;
}
2012-09-06 10:21:38 +00:00
vcProject . Keyword = project - > first ( " VCPROJ_KEYWORD " ) . toQString ( ) ;
2013-02-11 22:44:39 +00:00
if ( ! project - > isEmpty ( " VCPROJ_ARCH " ) ) {
vcProject . PlatformName = project - > first ( " VCPROJ_ARCH " ) . toQString ( ) ;
2016-09-22 07:00:15 +00:00
} else {
2011-05-05 08:51:27 +00:00
vcProject . PlatformName = ( is64Bit ? " x64 " : " Win32 " ) ;
2011-04-27 10:05:43 +00:00
}
2013-12-29 12:54:48 +00:00
vcProject . SdkVersion = project - > first ( " WINSDK_VER " ) . toQString ( ) ;
2011-04-27 10:05:43 +00:00
// These are not used by Qt, but may be used by customers
2012-09-06 10:21:38 +00:00
vcProject . SccProjectName = project - > first ( " SCCPROJECTNAME " ) . toQString ( ) ;
vcProject . SccLocalPath = project - > first ( " SCCLOCALPATH " ) . toQString ( ) ;
2011-04-27 10:05:43 +00:00
vcProject . flat_files = project - > isActiveConfig ( " flat " ) ;
2019-08-19 07:17:24 +00:00
// Set up the full target path for target conflict checking.
const QChar slash = QLatin1Char ( ' / ' ) ;
QString destdir = QDir : : fromNativeSeparators ( var ( " DESTDIR " ) ) ;
if ( ! destdir . endsWith ( slash ) )
destdir . append ( slash ) ;
project - > values ( " DEST_TARGET " ) = ProStringList ( destdir
+ project - > first ( " TARGET " )
+ project - > first ( " TARGET_EXT " ) ) ;
2011-04-27 10:05:43 +00:00
}
void VcprojGenerator : : initConfiguration ( )
{
// Initialize XML sub elements
// - Do this first since main configuration elements may need
// - to know of certain compiler/linker options
VCConfiguration & conf = vcProject . Configuration ;
2014-09-12 15:34:57 +00:00
conf . suppressUnknownOptionWarnings = project - > isActiveConfig ( " suppress_vcproj_warnings " ) ;
2016-11-10 08:40:09 +00:00
conf . CompilerVersion = vsVersionFromString ( project - > first ( " MSVC_VER " ) ) ;
2011-04-27 10:05:43 +00:00
initCompilerTool ( ) ;
// Only on configuration per build
bool isDebug = project - > isActiveConfig ( " debug " ) ;
if ( projectTarget = = StaticLib )
initLibrarianTool ( ) ;
else {
2013-11-18 20:39:08 +00:00
conf . linker . GenerateDebugInformation = project - > isActiveConfig ( " debug_info " ) ? _True : _False ;
2011-04-27 10:05:43 +00:00
initLinkerTool ( ) ;
}
2013-06-18 06:58:31 +00:00
initManifestTool ( ) ;
2011-04-27 10:05:43 +00:00
initResourceTool ( ) ;
initIDLTool ( ) ;
// Own elements -----------------------------
2012-09-06 10:21:38 +00:00
ProString temp = project - > first ( " BuildBrowserInformation " ) ;
2011-04-27 10:05:43 +00:00
switch ( projectTarget ) {
case SharedLib :
conf . ConfigurationType = typeDynamicLibrary ;
break ;
case StaticLib :
conf . ConfigurationType = typeStaticLibrary ;
break ;
case Application :
default :
conf . ConfigurationType = typeApplication ;
break ;
}
2012-09-06 10:21:38 +00:00
conf . OutputDirectory = project - > first ( " DESTDIR " ) . toQString ( ) ;
2011-04-27 10:05:43 +00:00
if ( conf . OutputDirectory . isEmpty ( ) )
conf . OutputDirectory = " . \\ " ;
if ( ! conf . OutputDirectory . endsWith ( " \\ " ) )
conf . OutputDirectory + = ' \\ ' ;
if ( conf . CompilerVersion > = NET2010 ) {
2014-04-02 15:16:33 +00:00
conf . PlatformToolSet = retrievePlatformToolSet ( ) ;
2014-10-21 11:47:16 +00:00
const QFileInfo targetInfo = fileInfo ( project - > first ( " MSVCPROJ_TARGET " ) . toQString ( ) ) ;
conf . PrimaryOutput = targetInfo . completeBaseName ( ) ;
const QString targetSuffix = targetInfo . suffix ( ) ;
if ( ! isStandardSuffix ( targetSuffix ) )
conf . PrimaryOutputExtension = ' . ' + targetSuffix ;
2011-04-27 10:05:43 +00:00
}
2012-05-18 18:00:23 +00:00
conf . Name = project - > values ( " BUILD_NAME " ) . join ( ' ' ) ;
2011-04-27 10:05:43 +00:00
if ( conf . Name . isEmpty ( ) )
conf . Name = isDebug ? " Debug " : " Release " ;
conf . ConfigurationName = conf . Name ;
2013-02-11 22:44:39 +00:00
if ( ! project - > isEmpty ( " VCPROJ_ARCH " ) ) {
conf . Name + = " | " + project - > first ( " VCPROJ_ARCH " ) ;
2016-09-22 07:00:15 +00:00
} else {
2011-05-05 08:51:27 +00:00
conf . Name + = ( is64Bit ? " |x64 " : " |Win32 " ) ;
2011-04-27 10:05:43 +00:00
}
conf . ATLMinimizesCRunTimeLibraryUsage = ( project - > first ( " ATLMinimizesCRunTimeLibraryUsage " ) . isEmpty ( ) ? _False : _True ) ;
conf . BuildBrowserInformation = triState ( temp . isEmpty ( ) ? ( short ) unset : temp . toShort ( ) ) ;
temp = project - > first ( " CharacterSet " ) ;
2020-06-05 07:24:37 +00:00
conf . CharacterSet = charSet ( temp . isEmpty ( ) ? short ( charSetNotSet ) : temp . toShort ( ) ) ;
2012-09-06 10:21:38 +00:00
conf . DeleteExtensionsOnClean = project - > first ( " DeleteExtensionsOnClean " ) . toQString ( ) ;
2011-04-27 10:05:43 +00:00
conf . ImportLibrary = conf . linker . ImportLibrary ;
2012-09-06 10:21:38 +00:00
conf . IntermediateDirectory = project - > first ( " OBJECTS_DIR " ) . toQString ( ) ;
2011-04-27 10:05:43 +00:00
conf . WholeProgramOptimization = conf . compiler . WholeProgramOptimization ;
temp = project - > first ( " UseOfATL " ) ;
if ( ! temp . isEmpty ( ) )
conf . UseOfATL = useOfATL ( temp . toShort ( ) ) ;
temp = project - > first ( " UseOfMfc " ) ;
if ( ! temp . isEmpty ( ) )
conf . UseOfMfc = useOfMfc ( temp . toShort ( ) ) ;
// Configuration does not need parameters from
// these sub XML items;
initCustomBuildTool ( ) ;
initPreBuildEventTools ( ) ;
initPostBuildEventTools ( ) ;
2017-07-14 09:50:00 +00:00
// Only deploy for crosscompiled projects
2020-06-05 07:24:37 +00:00
if ( ! project - > isHostBuild ( ) )
2011-04-27 10:05:43 +00:00
initDeploymentTool ( ) ;
2014-02-11 11:49:18 +00:00
initWinDeployQtTool ( ) ;
2011-04-27 10:05:43 +00:00
initPreLinkEventTools ( ) ;
}
2021-08-25 09:52:59 +00:00
// Filter from the given QMAKE_CFLAGS the options that are relevant
// for the vcxproj-global VCCLCompilerTool.
static ProStringList relevantCFlags ( const ProStringList & flags )
{
ProStringList result ;
static const QRegularExpression rex ( " ^[/-]std: " ) ;
for ( const ProString & flag : flags ) {
if ( rex . match ( flag . toQString ( ) ) . hasMatch ( ) ) {
result . append ( flag ) ;
}
}
return result ;
}
2011-04-27 10:05:43 +00:00
void VcprojGenerator : : initCompilerTool ( )
{
2012-09-06 10:21:38 +00:00
QString placement = project - > first ( " OBJECTS_DIR " ) . toQString ( ) ;
2011-04-27 10:05:43 +00:00
if ( placement . isEmpty ( ) )
placement = " . \\ " ;
VCConfiguration & conf = vcProject . Configuration ;
2012-01-06 15:40:27 +00:00
if ( conf . CompilerVersion > = NET2010 ) {
// adjust compiler tool defaults for VS 2010 and above
conf . compiler . Optimization = optimizeDisabled ;
}
2011-04-27 10:05:43 +00:00
conf . compiler . AssemblerListingLocation = placement ;
conf . compiler . ObjectFile = placement ;
conf . compiler . ExceptionHandling = ehNone ;
// PCH
if ( usePCH ) {
conf . compiler . UsePrecompiledHeader = pchUseUsingSpecific ;
conf . compiler . PrecompiledHeaderFile = " $(IntDir) \\ " + precompPch ;
2012-09-06 10:21:38 +00:00
conf . compiler . PrecompiledHeaderThrough = project - > first ( " PRECOMPILED_HEADER " ) . toQString ( ) ;
conf . compiler . ForcedIncludeFiles = project - > values ( " PRECOMPILED_HEADER " ) . toQStringList ( ) ;
2011-04-27 10:05:43 +00:00
}
2021-08-25 09:52:59 +00:00
conf . compiler . parseOptions ( relevantCFlags ( project - > values ( " QMAKE_CFLAGS " ) ) ) ;
2011-04-27 10:05:43 +00:00
conf . compiler . parseOptions ( project - > values ( " QMAKE_CXXFLAGS " ) ) ;
if ( project - > isActiveConfig ( " windows " ) )
conf . compiler . PreprocessorDefinitions + = " _WINDOWS " ;
else if ( project - > isActiveConfig ( " console " ) )
conf . compiler . PreprocessorDefinitions + = " _CONSOLE " ;
2012-09-06 10:21:38 +00:00
conf . compiler . PreprocessorDefinitions + = project - > values ( " DEFINES " ) . toQStringList ( ) ;
conf . compiler . PreprocessorDefinitions + = project - > values ( " PRL_EXPORT_DEFINES " ) . toQStringList ( ) ;
2011-04-27 10:05:43 +00:00
conf . compiler . parseOptions ( project - > values ( " MSVCPROJ_INCPATH " ) ) ;
}
void VcprojGenerator : : initLibrarianTool ( )
{
VCConfiguration & conf = vcProject . Configuration ;
conf . librarian . OutputFile = " $(OutDir) \\ " ;
2012-09-06 10:21:38 +00:00
conf . librarian . OutputFile + = project - > first ( " MSVCPROJ_TARGET " ) . toQString ( ) ;
conf . librarian . AdditionalOptions + = project - > values ( " QMAKE_LIBFLAGS " ) . toQStringList ( ) ;
2011-04-27 10:05:43 +00:00
}
2013-06-18 06:58:31 +00:00
void VcprojGenerator : : initManifestTool ( )
{
VCManifestTool & tool = vcProject . Configuration . manifestTool ;
const ProString tmplt = project - > first ( " TEMPLATE " ) ;
if ( ( tmplt = = " vclib "
& & ! project - > isActiveConfig ( " embed_manifest_dll " )
& & ! project - > isActiveConfig ( " static " ) )
| | ( tmplt = = " vcapp "
& & ! project - > isActiveConfig ( " embed_manifest_exe " ) ) ) {
tool . EmbedManifest = _False ;
}
}
2011-04-27 10:05:43 +00:00
void VcprojGenerator : : initLinkerTool ( )
{
VCConfiguration & conf = vcProject . Configuration ;
conf . linker . parseOptions ( project - > values ( " QMAKE_LFLAGS " ) ) ;
if ( ! project - > values ( " DEF_FILE " ) . isEmpty ( ) )
2012-09-06 10:21:38 +00:00
conf . linker . ModuleDefinitionFile = project - > first ( " DEF_FILE " ) . toQString ( ) ;
2011-04-27 10:05:43 +00:00
2018-10-08 16:24:14 +00:00
static const char * const lflags [ ] = { " LIBS " , " LIBS_PRIVATE " ,
" QMAKE_LIBS " , " QMAKE_LIBS_PRIVATE " , nullptr } ;
2015-10-27 14:13:34 +00:00
for ( int i = 0 ; lflags [ i ] ; i + + ) {
2016-01-26 13:38:54 +00:00
const auto libs = fixLibFlags ( lflags [ i ] ) ;
for ( const ProString & lib : libs ) {
2015-10-27 14:13:34 +00:00
if ( lib . startsWith ( " /LIBPATH: " ) )
conf . linker . AdditionalLibraryDirectories < < lib . mid ( 9 ) . toQString ( ) ;
else
conf . linker . AdditionalDependencies < < lib . toQString ( ) ;
2011-04-27 10:05:43 +00:00
}
}
conf . linker . OutputFile = " $(OutDir) \\ " ;
2012-09-06 10:21:38 +00:00
conf . linker . OutputFile + = project - > first ( " MSVCPROJ_TARGET " ) . toQString ( ) ;
2011-04-27 10:05:43 +00:00
}
void VcprojGenerator : : initResourceTool ( )
{
VCConfiguration & conf = vcProject . Configuration ;
2015-05-27 20:31:21 +00:00
ProStringList rcDefines = project - > values ( " RC_DEFINES " ) ;
if ( rcDefines . size ( ) > 0 )
conf . resource . PreprocessorDefinitions = rcDefines . toQStringList ( ) ;
else
conf . resource . PreprocessorDefinitions = conf . compiler . PreprocessorDefinitions ;
2011-04-27 10:05:43 +00:00
2016-01-26 13:38:54 +00:00
for ( const ProString & path : project - > values ( " RC_INCLUDEPATH " ) ) {
2012-12-06 15:29:30 +00:00
QString fixedPath = fileFixify ( path . toQString ( ) ) ;
if ( fileInfo ( fixedPath ) . isRelative ( ) ) {
2016-01-19 07:55:32 +00:00
if ( fixedPath = = QLatin1String ( " . " ) )
2012-12-06 15:29:30 +00:00
fixedPath = QStringLiteral ( " $(ProjectDir) " ) ;
else
fixedPath . prepend ( QStringLiteral ( " $(ProjectDir) \\ " ) ) ;
}
conf . resource . AdditionalIncludeDirectories < < escapeFilePath ( fixedPath ) ;
}
2011-04-27 10:05:43 +00:00
// We need to add _DEBUG for the debug version of the project, since the normal compiler defines
// do not contain it. (The compiler defines this symbol automatically, which is wy we don't need
// to add it for the compiler) However, the resource tool does not do this.
if ( project - > isActiveConfig ( " debug " ) )
conf . resource . PreprocessorDefinitions + = " _DEBUG " ;
2014-12-02 10:20:43 +00:00
if ( conf . CompilerVersion < NET2010 & & project - > isActiveConfig ( " staticlib " ) )
2011-04-27 10:05:43 +00:00
conf . resource . ResourceOutputFileName = " $(OutDir) \\ $(InputName).res " ;
}
void VcprojGenerator : : initIDLTool ( )
{
}
void VcprojGenerator : : initCustomBuildTool ( )
{
}
void VcprojGenerator : : initPreBuildEventTools ( )
{
}
void VcprojGenerator : : initPostBuildEventTools ( )
{
VCConfiguration & conf = vcProject . Configuration ;
if ( ! project - > values ( " QMAKE_POST_LINK " ) . isEmpty ( ) ) {
QStringList cmdline = VCToolBase : : fixCommandLine ( var ( " QMAKE_POST_LINK " ) ) ;
conf . postBuild . CommandLine = cmdline ;
conf . postBuild . Description = cmdline . join ( QLatin1String ( " \r \n " ) ) ;
conf . postBuild . ExcludedFromBuild = _False ;
}
if ( ! project - > values ( " MSVCPROJ_COPY_DLL " ) . isEmpty ( ) ) {
conf . postBuild . Description + = var ( " MSVCPROJ_COPY_DLL_DESC " ) ;
conf . postBuild . CommandLine + = var ( " MSVCPROJ_COPY_DLL " ) ;
conf . postBuild . ExcludedFromBuild = _False ;
}
}
void VcprojGenerator : : initDeploymentTool ( )
{
VCConfiguration & conf = vcProject . Configuration ;
2013-02-11 23:25:23 +00:00
QString targetPath ;
2020-06-05 07:24:37 +00:00
targetPath = project - > values ( " deploy.path " ) . join ( ' ' ) ;
if ( targetPath . isEmpty ( ) )
targetPath = QString ( " %CSIDL_PROGRAM_FILES% \\ " ) + project - > first ( " TARGET " ) ;
if ( targetPath . endsWith ( " / " ) | | targetPath . endsWith ( " \\ " ) )
targetPath . chop ( 1 ) ;
conf . deployment . RemoteDirectory = targetPath ;
2016-01-26 13:38:54 +00:00
const ProStringList dllPaths = project - > values ( " QMAKE_DLL_PATHS " ) ;
2011-04-27 10:05:43 +00:00
// Only deploy Qt libs for shared build
2020-06-05 07:24:37 +00:00
if ( ! dllPaths . isEmpty ( ) ) {
2012-07-12 18:33:25 +00:00
// FIXME: This code should actually resolve the libraries from all Qt modules.
2018-10-08 16:24:14 +00:00
ProStringList arg = project - > values ( " LIBS " ) + project - > values ( " LIBS_PRIVATE " )
+ project - > values ( " QMAKE_LIBS " ) + project - > values ( " QMAKE_LIBS_PRIVATE " ) ;
2016-03-21 07:42:11 +00:00
bool qpaPluginDeployed = false ;
2012-09-06 10:21:38 +00:00
for ( ProStringList : : ConstIterator it = arg . constBegin ( ) ; it ! = arg . constEnd ( ) ; + + it ) {
2015-03-16 13:15:27 +00:00
QString dllName = ( * it ) . toQString ( ) ;
dllName . replace ( QLatin1Char ( ' \\ ' ) , QLatin1Char ( ' / ' ) ) ;
// LIBPATH isn't relevant for deployment
if ( dllName . startsWith ( QLatin1String ( " /LIBPATH: " ) ) )
continue ;
// We want to deploy .dlls not .libs
if ( dllName . endsWith ( QLatin1String ( " .lib " ) ) )
dllName . replace ( dllName . length ( ) - 3 , 3 , QLatin1String ( " dll " ) ) ;
// Use only the file name and check in Qt's install path and LIBPATHs to check for existence
dllName . remove ( 0 , dllName . lastIndexOf ( QLatin1Char ( ' / ' ) ) + 1 ) ;
QFileInfo info ;
2016-01-26 13:38:54 +00:00
for ( const ProString & dllPath : dllPaths ) {
2015-03-16 13:15:27 +00:00
QString absoluteDllFilePath = dllPath . toQString ( ) ;
if ( ! absoluteDllFilePath . endsWith ( QLatin1Char ( ' / ' ) ) )
absoluteDllFilePath + = QLatin1Char ( ' / ' ) ;
absoluteDllFilePath + = dllName ;
info = QFileInfo ( absoluteDllFilePath ) ;
if ( info . exists ( ) )
break ;
}
2011-04-27 10:05:43 +00:00
2015-03-16 13:15:27 +00:00
if ( ! info . exists ( ) )
continue ;
2020-06-05 07:24:37 +00:00
conf . deployment . AdditionalFiles + = info . fileName ( )
+ " | " + QDir : : toNativeSeparators ( info . absolutePath ( ) )
+ " | " + targetPath
+ " |0; " ;
if ( ! qpaPluginDeployed ) {
QString debugInfix ;
bool foundGuid = dllName . contains ( QLatin1String ( " Guid " ) ) ;
if ( foundGuid )
debugInfix = QLatin1Char ( ' d ' ) ;
if ( foundGuid | | dllName . contains ( QLatin1String ( " Gui " ) ) ) {
QFileInfo info2 ;
for ( const ProString & dllPath : dllPaths ) {
QString absoluteDllFilePath = dllPath . toQString ( ) ;
if ( ! absoluteDllFilePath . endsWith ( QLatin1Char ( ' / ' ) ) )
absoluteDllFilePath + = QLatin1Char ( ' / ' ) ;
absoluteDllFilePath + = QLatin1String ( " ../plugins/platforms/qwindows " )
+ debugInfix + QLatin1String ( " .dll " ) ;
info2 = QFileInfo ( absoluteDllFilePath ) ;
if ( info2 . exists ( ) )
break ;
}
if ( info2 . exists ( ) ) {
conf . deployment . AdditionalFiles + = QLatin1String ( " qwindows " ) + debugInfix + QLatin1String ( " .dll " )
+ QLatin1Char ( ' | ' ) + QDir : : toNativeSeparators ( info2 . absolutePath ( ) )
+ QLatin1Char ( ' | ' ) + targetPath + QLatin1String ( " \\ platforms " )
+ QLatin1String ( " |0; " ) ;
qpaPluginDeployed = true ;
2016-03-21 07:42:11 +00:00
}
}
2011-04-27 10:05:43 +00:00
}
}
}
2016-01-26 13:38:54 +00:00
for ( const ProString & item : project - > values ( " INSTALLS " ) ) {
2011-04-27 10:05:43 +00:00
// get item.path
2012-09-06 10:21:38 +00:00
QString devicePath = project - > first ( ProKey ( item + " .path " ) ) . toQString ( ) ;
2020-06-05 07:24:37 +00:00
if ( devicePath . isEmpty ( ) )
devicePath = targetPath ;
// check if item.path is relative (! either /,\ or %)
if ( ! ( devicePath . at ( 0 ) = = QLatin1Char ( ' / ' )
| | devicePath . at ( 0 ) = = QLatin1Char ( ' \\ ' )
| | devicePath . at ( 0 ) = = QLatin1Char ( ' % ' ) ) ) {
// create output path
devicePath = Option : : fixPathToTargetOS ( targetPath + QLatin1Char ( ' \\ ' ) + devicePath ) ;
2011-04-27 10:05:43 +00:00
}
2012-07-02 13:21:15 +00:00
// foreach d in item.files
2016-01-26 13:38:54 +00:00
for ( const ProString & src : project - > values ( ProKey ( item + " .files " ) ) ) {
2011-04-27 10:05:43 +00:00
QString itemDevicePath = devicePath ;
2014-11-24 15:02:38 +00:00
QString source = Option : : normalizePath ( src . toQString ( ) ) ;
2011-04-27 10:05:43 +00:00
QString nameFilter ;
QFileInfo info ( source ) ;
QString searchPath ;
if ( info . isDir ( ) ) {
nameFilter = QLatin1String ( " * " ) ;
itemDevicePath + = " \\ " + info . fileName ( ) ;
searchPath = info . absoluteFilePath ( ) ;
} else {
2014-11-24 15:02:38 +00:00
nameFilter = info . fileName ( ) ;
2011-04-27 10:05:43 +00:00
searchPath = info . absolutePath ( ) ;
}
int pathSize = searchPath . size ( ) ;
QDirIterator iterator ( searchPath , QStringList ( ) < < nameFilter
, QDir : : Files | QDir : : NoDotAndDotDot | QDir : : NoSymLinks
, QDirIterator : : Subdirectories ) ;
// foreach dirIterator-entry in d
while ( iterator . hasNext ( ) ) {
iterator . next ( ) ;
2013-02-11 23:25:23 +00:00
2020-06-05 07:24:37 +00:00
QString absoluteItemPath = Option : : fixPathToTargetOS ( QFileInfo ( iterator . filePath ( ) ) . absolutePath ( ) ) ;
// Identify if it is just another subdir
int diffSize = absoluteItemPath . size ( ) - pathSize ;
// write out rules
conf . deployment . AdditionalFiles + = iterator . fileName ( )
+ " | " + absoluteItemPath
+ " | " + itemDevicePath + ( diffSize ? ( absoluteItemPath . right ( diffSize ) ) : QLatin1String ( " " ) )
+ " |0; " ;
}
2013-02-11 23:25:23 +00:00
}
2011-04-27 10:05:43 +00:00
}
}
2014-02-11 11:49:18 +00:00
void VcprojGenerator : : initWinDeployQtTool ( )
{
VCConfiguration & conf = vcProject . Configuration ;
conf . windeployqt . ExcludedFromBuild = true ;
if ( project - > isActiveConfig ( " windeployqt " ) ) {
conf . windeployqt . Record = QStringLiteral ( " $(TargetName).windeployqt.$(Platform).$(Configuration) " ) ;
2015-03-27 14:56:37 +00:00
const QString commandLine = MakefileGenerator : : shellQuote ( QDir : : toNativeSeparators ( project - > first ( " QMAKE_WINDEPLOYQT " ) . toQString ( ) ) )
+ QLatin1Char ( ' ' ) + project - > values ( " WINDEPLOYQT_OPTIONS " ) . join ( QLatin1Char ( ' ' ) ) ;
// Visual Studio copies all files to be deployed into the MSIL directory
// and then invokes MDILXapCompile on it, which checks for managed code and
// translates it into native code. The problem is that all entries of the
// package will be copied into the MSIL directly, losing the subdirectory
// structure (for instance for plugins). However, the MDILXapCompile call
// itself contains the original subdirectories as parameters and hence the
// call fails.
2016-11-22 13:54:02 +00:00
// Hence the only way to get a build done is to recreate the directory
// structure manually by invoking windeployqt a second time, so that
// the MDILXapCompile call succeeds and deployment continues.
2015-03-27 14:56:37 +00:00
conf . windeployqt . CommandLine + = commandLine
2019-02-21 08:58:29 +00:00
+ QStringLiteral ( " -list relative -dir \" $(MSBuildProjectDirectory) \" \" $(OutDir) \\ $(TargetFileName) \" > " )
2014-02-11 11:49:18 +00:00
+ MakefileGenerator : : shellQuote ( conf . windeployqt . Record ) ;
conf . windeployqt . config = & vcProject . Configuration ;
conf . windeployqt . ExcludedFromBuild = false ;
}
}
2011-04-27 10:05:43 +00:00
void VcprojGenerator : : initPreLinkEventTools ( )
{
VCConfiguration & conf = vcProject . Configuration ;
if ( ! project - > values ( " QMAKE_PRE_LINK " ) . isEmpty ( ) ) {
QStringList cmdline = VCToolBase : : fixCommandLine ( var ( " QMAKE_PRE_LINK " ) ) ;
conf . preLink . CommandLine = cmdline ;
conf . preLink . Description = cmdline . join ( QLatin1String ( " \r \n " ) ) ;
conf . preLink . ExcludedFromBuild = _False ;
}
}
void VcprojGenerator : : initRootFiles ( )
{
// Note: Root files do _not_ have any filter name, filter nor GUID!
vcProject . RootFiles . addFiles ( project - > values ( " RC_FILE " ) ) ;
vcProject . RootFiles . Project = this ;
vcProject . RootFiles . Config = & ( vcProject . Configuration ) ;
}
void VcprojGenerator : : initSourceFiles ( )
{
vcProject . SourceFiles . Name = " Source Files " ;
vcProject . SourceFiles . Filter = " cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx " ;
vcProject . SourceFiles . Guid = _GUIDSourceFiles ;
vcProject . SourceFiles . addFiles ( project - > values ( " SOURCES " ) ) ;
vcProject . SourceFiles . Project = this ;
vcProject . SourceFiles . Config = & ( vcProject . Configuration ) ;
}
void VcprojGenerator : : initHeaderFiles ( )
{
vcProject . HeaderFiles . Name = " Header Files " ;
vcProject . HeaderFiles . Filter = " h;hpp;hxx;hm;inl;inc;xsd " ;
vcProject . HeaderFiles . Guid = _GUIDHeaderFiles ;
vcProject . HeaderFiles . addFiles ( project - > values ( " HEADERS " ) ) ;
if ( usePCH ) // Generated PCH cpp file
vcProject . HeaderFiles . addFile ( precompH ) ;
vcProject . HeaderFiles . Project = this ;
vcProject . HeaderFiles . Config = & ( vcProject . Configuration ) ;
// vcProject.HeaderFiles.CustomBuild = mocHdr;
// addMocArguments(vcProject.HeaderFiles);
}
void VcprojGenerator : : initGeneratedFiles ( )
{
vcProject . GeneratedFiles . Name = " Generated Files " ;
vcProject . GeneratedFiles . Filter = " cpp;c;cxx;moc;h;def;odl;idl;res; " ;
vcProject . GeneratedFiles . Guid = _GUIDGeneratedFiles ;
// ### These cannot have CustomBuild (mocSrc)!!
vcProject . GeneratedFiles . addFiles ( project - > values ( " GENERATED_SOURCES " ) ) ;
vcProject . GeneratedFiles . addFiles ( project - > values ( " GENERATED_FILES " ) ) ;
vcProject . GeneratedFiles . addFiles ( project - > values ( " IDLSOURCES " ) ) ;
2013-07-02 12:44:53 +00:00
if ( project - > values ( " RC_FILE " ) . isEmpty ( ) )
vcProject . GeneratedFiles . addFiles ( project - > values ( " RES_FILE " ) ) ;
2011-04-27 10:05:43 +00:00
if ( ! extraCompilerOutputs . isEmpty ( ) )
vcProject . GeneratedFiles . addFiles ( extraCompilerOutputs . keys ( ) ) ;
vcProject . GeneratedFiles . Project = this ;
vcProject . GeneratedFiles . Config = & ( vcProject . Configuration ) ;
// vcProject.GeneratedFiles.CustomBuild = mocSrc;
}
void VcprojGenerator : : initLexYaccFiles ( )
{
vcProject . LexYaccFiles . Name = " Lex / Yacc Files " ;
vcProject . LexYaccFiles . ParseFiles = _False ;
vcProject . LexYaccFiles . Filter = " l;y " ;
vcProject . LexYaccFiles . Guid = _GUIDLexYaccFiles ;
vcProject . LexYaccFiles . addFiles ( project - > values ( " LEXSOURCES " ) ) ;
vcProject . LexYaccFiles . addFiles ( project - > values ( " YACCSOURCES " ) ) ;
vcProject . LexYaccFiles . Project = this ;
vcProject . LexYaccFiles . Config = & ( vcProject . Configuration ) ;
}
void VcprojGenerator : : initTranslationFiles ( )
{
vcProject . TranslationFiles . Name = " Translation Files " ;
vcProject . TranslationFiles . ParseFiles = _False ;
vcProject . TranslationFiles . Filter = " ts;xlf " ;
vcProject . TranslationFiles . Guid = _GUIDTranslationFiles ;
vcProject . TranslationFiles . addFiles ( project - > values ( " TRANSLATIONS " ) ) ;
2019-02-25 13:56:53 +00:00
vcProject . TranslationFiles . addFiles ( project - > values ( " EXTRA_TRANSLATIONS " ) ) ;
2011-04-27 10:05:43 +00:00
vcProject . TranslationFiles . Project = this ;
vcProject . TranslationFiles . Config = & ( vcProject . Configuration ) ;
}
void VcprojGenerator : : initFormFiles ( )
{
vcProject . FormFiles . Name = " Form Files " ;
vcProject . FormFiles . ParseFiles = _False ;
vcProject . FormFiles . Filter = " ui " ;
vcProject . FormFiles . Guid = _GUIDFormFiles ;
vcProject . FormFiles . addFiles ( project - > values ( " FORMS " ) ) ;
vcProject . FormFiles . Project = this ;
vcProject . FormFiles . Config = & ( vcProject . Configuration ) ;
}
void VcprojGenerator : : initResourceFiles ( )
{
vcProject . ResourceFiles . Name = " Resource Files " ;
vcProject . ResourceFiles . ParseFiles = _False ;
vcProject . ResourceFiles . Filter = " qrc;* " ; //"rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;ts;xlf;qrc";
vcProject . ResourceFiles . Guid = _GUIDResourceFiles ;
// Bad hack, please look away -------------------------------------
2012-05-18 18:00:23 +00:00
QString rcc_dep_cmd = project - > values ( " rcc.depend_command " ) . join ( ' ' ) ;
2011-04-27 10:05:43 +00:00
if ( ! rcc_dep_cmd . isEmpty ( ) ) {
2020-01-02 13:16:21 +00:00
const QStringList qrc_files = project - > values ( " RESOURCES " ) . toQStringList ( ) ;
2011-04-27 10:05:43 +00:00
QStringList deps ;
2020-01-02 13:16:21 +00:00
for ( const QString & qrc_file : qrc_files ) {
callExtraCompilerDependCommand ( " rcc " ,
rcc_dep_cmd ,
qrc_file ,
QString ( ) ,
true , // dep_lines
& deps ,
false , // existingDepsOnly
true // checkCommandavailability
) ;
2011-04-27 10:05:43 +00:00
}
2020-01-02 13:16:21 +00:00
vcProject . ResourceFiles . addFiles ( deps ) ;
2011-04-27 10:05:43 +00:00
}
// You may look again --------------------------------------------
vcProject . ResourceFiles . addFiles ( project - > values ( " RESOURCES " ) ) ;
vcProject . ResourceFiles . Project = this ;
vcProject . ResourceFiles . Config = & ( vcProject . Configuration ) ;
}
2015-03-20 09:58:02 +00:00
void VcprojGenerator : : initDistributionFiles ( )
{
vcProject . DistributionFiles . Name = " Distribution Files " ;
vcProject . DistributionFiles . ParseFiles = _False ;
vcProject . DistributionFiles . Filter = " * " ;
vcProject . DistributionFiles . Guid = _GUIDDistributionFiles ;
vcProject . DistributionFiles . addFiles ( project - > values ( " DISTFILES " ) ) ;
vcProject . DistributionFiles . Project = this ;
vcProject . DistributionFiles . Config = & ( vcProject . Configuration ) ;
}
2019-05-31 08:22:44 +00:00
QString VcprojGenerator : : extraCompilerName ( const ProString & extraCompiler ,
const QStringList & inputs ,
const QStringList & outputs )
{
QString name = project - > values ( ProKey ( extraCompiler + " .name " ) ) . join ( ' ' ) ;
if ( name . isEmpty ( ) )
name = extraCompiler . toQString ( ) ;
else
name = replaceExtraCompilerVariables ( name , inputs , outputs , NoShell ) ;
return name ;
}
2011-04-27 10:05:43 +00:00
void VcprojGenerator : : initExtraCompilerOutputs ( )
{
2012-09-06 10:21:38 +00:00
ProStringList otherFilters ;
2011-04-27 10:05:43 +00:00
otherFilters < < " FORMS "
< < " GENERATED_FILES "
< < " GENERATED_SOURCES "
< < " HEADERS "
< < " IDLSOURCES "
< < " LEXSOURCES "
< < " RC_FILE "
< < " RESOURCES "
< < " RES_FILE "
< < " SOURCES "
< < " TRANSLATIONS "
< < " YACCSOURCES " ;
2012-09-06 10:21:38 +00:00
const ProStringList & quc = project - > values ( " QMAKE_EXTRA_COMPILERS " ) ;
for ( ProStringList : : ConstIterator it = quc . begin ( ) ; it ! = quc . end ( ) ; + + it ) {
2019-05-31 08:22:44 +00:00
const ProStringList & inputVars = project - > values ( ProKey ( * it + " .input " ) ) ;
ProStringList inputFiles ;
for ( auto var : inputVars )
inputFiles . append ( project - > values ( var . toKey ( ) ) ) ;
const ProStringList & outputs = project - > values ( ProKey ( * it + " .output " ) ) ;
2011-04-27 10:05:43 +00:00
// Create an extra compiler filter and add the files
VCFilter extraCompile ;
2019-05-31 08:22:44 +00:00
extraCompile . Name = extraCompilerName ( it - > toQString ( ) , inputFiles . toQStringList ( ) ,
outputs . toQStringList ( ) ) ;
2011-04-27 10:05:43 +00:00
extraCompile . ParseFiles = _False ;
extraCompile . Filter = " " ;
extraCompile . Guid = QString ( _GUIDExtraCompilerFiles ) + " - " + ( * it ) ;
2015-04-21 13:43:29 +00:00
bool addOnInput = hasBuiltinCompiler ( firstExpandedOutputFileName ( * it ) ) ;
2011-04-27 10:05:43 +00:00
if ( ! addOnInput ) {
2019-01-30 12:44:54 +00:00
// If the extra compiler has a variable_out set that is already handled
// some other place, ignore it.
const ProString & outputVar = project - > first ( ProKey ( * it + " .variable_out " ) ) ;
if ( ! outputVar . isEmpty ( ) & & otherFilters . contains ( outputVar ) )
continue ;
2019-10-14 08:58:29 +00:00
QString tmp_out ;
if ( ! outputs . isEmpty ( ) )
2020-10-28 08:55:34 +00:00
tmp_out = outputs . first ( ) . toQString ( ) ;
2012-09-06 10:21:38 +00:00
if ( project - > values ( ProKey ( * it + " .CONFIG " ) ) . indexOf ( " combine " ) ! = - 1 ) {
2021-10-18 13:09:46 +00:00
// Combined output, only one file result. Use .cbt file.
2014-11-20 15:20:16 +00:00
extraCompile . addFile ( Option : : fixPathToTargetOS (
2021-10-18 13:09:46 +00:00
replaceExtraCompilerVariables ( tmp_out + customBuildToolFilterFileSuffix ,
QString ( ) , QString ( ) , NoShell ) , false ) ) ;
2019-10-14 08:58:29 +00:00
} else if ( ! inputVars . isEmpty ( ) ) {
2011-04-27 10:05:43 +00:00
// One output file per input
2019-05-31 08:22:44 +00:00
const ProStringList & tmp_in = project - > values ( inputVars . first ( ) . toKey ( ) ) ;
2011-04-27 10:05:43 +00:00
for ( int i = 0 ; i < tmp_in . count ( ) ; + + i ) {
2012-09-06 10:21:38 +00:00
const QString & filename = tmp_in . at ( i ) . toQString ( ) ;
2019-02-25 13:58:28 +00:00
if ( extraCompilerSources . contains ( filename ) & & ! otherFiltersContain ( filename ) )
2014-11-20 15:20:16 +00:00
extraCompile . addFile ( Option : : fixPathToTargetOS (
replaceExtraCompilerVariables ( filename , tmp_out , QString ( ) , NoShell ) , false ) ) ;
2011-04-27 10:05:43 +00:00
}
}
} else {
// In this case we the outputs have a built-in compiler, so we cannot add the custom
// build steps there. So, we turn it around and add it to the input files instead,
// provided that the input file variable is not handled already (those in otherFilters
// are handled, so we avoid them).
2016-01-26 13:38:54 +00:00
for ( const ProString & inputVar : inputVars ) {
2011-04-27 10:05:43 +00:00
if ( ! otherFilters . contains ( inputVar ) ) {
2012-09-06 10:21:38 +00:00
const ProStringList & tmp_in = project - > values ( inputVar . toKey ( ) ) ;
2011-04-27 10:05:43 +00:00
for ( int i = 0 ; i < tmp_in . count ( ) ; + + i ) {
2012-09-06 10:21:38 +00:00
const QString & filename = tmp_in . at ( i ) . toQString ( ) ;
2019-02-25 13:58:28 +00:00
if ( extraCompilerSources . contains ( filename ) & & ! otherFiltersContain ( filename ) )
2014-11-20 15:20:16 +00:00
extraCompile . addFile ( Option : : fixPathToTargetOS (
replaceExtraCompilerVariables ( filename , QString ( ) , QString ( ) , NoShell ) , false ) ) ;
2011-04-27 10:05:43 +00:00
}
}
}
}
extraCompile . Project = this ;
extraCompile . Config = & ( vcProject . Configuration ) ;
vcProject . ExtraCompilersFiles . append ( extraCompile ) ;
}
}
2019-02-25 13:58:28 +00:00
bool VcprojGenerator : : otherFiltersContain ( const QString & fileName ) const
{
auto filterFileMatches = [ & fileName ] ( const VCFilterFile & ff )
{
return ff . file = = fileName ;
} ;
for ( const VCFilter * filter : { & vcProject . RootFiles ,
& vcProject . SourceFiles ,
& vcProject . HeaderFiles ,
& vcProject . GeneratedFiles ,
& vcProject . LexYaccFiles ,
& vcProject . TranslationFiles ,
& vcProject . FormFiles ,
& vcProject . ResourceFiles ,
& vcProject . DeploymentFiles ,
& vcProject . DistributionFiles } ) {
if ( std : : any_of ( filter - > Files . cbegin ( ) , filter - > Files . cend ( ) , filterFileMatches ) )
return true ;
}
return false ;
}
2011-04-27 10:05:43 +00:00
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
VCProjectWriter * VcprojGenerator : : createProjectWriter ( )
{
return new VCProjectWriter ;
}
2014-11-20 15:20:16 +00:00
QString VcprojGenerator : : replaceExtraCompilerVariables (
const QString & var , const QStringList & in , const QStringList & out , ReplaceFor forShell )
2011-04-27 10:05:43 +00:00
{
2014-11-20 15:20:16 +00:00
QString ret = MakefileGenerator : : replaceExtraCompilerVariables ( var , in , out , forShell ) ;
2011-04-27 10:05:43 +00:00
2012-09-06 10:21:38 +00:00
ProStringList & defines = project - > values ( " VCPROJ_MAKEFILE_DEFINES " ) ;
2011-04-27 10:05:43 +00:00
if ( defines . isEmpty ( ) )
defines . append ( varGlue ( " PRL_EXPORT_DEFINES " , " -D " , " -D " , " " ) +
varGlue ( " DEFINES " , " -D " , " -D " , " " ) ) ;
2016-02-04 14:12:03 +00:00
ret . replace ( QLatin1String ( " $(DEFINES) " ) , defines . first ( ) . toQString ( ) ) ;
2011-04-27 10:05:43 +00:00
2012-09-06 10:21:38 +00:00
ProStringList & incpath = project - > values ( " VCPROJ_MAKEFILE_INCPATH " ) ;
2011-04-27 10:05:43 +00:00
if ( incpath . isEmpty ( ) & & ! this - > var ( " MSVCPROJ_INCPATH " ) . isEmpty ( ) )
incpath . append ( this - > var ( " MSVCPROJ_INCPATH " ) ) ;
2016-02-04 14:12:03 +00:00
ret . replace ( QLatin1String ( " $(INCPATH) " ) , incpath . join ( ' ' ) ) ;
2011-04-27 10:05:43 +00:00
return ret ;
}
bool VcprojGenerator : : openOutput ( QFile & file , const QString & /*build*/ ) const
{
2018-07-17 13:11:07 +00:00
ProString fileName = file . fileName ( ) ;
ProString extension = project - > first ( " TEMPLATE " ) = = " vcsubdirs "
? project - > first ( " VCSOLUTION_EXTENSION " ) : project - > first ( " VCPROJ_EXTENSION " ) ;
if ( ! fileName . endsWith ( extension ) ) {
if ( fileName . isEmpty ( ) ) {
fileName = ! project - > first ( " MAKEFILE " ) . isEmpty ( )
? project - > first ( " MAKEFILE " ) : project - > first ( " TARGET " ) ;
}
file . setFileName ( fileName + extension ) ;
2011-04-27 10:05:43 +00:00
}
return Win32MakefileGenerator : : openOutput ( file , QString ( ) ) ;
}
QT_END_NAMESPACE