| /****************************************************************************  | 
| **  | 
| ** Copyright (C) 2016 The Qt Company Ltd.  | 
| ** Contact: https://www.qt.io/licensing/  | 
| **  | 
| ** This file is part of the Qt VS Tools.  | 
| **  | 
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$  | 
| ** 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  | 
| ** a written agreement between you and The Qt Company. For licensing terms  | 
| ** and conditions see https://www.qt.io/terms-conditions. For further  | 
| ** information use the contact form at https://www.qt.io/contact-us.  | 
| **  | 
| ** 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.  | 
| **  | 
| ** $QT_END_LICENSE$  | 
| **  | 
| ****************************************************************************/  | 
|   | 
| using System;  | 
| using System.Collections.Generic;  | 
| using System.Diagnostics;  | 
| using System.IO;  | 
| using System.Linq;  | 
| using System.Text;  | 
|   | 
| namespace QtVsTools.Core  | 
| {  | 
|     using VisualStudio;  | 
|   | 
|     public abstract class QMake  | 
|     {  | 
|         public Dictionary<string, string> Vars { get; protected set; }  | 
|         public string OutputFile { get; protected set; }  | 
|         private uint DebugLevel { get; set; }  | 
|         public string TemplatePrefix { get; protected set; }  | 
|         public bool Recursive { get; protected set; }  | 
|         public string ProFile { get; protected set; }  | 
|         public string Query { get; protected set; }  | 
|         public bool DisableWarnings { get; set; }  | 
|   | 
|         protected VersionInformation QtVersion { get; }  | 
|         private EnvDTE.DTE Dte { get; }  | 
|   | 
|         public QMake(VersionInformation qtVersion, EnvDTE.DTE dte = null)  | 
|         {  | 
|             Debug.Assert(qtVersion != null);  | 
|             QtVersion = qtVersion;  | 
|             Dte = dte ?? VsServiceProvider.GetService<EnvDTE.DTE>();  | 
|         }  | 
|   | 
|         protected virtual string QMakeExe  | 
|         {  | 
|             get  | 
|             {  | 
|                 var qmakePath = Path.Combine(QtVersion.qtDir, "bin", "qmake.exe");  | 
|                 if (!File.Exists(qmakePath))  | 
|                     qmakePath = Path.Combine(QtVersion.qtDir, "qmake.exe");  | 
|                 return qmakePath;  | 
|             }  | 
|         }  | 
|   | 
|         protected virtual string WorkingDirectory  | 
|         {  | 
|             get  | 
|             {  | 
|                 return Path.GetDirectoryName(ProFile);  | 
|             }  | 
|         }  | 
|   | 
|         string MakeRelative(string absolutePath)  | 
|         {  | 
|             var workDir = new Uri(Path.GetDirectoryName(ProFile) + Path.DirectorySeparatorChar);  | 
|             var path = new Uri(absolutePath);  | 
|             if (workDir.IsBaseOf(path)) {  | 
|                 return workDir.MakeRelativeUri(path).OriginalString  | 
|                     .Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);  | 
|             } else {  | 
|                 return absolutePath;  | 
|             }  | 
|         }  | 
|   | 
|         protected virtual string QMakeArgs  | 
|         {  | 
|             get  | 
|             {  | 
|                 var args = new StringBuilder();  | 
|                 if (Vars != null) {  | 
|                     foreach (KeyValuePair<string, string> v in Vars) {  | 
|                         args.AppendFormat(" {0}={1}", v.Key, v.Value);  | 
|                     }  | 
|                 }  | 
|   | 
|                 if (!string.IsNullOrEmpty(OutputFile))  | 
|                     args.AppendFormat(" -o \"{0}\"", MakeRelative(OutputFile));  | 
|   | 
|                 for (int i = 0; i < DebugLevel; ++i)  | 
|                     args.Append(" -d");  | 
|   | 
|                 if (!string.IsNullOrEmpty(TemplatePrefix))  | 
|                     args.AppendFormat(" -tp {0}", TemplatePrefix);  | 
|   | 
|                 if (Recursive)  | 
|                     args.Append(" -recursive");  | 
|   | 
|                 if (DisableWarnings)  | 
|                     args.Append(" -Wnone");  | 
|   | 
|                 if (!string.IsNullOrEmpty(ProFile))  | 
|                     args.AppendFormat(" \"{0}\"", MakeRelative(ProFile));  | 
|   | 
|                 if (!string.IsNullOrEmpty(Query))  | 
|                     args.AppendFormat(" -query {0}", Query);  | 
|   | 
|                 return args.ToString();  | 
|             }  | 
|         }  | 
|   | 
|         protected virtual Process CreateProcess()  | 
|         {  | 
|             var qmakeStartInfo = new ProcessStartInfo  | 
|             {  | 
|                 CreateNoWindow = true,  | 
|                 UseShellExecute = false,  | 
|                 RedirectStandardError = true,  | 
|                 RedirectStandardOutput = true,  | 
|                 FileName = QMakeExe,  | 
|                 Arguments = QMakeArgs,  | 
|                 WorkingDirectory = WorkingDirectory,  | 
|             };  | 
|             qmakeStartInfo.EnvironmentVariables["QTDIR"] = QtVersion.qtDir;  | 
|   | 
|             var qmakeProc = new Process  | 
|             {  | 
|                 StartInfo = qmakeStartInfo,  | 
|             };  | 
|             qmakeProc.OutputDataReceived += (sender, ev) => OutMsg(ev.Data);  | 
|             qmakeProc.ErrorDataReceived += (sender, ev) => ErrMsg(ev.Data);  | 
|   | 
|             return qmakeProc;  | 
|         }  | 
|   | 
|         protected virtual void OutMsg(string msg)  | 
|         {  | 
|             if (Dte != null && !string.IsNullOrEmpty(msg))  | 
|                 Messages.Print(msg);  | 
|         }  | 
|   | 
|         protected virtual void ErrMsg(string msg)  | 
|         {  | 
|             if (Dte != null && !string.IsNullOrEmpty(msg))  | 
|                 Messages.Print(msg);  | 
|         }  | 
|   | 
|         protected virtual void InfoMsg(string msg)  | 
|         {  | 
|             if (Dte != null && !string.IsNullOrEmpty(msg))  | 
|                 Messages.Print(msg);  | 
|         }  | 
|   | 
|         protected virtual void InfoStart(Process qmakeProc)  | 
|         {  | 
|             InfoMsg(string.Format("--- qmake({0}): started {1}",  | 
|                 qmakeProc.Id, qmakeProc.StartInfo.FileName));  | 
|         }  | 
|   | 
|         protected virtual void InfoExit(Process qmakeProc)  | 
|         {  | 
|             InfoMsg(string.Format("--- qmake({0}): exit code {1} ({2:0.##} msecs)\r\n",  | 
|                 qmakeProc.Id, qmakeProc.ExitCode,  | 
|                 (qmakeProc.ExitTime - qmakeProc.StartTime).TotalMilliseconds));  | 
|         }  | 
|   | 
|         public virtual int Run(bool setVCVars = false)  | 
|         {  | 
|             int exitCode = -1;  | 
|             using (var qmakeProc = CreateProcess()) {  | 
|                 try {  | 
|                     if (setVCVars  | 
|                         && !HelperFunctions.SetVCVars(QtVersion, qmakeProc.StartInfo)) {  | 
|                         OutMsg("Error setting VC vars");  | 
|                     }  | 
|                     if (qmakeProc.Start()) {  | 
|                         InfoStart(qmakeProc);  | 
|                         qmakeProc.BeginOutputReadLine();  | 
|                         qmakeProc.BeginErrorReadLine();  | 
|                         qmakeProc.WaitForExit();  | 
|                         exitCode = qmakeProc.ExitCode;  | 
|                         InfoExit(qmakeProc);  | 
|                     }  | 
|                 } catch (Exception exception) {  | 
|                     exception.Log();  | 
|                 }  | 
|             }  | 
|             return exitCode;  | 
|         }  | 
|   | 
|         public static bool Exists(string path)  | 
|         {  | 
|             var possibleQMakePaths = new[] {  | 
|                 // Path points to qmake.exe  | 
|                 path,  | 
|                 // Path points to folder containing qmake.exe  | 
|                 Path.Combine(path, "qmake.exe"),  | 
|                 // Path points to folder containing bin\qmake.exe  | 
|                 Path.Combine(path, "bin", "qmake.exe"),  | 
|             };  | 
|             return possibleQMakePaths.Where(p => File.Exists(p)  | 
|                 && Path.GetFileName(p).Equals("qmake.exe", StringComparison.OrdinalIgnoreCase))  | 
|                 .Any();  | 
|         }  | 
|     }  | 
|   | 
|     public class QMakeImport : QMake  | 
|     {  | 
|         public QMakeImport(  | 
|             VersionInformation qtVersion,  | 
|             string proFilePath,  | 
|             bool recursiveRun = false,  | 
|             EnvDTE.DTE dte = null)  | 
|         : base(qtVersion, dte)  | 
|         {  | 
|             ProFile = proFilePath;  | 
|             TemplatePrefix = "vc";  | 
|             if (recursiveRun)  | 
|                 Recursive = true;  | 
|             else  | 
|                 OutputFile = Path.ChangeExtension(proFilePath, ".vcxproj");  | 
|             Vars = new Dictionary<string, string>  | 
|             {  | 
|                 { "QMAKE_INCDIR_QT", @"$(QTDIR)\include" },  | 
|                 { "QMAKE_LIBDIR", @"$(QTDIR)\lib" },  | 
|                 { "QMAKE_MOC", @"$(QTDIR)\bin\moc.exe" },  | 
|                 { "QMAKE_QMAKE", @"$(QTDIR)\bin\qmake.exe" },  | 
|             };  | 
|         }  | 
|   | 
|         protected override void InfoStart(Process qmakeProc)  | 
|         {  | 
|             base.InfoStart(qmakeProc);  | 
|             InfoMsg("--- qmake: Working Directory: " + qmakeProc.StartInfo.WorkingDirectory);  | 
|             InfoMsg("--- qmake: Arguments: " + qmakeProc.StartInfo.Arguments);  | 
|             if (qmakeProc.StartInfo.EnvironmentVariables.ContainsKey("QMAKESPEC")) {  | 
|                 var qmakeSpec = qmakeProc.StartInfo.EnvironmentVariables["QMAKESPEC"];  | 
|                 if (qmakeSpec != QtVersion.QMakeSpecDirectory) {  | 
|                     InfoMsg("--- qmake: Environment "  | 
|                         + "variable QMAKESPEC overwriting Qt version QMAKESPEC.");  | 
|                     InfoMsg("--- qmake: Qt version "  | 
|                         + "QMAKESPEC: " + QtVersion.QMakeSpecDirectory);  | 
|                     InfoMsg("--- qmake: Environment "  | 
|                         + "variable QMAKESPEC: " + qmakeSpec);  | 
|                 }  | 
|             }  | 
|         }  | 
|     }  | 
| }  |