1 /*
2   paths.cpp
3 
4   This file is part of GammaRay, the Qt application inspection and
5   manipulation tool.
6 
7   Copyright (C) 2013-2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
8   Author: Volker Krause <volker.krause@kdab.com>
9 
10   Licensees holding valid commercial KDAB GammaRay licenses may use this file in
11   accordance with GammaRay Commercial License Agreement provided with the Software.
12 
13   Contact info@kdab.com if any conditions of this licensing are not clear to you.
14 
15   This program is free software; you can redistribute it and/or modify
16   it under the terms of the GNU General Public License as published by
17   the Free Software Foundation, either version 2 of the License, or
18   (at your option) any later version.
19 
20   This program is distributed in the hope that it will be useful,
21   but WITHOUT ANY WARRANTY; without even the implied warranty of
22   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23   GNU General Public License for more details.
24 
25   You should have received a copy of the GNU General Public License
26   along with this program.  If not, see <http://www.gnu.org/licenses/>.
27 */
28 
29 #include <config-gammaray.h>
30 #include "paths.h"
31 #include "selflocator.h"
32 
33 #include <QCoreApplication>
34 #include <QDebug>
35 #include <QDir>
36 #include <QFileInfo>
37 #include <QLibraryInfo>
38 #include <QMutex>
39 
40 namespace GammaRay {
41 
42 struct PathData
43 {
44     QString rootPath;
45     QMutex mutex; // rootPath is set from the probe setting receiver thread
46 };
47 
48 Q_GLOBAL_STATIC(PathData, s_pathData)
49 
50 namespace Paths {
51 
rootPath()52 QString rootPath()
53 {
54     QMutexLocker locker(&s_pathData()->mutex);
55     if (s_pathData()->rootPath.isEmpty()) {
56         QFileInfo fi(SelfLocator::findMe());
57         fi.setFile(fi.absolutePath() + QLatin1String("/" GAMMARAY_INVERSE_LIB_DIR));
58         if (fi.isDir())
59             s_pathData()->rootPath = fi.absoluteFilePath();
60     }
61     Q_ASSERT(!s_pathData()->rootPath.isEmpty());
62     return s_pathData()->rootPath;
63 }
64 
setRootPath(const QString & rootPath)65 void setRootPath(const QString &rootPath)
66 {
67     Q_ASSERT(!rootPath.isEmpty());
68     Q_ASSERT(QDir(rootPath).exists());
69     Q_ASSERT(QDir(rootPath).isAbsolute());
70 
71     QMutexLocker locker(&s_pathData()->mutex);
72     s_pathData()->rootPath = rootPath;
73 }
74 
setRelativeRootPath(const char * relativeRootPath)75 void setRelativeRootPath(const char *relativeRootPath)
76 {
77     Q_ASSERT(relativeRootPath);
78     setRootPath(QCoreApplication::applicationDirPath() + QDir::separator()
79                 + QLatin1String(relativeRootPath));
80 }
81 
probePath(const QString & probeABI,const QString & rootPath)82 QString probePath(const QString &probeABI, const QString &rootPath)
83 {
84 #ifndef GAMMARAY_INSTALL_QT_LAYOUT
85     return rootPath + QDir::separator()
86            + QLatin1String(GAMMARAY_PLUGIN_INSTALL_DIR) + QDir::separator()
87            + QLatin1String(GAMMARAY_PLUGIN_VERSION) + QDir::separator()
88            + probeABI;
89 #else
90     Q_UNUSED(probeABI);
91     return rootPath + QDir::separator() + QLatin1String(GAMMARAY_PROBE_INSTALL_DIR);
92 #endif
93 }
94 
binPath()95 QString binPath()
96 {
97     return rootPath() + QDir::separator() + QLatin1String(GAMMARAY_BIN_INSTALL_DIR);
98 }
99 
libexecPath()100 QString libexecPath()
101 {
102     return rootPath() + QDir::separator() + QLatin1String(GAMMARAY_LIBEXEC_INSTALL_DIR);
103 }
104 
currentProbePath()105 QString currentProbePath()
106 {
107     return probePath(QStringLiteral(GAMMARAY_PROBE_ABI));
108 }
109 
addPluginPath(QStringList & list,const QString & path)110 static void addPluginPath(QStringList &list, const QString &path)
111 {
112     QFileInfo fi(path);
113     if (!fi.isDir())
114         return;
115     list.push_back(fi.canonicalFilePath());
116 }
117 
pluginPaths(const QString & probeABI)118 QStringList pluginPaths(const QString &probeABI)
119 {
120     QStringList l;
121     // TODO based on environment variable for custom plugins
122 
123     // based on rootPath()
124     addPluginPath(l, rootPath() + QLatin1String("/" GAMMARAY_PLUGIN_INSTALL_DIR "/" GAMMARAY_PLUGIN_VERSION "/") + probeABI);
125     addPluginPath(l, rootPath() + QLatin1String("/" GAMMARAY_PLUGIN_INSTALL_DIR));
126 
127     // based on Qt plugin search paths
128     foreach (const auto &path, QCoreApplication::libraryPaths()) {
129         addPluginPath(l, path + QLatin1String("/gammaray/" GAMMARAY_PLUGIN_VERSION "/") + probeABI);
130         addPluginPath(l, path + QLatin1String("/gammaray"));
131 
132 #if defined(Q_OS_ANDROID) && QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
133         addPluginPath(l, path);
134 #endif
135     }
136 
137     // based on Qt's own install layout and/or qt.conf
138     const auto path = QLibraryInfo::location(QLibraryInfo::PluginsPath);
139     addPluginPath(l, path + QLatin1String("/gammaray/" GAMMARAY_PLUGIN_VERSION "/") + probeABI);
140     addPluginPath(l, path + QLatin1String("/gammaray"));
141 
142 
143     return l;
144 }
145 
targetPluginPaths(const QString & probeABI)146 QStringList targetPluginPaths(const QString& probeABI)
147 {
148     QStringList l;
149 
150     // based on rootPath()
151     addPluginPath(l, rootPath() + QLatin1String("/" GAMMARAY_TARGET_PLUGIN_INSTALL_DIR "/" GAMMARAY_PLUGIN_VERSION "/") + probeABI);
152     addPluginPath(l, rootPath() + QLatin1String("/" GAMMARAY_TARGET_PLUGIN_INSTALL_DIR));
153 
154     // based on Qt plugin search paths
155     foreach (const auto &path, QCoreApplication::libraryPaths()) {
156         addPluginPath(l, path + QLatin1String("/gammaray/" GAMMARAY_PLUGIN_VERSION "/") + probeABI + QLatin1String("/target"));
157         addPluginPath(l, path + QLatin1String("/gammaray-target"));
158     }
159 
160     // based on Qt's own install layout and/or qt.conf
161     const auto path = QLibraryInfo::location(QLibraryInfo::PluginsPath);
162     addPluginPath(l, path + QLatin1String("/gammaray/" GAMMARAY_PLUGIN_VERSION "/") + probeABI + QLatin1String("/target"));
163     addPluginPath(l, path + QLatin1String("/gammaray-target"));
164 
165     return l;
166 }
167 
currentPluginsPath()168 QString currentPluginsPath()
169 {
170 #ifndef GAMMARAY_INSTALL_QT_LAYOUT
171     return probePath(QStringLiteral(GAMMARAY_PROBE_ABI));
172 #else
173     return rootPath() + QDir::separator() + QStringLiteral(GAMMARAY_PLUGIN_INSTALL_DIR);
174 #endif
175 }
176 
libraryExtension()177 QString libraryExtension()
178 {
179 #ifdef Q_OS_WIN
180     return QStringLiteral(".dll");
181 #elif defined(Q_OS_MAC)
182     return QStringLiteral(".dylib");
183 #elif defined(Q_OS_ANDROID) && QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
184     return QLatin1Char('_') + QLatin1String(ANDROID_ABI) + QLatin1String(".so");
185 #else
186     return QStringLiteral(".so");
187 #endif
188 }
189 
pluginExtension()190 QString pluginExtension()
191 {
192 #ifdef Q_OS_MAC
193     return QStringLiteral(".so");
194 #else
195     return libraryExtension();
196 #endif
197 }
198 
documentationPath()199 QString documentationPath()
200 {
201     return rootPath() + QLatin1Char('/') + QLatin1String(GAMMARAY_QCH_INSTALL_DIR);
202 }
203 }
204 }
205