/**************************************************************************** ** ** 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 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(); } 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 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 { { "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); } } } } }