/**************************************************************************** ** ** 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; using System.IO; namespace QtVsTools.Core { public class QMakeConf { public Hashtable Entries { get; private set; } public string QMakeSpecDirectory { get; private set; } public QMakeConf(VersionInformation versionInfo, QMakeQuery qmakeQuery = null) { Entries = new Hashtable(); QMakeSpecDirectory = Path.Combine(versionInfo.qtDir, "mkspecs", "default"); var qmakeConf = Path.Combine(QMakeSpecDirectory, "qmake.conf"); // Starting from Qt5 beta2 there is no more "\\mkspecs\\default" folder available // To find location of "qmake.conf" there is a need to run "qmake -query" command // This is what happens below. if (!File.Exists(qmakeConf)) { if (qmakeQuery == null) qmakeQuery = new QMakeQuery(versionInfo); string qtPrefix = qmakeQuery["QT_INSTALL_PREFIX"]; if (string.IsNullOrEmpty(qtPrefix)) throw new QtVSException("qmake error: no value for QT_INSTALL_PREFIX"); string qtArchData = qmakeQuery["QT_INSTALL_ARCHDATA"]; if (string.IsNullOrEmpty(qtArchData)) throw new QtVSException("qmake error: no value for QT_INSTALL_ARCHDATA"); string qmakeXSpec = qmakeQuery["QMAKE_XSPEC"]; if (string.IsNullOrEmpty(qtArchData)) throw new QtVSException("qmake error: no value for QMAKE_XSPEC"); qmakeConf = Path.Combine(qtPrefix, qtArchData, "mkspecs", qmakeXSpec, "qmake.conf"); if (!File.Exists(qmakeConf)) throw new QtVSException("qmake.conf expected at " + qmakeConf + " not found"); } ParseFile(qmakeConf); } private void ParseFile(string filename) { var fileInfo = new FileInfo(filename); if (fileInfo.Exists) { var streamReader = new StreamReader(filename); var line = streamReader.ReadLine(); while (line != null) { line = line.Trim(); var commentStartIndex = line.IndexOf('#'); if (commentStartIndex >= 0) line = line.Remove(commentStartIndex); var pos = line.IndexOf('='); if (pos > 0) { var op = "="; if (line[pos - 1] == '+' || line[pos - 1] == '-') op = line[pos - 1] + "="; var lineKey = line.Substring(0, pos - op.Length + 1).Trim(); var lineValue = ExpandVariables(line.Substring(pos + 1).Trim()); if (op == "+=") { Entries[lineKey] += " " + lineValue; } else if (op == "-=") { foreach (var remval in lineValue.Split(' ', '\t')) RemoveValue(lineKey, remval); } else { Entries[lineKey] = lineValue; } } else if (line.StartsWith("include", StringComparison.Ordinal)) { pos = line.IndexOf('('); var posEnd = line.LastIndexOf(')'); if (pos > 0 && pos < posEnd) { var filenameToInclude = line.Substring(pos + 1, posEnd - pos - 1); var saveCurrentDir = Environment.CurrentDirectory; Environment.CurrentDirectory = fileInfo.Directory.FullName; var fileInfoToInclude = new FileInfo(filenameToInclude); if (fileInfoToInclude.Exists) ParseFile(fileInfoToInclude.FullName); Environment.CurrentDirectory = saveCurrentDir; } } line = streamReader.ReadLine(); } streamReader.Close(); RemoveValue("QMAKE_LFLAGS_CONSOLE", "@QMAKE_SUBSYSTEM_SUFFIX@"); RemoveValue("QMAKE_LFLAGS_WINDOWS", "@QMAKE_SUBSYSTEM_SUFFIX@"); } } private string ExpandVariables(string value) { var pos = value.IndexOf("$$", StringComparison.Ordinal); while (pos != -1) { var startPos = pos + 2; var endPos = startPos; if (value[startPos] != '[') { // at the moment no handling of qmake internal variables for (; endPos < value.Length; ++endPos) { if ((Char.IsPunctuation(value[endPos]) && value[endPos] != '_') || Char.IsWhiteSpace(value[endPos])) { break; } } if (endPos > startPos) { var varName = value.Substring(startPos, endPos - startPos); var varValue = (Entries[varName] ?? string.Empty).ToString(); value = value.Substring(0, pos) + varValue + value.Substring(endPos); endPos = pos + varValue.Length; } } pos = value.IndexOf("$$", endPos, StringComparison.Ordinal); } return value; } private void RemoveValue(string key, string valueToRemove) { var pos = -1; if (!Entries.Contains(key)) return; var value = Entries[key].ToString(); do { pos = value.IndexOf(valueToRemove, StringComparison.Ordinal); if (pos >= 0) value = value.Remove(pos, valueToRemove.Length); } while (pos >= 0); Entries[key] = value; } } }