Implement Project Manager 'build' button for Mac and Linux(#4248)
Signed-off-by: Steve Pham <spham@amazon.com>
This commit is contained in:
@@ -7,14 +7,69 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ProjectBuilderWorker.h>
|
#include <ProjectBuilderWorker.h>
|
||||||
|
#include <ProjectManagerDefs.h>
|
||||||
|
#include <ProjectUtils.h>
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
namespace O3DE::ProjectManager
|
namespace O3DE::ProjectManager
|
||||||
{
|
{
|
||||||
AZ::Outcome<void, QString> ProjectBuilderWorker::BuildProjectForPlatform()
|
AZ::Outcome<QStringList, QString> ProjectBuilderWorker::ConstructCmakeGenerateProjectArguments(const QString& thirdPartyPath) const
|
||||||
{
|
{
|
||||||
QString error = tr("Automatic building on Linux not currently supported!");
|
// Attempt to use the Ninja build system if it is installed (described in the o3de documentation) if possible,
|
||||||
QStringToAZTracePrint(error);
|
// otherwise default to the the default for Linux (Unix Makefiles)
|
||||||
return AZ::Failure(error);
|
auto whichNinjaResult = ProjectUtils::ExecuteCommandResult("which", QStringList{"ninja"}, QProcessEnvironment::systemEnvironment());
|
||||||
|
QString cmakeGenerator = (whichNinjaResult.IsSuccess()) ? "Ninja Multi-Config" : "Unix Makefiles";
|
||||||
|
bool compileProfileOnBuild = (whichNinjaResult.IsSuccess());
|
||||||
|
|
||||||
|
// On Linux the default compiler is gcc. For O3DE, it is clang, so we need to specify the version of clang that is detected
|
||||||
|
// in order to get the compiler option.
|
||||||
|
auto compilerOptionResult = ProjectUtils::FindSupportedCompilerForPlatform();
|
||||||
|
if (!compilerOptionResult.IsSuccess())
|
||||||
|
{
|
||||||
|
return AZ::Failure(compilerOptionResult.GetError());
|
||||||
|
}
|
||||||
|
auto clangCompilers = compilerOptionResult.GetValue().split('|');
|
||||||
|
AZ_Assert(clangCompilers.length()==2, "Invalid clang compiler pair specification");
|
||||||
|
|
||||||
|
QString clangCompilerOption = clangCompilers[0];
|
||||||
|
QString clangPPCompilerOption = clangCompilers[1];
|
||||||
|
QString targetBuildPath = QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix);
|
||||||
|
QStringList generateProjectArgs = QStringList{ProjectCMakeCommand,
|
||||||
|
"-B", ProjectBuildPathPostfix,
|
||||||
|
"-S", ".",
|
||||||
|
QString("-G%1").arg(cmakeGenerator),
|
||||||
|
QString("-DCMAKE_C_COMPILER=").append(clangCompilerOption),
|
||||||
|
QString("-DCMAKE_CXX_COMPILER=").append(clangPPCompilerOption),
|
||||||
|
QString("-DLY_3RDPARTY_PATH=").append(thirdPartyPath)};
|
||||||
|
if (!compileProfileOnBuild)
|
||||||
|
{
|
||||||
|
generateProjectArgs.append("-DCMAKE_BUILD_TYPE=profile");
|
||||||
|
}
|
||||||
|
return AZ::Success(generateProjectArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AZ::Outcome<QStringList, QString> ProjectBuilderWorker::ConstructCmakeBuildCommandArguments() const
|
||||||
|
{
|
||||||
|
auto whichNinjaResult = ProjectUtils::ExecuteCommandResult("which", QStringList{"ninja"}, QProcessEnvironment::systemEnvironment());
|
||||||
|
bool compileProfileOnBuild = (whichNinjaResult.IsSuccess());
|
||||||
|
QString targetBuildPath = QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix);
|
||||||
|
QString launcherTargetName = m_projectInfo.m_projectName + ".GameLauncher";
|
||||||
|
|
||||||
|
QStringList buildProjectArgs = QStringList{ProjectCMakeCommand,
|
||||||
|
"--build", ProjectBuildPathPostfix,
|
||||||
|
"--target", launcherTargetName, ProjectCMakeBuildTargetEditor};
|
||||||
|
if (compileProfileOnBuild)
|
||||||
|
{
|
||||||
|
buildProjectArgs.append(QStringList{"--config","profile"});
|
||||||
|
}
|
||||||
|
return AZ::Success(buildProjectArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
AZ::Outcome<QStringList, QString> ProjectBuilderWorker::ConstructKillProcessCommandArguments(const QString& pidToKill) const
|
||||||
|
{
|
||||||
|
return AZ::Success(QStringList{"kill", "-9", pidToKill});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace O3DE::ProjectManager
|
} // namespace O3DE::ProjectManager
|
||||||
|
|||||||
@@ -6,15 +6,48 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ProjectUtils.h>
|
#include <ProjectUtils.h>
|
||||||
|
#include <ProjectManagerDefs.h>
|
||||||
|
#include <QProcessEnvironment>
|
||||||
|
|
||||||
namespace O3DE::ProjectManager
|
namespace O3DE::ProjectManager
|
||||||
{
|
{
|
||||||
namespace ProjectUtils
|
namespace ProjectUtils
|
||||||
{
|
{
|
||||||
AZ::Outcome<void, QString> FindSupportedCompilerForPlatform()
|
// The list of clang C/C++ compiler command lines to validate on the host Linux system
|
||||||
|
const QStringList SupportedClangCommands = {"clang-12|clang++-12"};
|
||||||
|
|
||||||
|
AZ::Outcome<QProcessEnvironment, QString> GetCommandLineProcessEnvironment()
|
||||||
{
|
{
|
||||||
// Compiler detection not supported on platform
|
return AZ::Success(QProcessEnvironment(QProcessEnvironment::systemEnvironment()));
|
||||||
return AZ::Success();
|
}
|
||||||
|
|
||||||
|
AZ::Outcome<QString, QString> FindSupportedCompilerForPlatform()
|
||||||
|
{
|
||||||
|
// Validate that cmake is installed and is in the command line
|
||||||
|
auto whichCMakeResult = ProjectUtils::ExecuteCommandResult("which", QStringList{ProjectCMakeCommand}, QProcessEnvironment::systemEnvironment());
|
||||||
|
if (!whichCMakeResult.IsSuccess())
|
||||||
|
{
|
||||||
|
return AZ::Failure(QObject::tr("CMake not found. \n\n"
|
||||||
|
"Make sure that the minimum version of CMake is installed and available from the command prompt. "
|
||||||
|
"Refer to the <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#cmake'>O3DE requirements</a> page for more information."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for the first compatible version of clang. The list below will contain the known clang compilers that have been tested for O3DE.
|
||||||
|
for (const QString& supportClangCommand : SupportedClangCommands)
|
||||||
|
{
|
||||||
|
auto clangCompilers = supportClangCommand.split('|');
|
||||||
|
AZ_Assert(clangCompilers.length()==2, "Invalid clang compiler pair specification");
|
||||||
|
|
||||||
|
auto whichClangResult = ProjectUtils::ExecuteCommandResult("which", QStringList{clangCompilers[0]}, QProcessEnvironment::systemEnvironment());
|
||||||
|
auto whichClangPPResult = ProjectUtils::ExecuteCommandResult("which", QStringList{clangCompilers[1]}, QProcessEnvironment::systemEnvironment());
|
||||||
|
if (whichClangResult.IsSuccess() && whichClangPPResult.IsSuccess())
|
||||||
|
{
|
||||||
|
return AZ::Success(supportClangCommand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AZ::Failure(QObject::tr("Clang not found. \n\n"
|
||||||
|
"Make sure that the clang is installed and available from the command prompt. "
|
||||||
|
"Refer to the <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#cmake'>O3DE requirements</a> page for more information."));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ProjectUtils
|
} // namespace ProjectUtils
|
||||||
|
|||||||
@@ -7,14 +7,82 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ProjectBuilderWorker.h>
|
#include <ProjectBuilderWorker.h>
|
||||||
|
#include <ProjectManagerDefs.h>
|
||||||
|
#include <ProjectUtils.h>
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
namespace O3DE::ProjectManager
|
namespace O3DE::ProjectManager
|
||||||
{
|
{
|
||||||
AZ::Outcome<void, QString> ProjectBuilderWorker::BuildProjectForPlatform()
|
namespace Internal
|
||||||
{
|
{
|
||||||
QString error = tr("Automatic building on MacOS not currently supported!");
|
AZ::Outcome<QString, QString> QueryInstalledCmakeFullPath()
|
||||||
QStringToAZTracePrint(error);
|
{
|
||||||
return AZ::Failure(error);
|
auto environmentRequest = ProjectUtils::GetCommandLineProcessEnvironment();
|
||||||
|
if (!environmentRequest.IsSuccess())
|
||||||
|
{
|
||||||
|
return AZ::Failure(environmentRequest.GetError());
|
||||||
|
}
|
||||||
|
auto currentEnvironment = environmentRequest.GetValue();
|
||||||
|
|
||||||
|
auto queryCmakeInstalled = ProjectUtils::ExecuteCommandResult("which",
|
||||||
|
QStringList{ProjectCMakeCommand},
|
||||||
|
currentEnvironment);
|
||||||
|
if (!queryCmakeInstalled.IsSuccess())
|
||||||
|
{
|
||||||
|
return AZ::Failure(QObject::tr("Unable to detect CMake on this host."));
|
||||||
|
}
|
||||||
|
QString cmakeInstalledPath = queryCmakeInstalled.GetValue().split("\n")[0];
|
||||||
|
return AZ::Success(cmakeInstalledPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AZ::Outcome<QStringList, QString> ProjectBuilderWorker::ConstructCmakeGenerateProjectArguments(const QString& thirdPartyPath) const
|
||||||
|
{
|
||||||
|
// For Mac, we need to resolve the full path of cmake and use that in the process request. For
|
||||||
|
// some reason, 'which' will resolve the full path, but when you just specify cmake with the same
|
||||||
|
// environment, it is unable to resolve. To work around this, we will use 'which' to resolve the
|
||||||
|
// full path and then use it as the command argument
|
||||||
|
auto cmakeInstalledPathQuery = Internal::QueryInstalledCmakeFullPath();
|
||||||
|
if (!cmakeInstalledPathQuery.IsSuccess())
|
||||||
|
{
|
||||||
|
return AZ::Failure(cmakeInstalledPathQuery.GetError());
|
||||||
|
}
|
||||||
|
QString cmakeInstalledPath = cmakeInstalledPathQuery.GetValue();
|
||||||
|
QString targetBuildPath = QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix);
|
||||||
|
|
||||||
|
return AZ::Success(QStringList{cmakeInstalledPath,
|
||||||
|
"-B", targetBuildPath,
|
||||||
|
"-S", m_projectInfo.m_path,
|
||||||
|
"-GXcode"});
|
||||||
|
}
|
||||||
|
|
||||||
|
AZ::Outcome<QStringList, QString> ProjectBuilderWorker::ConstructCmakeBuildCommandArguments() const
|
||||||
|
{
|
||||||
|
// For Mac, we need to resolve the full path of cmake and use that in the process request. For
|
||||||
|
// some reason, 'which' will resolve the full path, but when you just specify cmake with the same
|
||||||
|
// environment, it is unable to resolve. To work around this, we will use 'which' to resolve the
|
||||||
|
// full path and then use it as the command argument
|
||||||
|
auto cmakeInstalledPathQuery = Internal::QueryInstalledCmakeFullPath();
|
||||||
|
if (!cmakeInstalledPathQuery.IsSuccess())
|
||||||
|
{
|
||||||
|
return AZ::Failure(cmakeInstalledPathQuery.GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString cmakeInstalledPath = cmakeInstalledPathQuery.GetValue();
|
||||||
|
QString targetBuildPath = QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix);
|
||||||
|
QString launcherTargetName = m_projectInfo.m_projectName + ".GameLauncher";
|
||||||
|
|
||||||
|
return AZ::Success(QStringList{cmakeInstalledPath,
|
||||||
|
"--build", targetBuildPath,
|
||||||
|
"--config", "profile",
|
||||||
|
"--target", launcherTargetName, ProjectCMakeBuildTargetEditor});
|
||||||
|
}
|
||||||
|
|
||||||
|
AZ::Outcome<QStringList, QString> ProjectBuilderWorker::ConstructKillProcessCommandArguments(const QString& pidToKill) const
|
||||||
|
{
|
||||||
|
return AZ::Success(QStringList{"kill", "-9", pidToKill});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace O3DE::ProjectManager
|
} // namespace O3DE::ProjectManager
|
||||||
|
|||||||
@@ -7,15 +7,59 @@
|
|||||||
|
|
||||||
#include <ProjectUtils.h>
|
#include <ProjectUtils.h>
|
||||||
|
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
namespace O3DE::ProjectManager
|
namespace O3DE::ProjectManager
|
||||||
{
|
{
|
||||||
namespace ProjectUtils
|
namespace ProjectUtils
|
||||||
{
|
{
|
||||||
AZ::Outcome<void, QString> FindSupportedCompilerForPlatform()
|
AZ::Outcome<QProcessEnvironment, QString> GetCommandLineProcessEnvironment()
|
||||||
{
|
{
|
||||||
// Compiler detection not supported on platform
|
// For CMake on Mac, if its installed through home-brew, then it will be installed
|
||||||
return AZ::Success();
|
// under /usr/local/bin, which may not be in the system PATH environment.
|
||||||
|
// Add that path for the command line process so that it will be able to locate
|
||||||
|
// a home-brew installed version of CMake
|
||||||
|
QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment());
|
||||||
|
QString pathValue = currentEnvironment.value("PATH");
|
||||||
|
pathValue += ":/usr/local/bin";
|
||||||
|
currentEnvironment.insert("PATH", pathValue);
|
||||||
|
return AZ::Success(currentEnvironment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AZ::Outcome<QString, QString> FindSupportedCompilerForPlatform()
|
||||||
|
{
|
||||||
|
QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment());
|
||||||
|
QString pathValue = currentEnvironment.value("PATH");
|
||||||
|
pathValue += ":/usr/local/bin";
|
||||||
|
currentEnvironment.insert("PATH", pathValue);
|
||||||
|
|
||||||
|
// Validate that we have cmake installed first
|
||||||
|
auto queryCmakeInstalled = ExecuteCommandResult("which", QStringList{ProjectCMakeCommand}, currentEnvironment);
|
||||||
|
if (!queryCmakeInstalled.IsSuccess())
|
||||||
|
{
|
||||||
|
return AZ::Failure(QObject::tr("Unable to detect CMake on this host."));
|
||||||
|
}
|
||||||
|
QString cmakeInstalledPath = queryCmakeInstalled.GetValue().split("\n")[0];
|
||||||
|
|
||||||
|
// Query the version of the installed cmake
|
||||||
|
auto queryCmakeVersionQuery = ExecuteCommandResult(cmakeInstalledPath, QStringList{"-version"}, currentEnvironment);
|
||||||
|
if (!queryCmakeVersionQuery.IsSuccess())
|
||||||
|
{
|
||||||
|
return AZ::Failure(QObject::tr("Unable to determine the version of CMake on this host."));
|
||||||
|
}
|
||||||
|
AZ_TracePrintf("Project Manager", "Cmake version %s detected.", queryCmakeVersionQuery.GetValue().split("\n")[0].toUtf8().constData());
|
||||||
|
|
||||||
|
// Query for the version of xcodebuild (if installed)
|
||||||
|
auto queryXcodeBuildVersion = ExecuteCommandResult("xcodebuild", QStringList{"-version"}, currentEnvironment);
|
||||||
|
if (!queryCmakeInstalled.IsSuccess())
|
||||||
|
{
|
||||||
|
return AZ::Failure(QObject::tr("Unable to detect XCodeBuilder on this host."));
|
||||||
|
}
|
||||||
|
QString xcodeBuilderVersionNumber = queryXcodeBuildVersion.GetValue().split("\n")[0];
|
||||||
|
AZ_TracePrintf("Project Manager", "XcodeBuilder version %s detected.", xcodeBuilderVersionNumber.toUtf8().constData());
|
||||||
|
|
||||||
|
|
||||||
|
return AZ::Success(xcodeBuilderVersionNumber);
|
||||||
|
}
|
||||||
} // namespace ProjectUtils
|
} // namespace ProjectUtils
|
||||||
} // namespace O3DE::ProjectManager
|
} // namespace O3DE::ProjectManager
|
||||||
|
|||||||
@@ -8,189 +8,37 @@
|
|||||||
|
|
||||||
#include <ProjectBuilderWorker.h>
|
#include <ProjectBuilderWorker.h>
|
||||||
#include <ProjectManagerDefs.h>
|
#include <ProjectManagerDefs.h>
|
||||||
#include <PythonBindingsInterface.h>
|
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFile>
|
#include <QString>
|
||||||
#include <QProcess>
|
|
||||||
#include <QProcessEnvironment>
|
|
||||||
#include <QTextStream>
|
|
||||||
#include <QThread>
|
|
||||||
|
|
||||||
namespace O3DE::ProjectManager
|
namespace O3DE::ProjectManager
|
||||||
{
|
{
|
||||||
AZ::Outcome<void, QString> ProjectBuilderWorker::BuildProjectForPlatform()
|
AZ::Outcome<QStringList, QString> ProjectBuilderWorker::ConstructCmakeGenerateProjectArguments(const QString& thirdPartyPath) const
|
||||||
{
|
{
|
||||||
// Check if we are trying to cancel task
|
QString targetBuildPath = QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix);
|
||||||
if (QThread::currentThread()->isInterruptionRequested())
|
|
||||||
{
|
|
||||||
QStringToAZTracePrint(BuildCancelled);
|
|
||||||
return AZ::Failure(BuildCancelled);
|
|
||||||
}
|
|
||||||
|
|
||||||
QFile logFile(GetLogFilePath());
|
return AZ::Success(QStringList{ ProjectCMakeCommand,
|
||||||
if (!logFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
|
"-B", targetBuildPath,
|
||||||
{
|
"-S", m_projectInfo.m_path,
|
||||||
QString error = tr("Failed to open log file.");
|
QString("-DLY_3RDPARTY_PATH=").append(thirdPartyPath),
|
||||||
QStringToAZTracePrint(error);
|
"-DLY_UNITY_BUILD=ON" } );
|
||||||
return AZ::Failure(error);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
EngineInfo engineInfo;
|
AZ::Outcome<QStringList, QString> ProjectBuilderWorker::ConstructCmakeBuildCommandArguments() const
|
||||||
|
{
|
||||||
|
QString targetBuildPath = QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix);
|
||||||
|
QString launcherTargetName = m_projectInfo.m_projectName + ".GameLauncher";
|
||||||
|
|
||||||
AZ::Outcome<EngineInfo> engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo();
|
return AZ::Success(QStringList{ ProjectCMakeCommand,
|
||||||
if (engineInfoResult.IsSuccess())
|
"--build", targetBuildPath,
|
||||||
{
|
"--config", "profile",
|
||||||
engineInfo = engineInfoResult.GetValue();
|
"--target", launcherTargetName, ProjectCMakeBuildTargetEditor });
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
QString error = tr("Failed to get engine info.");
|
|
||||||
QStringToAZTracePrint(error);
|
|
||||||
return AZ::Failure(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
QTextStream logStream(&logFile);
|
AZ::Outcome<QStringList, QString> ProjectBuilderWorker::ConstructKillProcessCommandArguments(const QString& pidToKill) const
|
||||||
if (QThread::currentThread()->isInterruptionRequested())
|
{
|
||||||
{
|
return AZ::Success(QStringList { "cmd.exe", "/C", "taskkill", "/pid", pidToKill, "/f", "/t" } );
|
||||||
logFile.close();
|
|
||||||
QStringToAZTracePrint(BuildCancelled);
|
|
||||||
return AZ::Failure(BuildCancelled);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show some kind of progress with very approximate estimates
|
|
||||||
UpdateProgress(++m_progressEstimate);
|
|
||||||
|
|
||||||
QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment());
|
|
||||||
// Append cmake path to PATH incase it is missing
|
|
||||||
QDir cmakePath(engineInfo.m_path);
|
|
||||||
cmakePath.cd("cmake/runtime/bin");
|
|
||||||
QString pathValue = currentEnvironment.value("PATH");
|
|
||||||
pathValue += ";" + cmakePath.path();
|
|
||||||
currentEnvironment.insert("PATH", pathValue);
|
|
||||||
|
|
||||||
m_configProjectProcess = new QProcess(this);
|
|
||||||
m_configProjectProcess->setProcessChannelMode(QProcess::MergedChannels);
|
|
||||||
m_configProjectProcess->setWorkingDirectory(m_projectInfo.m_path);
|
|
||||||
m_configProjectProcess->setProcessEnvironment(currentEnvironment);
|
|
||||||
|
|
||||||
m_configProjectProcess->start(
|
|
||||||
"cmake",
|
|
||||||
QStringList
|
|
||||||
{
|
|
||||||
"-B",
|
|
||||||
QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix),
|
|
||||||
"-S",
|
|
||||||
m_projectInfo.m_path,
|
|
||||||
"-G",
|
|
||||||
"Visual Studio 16",
|
|
||||||
"-DLY_3RDPARTY_PATH=" + engineInfo.m_thirdPartyPath,
|
|
||||||
"-DLY_UNITY_BUILD=1"
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!m_configProjectProcess->waitForStarted())
|
|
||||||
{
|
|
||||||
QString error = tr("Configuring project failed to start.");
|
|
||||||
QStringToAZTracePrint(error);
|
|
||||||
return AZ::Failure(error);
|
|
||||||
}
|
|
||||||
bool containsGeneratingDone = false;
|
|
||||||
while (m_configProjectProcess->waitForReadyRead(MaxBuildTimeMSecs))
|
|
||||||
{
|
|
||||||
QString configOutput = m_configProjectProcess->readAllStandardOutput();
|
|
||||||
|
|
||||||
if (configOutput.contains("Generating done"))
|
|
||||||
{
|
|
||||||
containsGeneratingDone = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
logStream << configOutput;
|
|
||||||
logStream.flush();
|
|
||||||
|
|
||||||
UpdateProgress(qMin(++m_progressEstimate, 19));
|
|
||||||
|
|
||||||
if (QThread::currentThread()->isInterruptionRequested())
|
|
||||||
{
|
|
||||||
logFile.close();
|
|
||||||
m_configProjectProcess->close();
|
|
||||||
QStringToAZTracePrint(BuildCancelled);
|
|
||||||
return AZ::Failure(BuildCancelled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_configProjectProcess->exitStatus() != QProcess::ExitStatus::NormalExit
|
|
||||||
|| m_configProjectProcess->exitCode() != 0
|
|
||||||
|| !containsGeneratingDone)
|
|
||||||
{
|
|
||||||
QString error = tr("Configuring project failed. See log for details.");
|
|
||||||
QStringToAZTracePrint(error);
|
|
||||||
return AZ::Failure(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateProgress(++m_progressEstimate);
|
|
||||||
|
|
||||||
m_buildProjectProcess = new QProcess(this);
|
|
||||||
m_buildProjectProcess->setProcessChannelMode(QProcess::MergedChannels);
|
|
||||||
m_buildProjectProcess->setWorkingDirectory(m_projectInfo.m_path);
|
|
||||||
m_buildProjectProcess->setProcessEnvironment(currentEnvironment);
|
|
||||||
|
|
||||||
m_buildProjectProcess->start(
|
|
||||||
"cmake",
|
|
||||||
QStringList
|
|
||||||
{
|
|
||||||
"--build",
|
|
||||||
QDir(m_projectInfo.m_path).filePath(ProjectBuildPathPostfix),
|
|
||||||
"--target",
|
|
||||||
m_projectInfo.m_projectName + ".GameLauncher",
|
|
||||||
"Editor",
|
|
||||||
"--config",
|
|
||||||
"profile"
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!m_buildProjectProcess->waitForStarted())
|
|
||||||
{
|
|
||||||
QString error = tr("Building project failed to start.");
|
|
||||||
QStringToAZTracePrint(error);
|
|
||||||
return AZ::Failure(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// There are a lot of steps when building so estimate around 800 more steps ((100 - 20) * 10) remaining
|
|
||||||
m_progressEstimate = 200;
|
|
||||||
while (m_buildProjectProcess->waitForReadyRead(MaxBuildTimeMSecs))
|
|
||||||
{
|
|
||||||
logStream << m_buildProjectProcess->readAllStandardOutput();
|
|
||||||
logStream.flush();
|
|
||||||
|
|
||||||
// Show 1% progress for every 10 steps completed
|
|
||||||
UpdateProgress(qMin(++m_progressEstimate / 10, 99));
|
|
||||||
|
|
||||||
if (QThread::currentThread()->isInterruptionRequested())
|
|
||||||
{
|
|
||||||
// QProcess is unable to kill its child processes so we need to ask the operating system to do that for us
|
|
||||||
QProcess killBuildProcess;
|
|
||||||
killBuildProcess.setProcessChannelMode(QProcess::MergedChannels);
|
|
||||||
killBuildProcess.start(
|
|
||||||
"cmd.exe", QStringList{ "/C", "taskkill", "/pid", QString::number(m_buildProjectProcess->processId()), "/f", "/t" });
|
|
||||||
killBuildProcess.waitForFinished();
|
|
||||||
|
|
||||||
logStream << "Killing Project Build.";
|
|
||||||
logStream << killBuildProcess.readAllStandardOutput();
|
|
||||||
m_buildProjectProcess->kill();
|
|
||||||
logFile.close();
|
|
||||||
QStringToAZTracePrint(BuildCancelled);
|
|
||||||
return AZ::Failure(BuildCancelled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_configProjectProcess->exitStatus() != QProcess::ExitStatus::NormalExit
|
|
||||||
|| m_configProjectProcess->exitCode() != 0)
|
|
||||||
{
|
|
||||||
QString error = tr("Building project failed. See log for details.");
|
|
||||||
QStringToAZTracePrint(error);
|
|
||||||
return AZ::Failure(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return AZ::Success();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace O3DE::ProjectManager
|
} // namespace O3DE::ProjectManager
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <ProjectUtils.h>
|
#include <ProjectUtils.h>
|
||||||
|
|
||||||
|
#include <PythonBindingsInterface.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
@@ -16,8 +18,44 @@ namespace O3DE::ProjectManager
|
|||||||
{
|
{
|
||||||
namespace ProjectUtils
|
namespace ProjectUtils
|
||||||
{
|
{
|
||||||
AZ::Outcome<void, QString> FindSupportedCompilerForPlatform()
|
AZ::Outcome<QProcessEnvironment, QString> GetCommandLineProcessEnvironment()
|
||||||
{
|
{
|
||||||
|
// Use the engine path to insert a path for cmake
|
||||||
|
auto engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo();
|
||||||
|
if (!engineInfoResult.IsSuccess())
|
||||||
|
{
|
||||||
|
return AZ::Failure(QObject::tr("Failed to get engine info"));
|
||||||
|
}
|
||||||
|
auto engineInfo = engineInfoResult.GetValue();
|
||||||
|
|
||||||
|
QProcessEnvironment currentEnvironment(QProcessEnvironment::systemEnvironment());
|
||||||
|
|
||||||
|
// Append cmake path to PATH incase it is missing
|
||||||
|
QDir cmakePath(engineInfo.m_path);
|
||||||
|
cmakePath.cd("cmake/runtime/bin");
|
||||||
|
QString pathValue = currentEnvironment.value("PATH");
|
||||||
|
pathValue += ";" + cmakePath.path();
|
||||||
|
currentEnvironment.insert("PATH", pathValue);
|
||||||
|
return AZ::Success(currentEnvironment);
|
||||||
|
}
|
||||||
|
|
||||||
|
AZ::Outcome<QString, QString> FindSupportedCompilerForPlatform()
|
||||||
|
{
|
||||||
|
// Validate that cmake is installed
|
||||||
|
auto cmakeProcessEnvResult = GetCommandLineProcessEnvironment();
|
||||||
|
if (!cmakeProcessEnvResult.IsSuccess())
|
||||||
|
{
|
||||||
|
return AZ::Failure(cmakeProcessEnvResult.GetError());
|
||||||
|
}
|
||||||
|
auto cmakeVersionQueryResult = ExecuteCommandResult("cmake", QStringList{"--version"}, cmakeProcessEnvResult.GetValue());
|
||||||
|
if (!cmakeVersionQueryResult.IsSuccess())
|
||||||
|
{
|
||||||
|
return AZ::Failure(QObject::tr("CMake not found. \n\n"
|
||||||
|
"Make sure that the minimum version of CMake is installed and available from the command prompt. "
|
||||||
|
"Refer to the <a href='https://o3de.org/docs/welcome-guide/setup/requirements/#cmake'>O3DE requirements</a> for more information."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate that the minimal version of visual studio is installed
|
||||||
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
|
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
|
||||||
QString programFilesPath = environment.value("ProgramFiles(x86)");
|
QString programFilesPath = environment.value("ProgramFiles(x86)");
|
||||||
QString vsWherePath = QDir(programFilesPath).filePath("Microsoft Visual Studio/Installer/vswhere.exe");
|
QString vsWherePath = QDir(programFilesPath).filePath("Microsoft Visual Studio/Installer/vswhere.exe");
|
||||||
@@ -25,27 +63,31 @@ namespace O3DE::ProjectManager
|
|||||||
QFileInfo vsWhereFile(vsWherePath);
|
QFileInfo vsWhereFile(vsWherePath);
|
||||||
if (vsWhereFile.exists() && vsWhereFile.isFile())
|
if (vsWhereFile.exists() && vsWhereFile.isFile())
|
||||||
{
|
{
|
||||||
QProcess vsWhereProcess;
|
QStringList vsWhereBaseArguments = QStringList{"-version",
|
||||||
vsWhereProcess.setProcessChannelMode(QProcess::MergedChannels);
|
"16.9.2",
|
||||||
|
"-latest",
|
||||||
|
"-requires",
|
||||||
|
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64"};
|
||||||
|
|
||||||
vsWhereProcess.start(
|
QProcess vsWhereIsCompleteProcess;
|
||||||
vsWherePath,
|
vsWhereIsCompleteProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
QStringList{
|
|
||||||
"-version",
|
|
||||||
"16.9.2",
|
|
||||||
"-latest",
|
|
||||||
"-requires",
|
|
||||||
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
|
|
||||||
"-property",
|
|
||||||
"isComplete"
|
|
||||||
});
|
|
||||||
|
|
||||||
if (vsWhereProcess.waitForStarted() && vsWhereProcess.waitForFinished())
|
vsWhereIsCompleteProcess.start(vsWherePath, vsWhereBaseArguments + QStringList{ "-property", "isComplete" });
|
||||||
|
|
||||||
|
if (vsWhereIsCompleteProcess.waitForStarted() && vsWhereIsCompleteProcess.waitForFinished())
|
||||||
{
|
{
|
||||||
QString vsWhereOutput(vsWhereProcess.readAllStandardOutput());
|
QString vsWhereIsCompleteOutput(vsWhereIsCompleteProcess.readAllStandardOutput());
|
||||||
if (vsWhereOutput.startsWith("1"))
|
if (vsWhereIsCompleteOutput.startsWith("1"))
|
||||||
{
|
{
|
||||||
return AZ::Success();
|
QProcess vsWhereCompilerVersionProcess;
|
||||||
|
vsWhereCompilerVersionProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
vsWhereCompilerVersionProcess.start(vsWherePath, vsWhereBaseArguments + QStringList{"-property", "catalog_productDisplayVersion"});
|
||||||
|
|
||||||
|
if (vsWhereCompilerVersionProcess.waitForStarted() && vsWhereCompilerVersionProcess.waitForFinished())
|
||||||
|
{
|
||||||
|
QString vsWhereCompilerVersionOutput(vsWhereCompilerVersionProcess.readAllStandardOutput());
|
||||||
|
return AZ::Success(vsWhereCompilerVersionOutput);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,15 @@
|
|||||||
|
|
||||||
#include <ProjectBuilderWorker.h>
|
#include <ProjectBuilderWorker.h>
|
||||||
#include <ProjectManagerDefs.h>
|
#include <ProjectManagerDefs.h>
|
||||||
|
#include <PythonBindingsInterface.h>
|
||||||
|
#include <ProjectUtils.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QProcessEnvironment>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
//#define MOCK_BUILD_PROJECT true
|
//#define MOCK_BUILD_PROJECT true
|
||||||
|
|
||||||
@@ -67,4 +74,176 @@ namespace O3DE::ProjectManager
|
|||||||
{
|
{
|
||||||
AZ_TracePrintf("Project Manager", error.toStdString().c_str());
|
AZ_TracePrintf("Project Manager", error.toStdString().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AZ::Outcome<void, QString> ProjectBuilderWorker::BuildProjectForPlatform()
|
||||||
|
{
|
||||||
|
// Check if we are trying to cancel task
|
||||||
|
if (QThread::currentThread()->isInterruptionRequested())
|
||||||
|
{
|
||||||
|
QStringToAZTracePrint(BuildCancelled);
|
||||||
|
return AZ::Failure(BuildCancelled);
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile logFile(GetLogFilePath());
|
||||||
|
if (!logFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
|
||||||
|
{
|
||||||
|
QString error = tr("Failed to open log file.");
|
||||||
|
QStringToAZTracePrint(error);
|
||||||
|
return AZ::Failure(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
EngineInfo engineInfo;
|
||||||
|
|
||||||
|
AZ::Outcome<EngineInfo> engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo();
|
||||||
|
if (engineInfoResult.IsSuccess())
|
||||||
|
{
|
||||||
|
engineInfo = engineInfoResult.GetValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QString error = tr("Failed to get engine info.");
|
||||||
|
QStringToAZTracePrint(error);
|
||||||
|
return AZ::Failure(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream logStream(&logFile);
|
||||||
|
if (QThread::currentThread()->isInterruptionRequested())
|
||||||
|
{
|
||||||
|
logFile.close();
|
||||||
|
QStringToAZTracePrint(BuildCancelled);
|
||||||
|
return AZ::Failure(BuildCancelled);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show some kind of progress with very approximate estimates
|
||||||
|
UpdateProgress(++m_progressEstimate);
|
||||||
|
|
||||||
|
auto currentEnvironmentRequest = ProjectUtils::GetCommandLineProcessEnvironment();
|
||||||
|
if (!currentEnvironmentRequest.IsSuccess())
|
||||||
|
{
|
||||||
|
QStringToAZTracePrint(currentEnvironmentRequest.GetError());
|
||||||
|
return AZ::Failure(currentEnvironmentRequest.GetError());
|
||||||
|
}
|
||||||
|
QProcessEnvironment currentEnvironment = currentEnvironmentRequest.GetValue();
|
||||||
|
|
||||||
|
m_configProjectProcess = new QProcess(this);
|
||||||
|
m_configProjectProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
m_configProjectProcess->setWorkingDirectory(m_projectInfo.m_path);
|
||||||
|
m_configProjectProcess->setProcessEnvironment(currentEnvironment);
|
||||||
|
|
||||||
|
auto cmakeGenerateArgumentsResult = ConstructCmakeGenerateProjectArguments(engineInfo.m_thirdPartyPath);
|
||||||
|
if (!cmakeGenerateArgumentsResult.IsSuccess())
|
||||||
|
{
|
||||||
|
QStringToAZTracePrint(cmakeGenerateArgumentsResult.GetError());
|
||||||
|
return AZ::Failure(cmakeGenerateArgumentsResult.GetError());
|
||||||
|
}
|
||||||
|
auto cmakeGenerateArguments = cmakeGenerateArgumentsResult.GetValue();
|
||||||
|
m_configProjectProcess->start(cmakeGenerateArguments.front(), cmakeGenerateArguments.mid(1));
|
||||||
|
if (!m_configProjectProcess->waitForStarted())
|
||||||
|
{
|
||||||
|
QString error = tr("Configuring project failed to start.");
|
||||||
|
QStringToAZTracePrint(error);
|
||||||
|
return AZ::Failure(error);
|
||||||
|
}
|
||||||
|
bool containsGeneratingDone = false;
|
||||||
|
while (m_configProjectProcess->waitForReadyRead(MaxBuildTimeMSecs))
|
||||||
|
{
|
||||||
|
QString configOutput = m_configProjectProcess->readAllStandardOutput();
|
||||||
|
|
||||||
|
if (configOutput.contains("Generating done"))
|
||||||
|
{
|
||||||
|
containsGeneratingDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
logStream << configOutput;
|
||||||
|
logStream.flush();
|
||||||
|
|
||||||
|
UpdateProgress(qMin(++m_progressEstimate, 19));
|
||||||
|
|
||||||
|
if (QThread::currentThread()->isInterruptionRequested())
|
||||||
|
{
|
||||||
|
logFile.close();
|
||||||
|
m_configProjectProcess->close();
|
||||||
|
QStringToAZTracePrint(BuildCancelled);
|
||||||
|
return AZ::Failure(BuildCancelled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_configProjectProcess->exitStatus() != QProcess::ExitStatus::NormalExit || m_configProjectProcess->exitCode() != 0 ||
|
||||||
|
!containsGeneratingDone)
|
||||||
|
{
|
||||||
|
QString error = tr("Configuring project failed. See log for details.");
|
||||||
|
QStringToAZTracePrint(error);
|
||||||
|
return AZ::Failure(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateProgress(++m_progressEstimate);
|
||||||
|
|
||||||
|
m_buildProjectProcess = new QProcess(this);
|
||||||
|
m_buildProjectProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
m_buildProjectProcess->setWorkingDirectory(m_projectInfo.m_path);
|
||||||
|
m_buildProjectProcess->setProcessEnvironment(currentEnvironment);
|
||||||
|
|
||||||
|
auto cmakeBuildArgumentsResult = ConstructCmakeBuildCommandArguments();
|
||||||
|
if (!cmakeBuildArgumentsResult.IsSuccess())
|
||||||
|
{
|
||||||
|
QStringToAZTracePrint(cmakeBuildArgumentsResult.GetError());
|
||||||
|
return AZ::Failure(cmakeBuildArgumentsResult.GetError());
|
||||||
|
}
|
||||||
|
auto cmakeBuildArguments = cmakeBuildArgumentsResult.GetValue();
|
||||||
|
|
||||||
|
m_buildProjectProcess->start(cmakeBuildArguments.front(), cmakeBuildArguments.mid(1));
|
||||||
|
if (!m_buildProjectProcess->waitForStarted())
|
||||||
|
{
|
||||||
|
QString error = tr("Building project failed to start.");
|
||||||
|
QStringToAZTracePrint(error);
|
||||||
|
return AZ::Failure(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// There are a lot of steps when building so estimate around 800 more steps ((100 - 20) * 10) remaining
|
||||||
|
m_progressEstimate = 200;
|
||||||
|
while (m_buildProjectProcess->waitForReadyRead(MaxBuildTimeMSecs))
|
||||||
|
{
|
||||||
|
logStream << m_buildProjectProcess->readAllStandardOutput();
|
||||||
|
logStream.flush();
|
||||||
|
|
||||||
|
// Show 1% progress for every 10 steps completed
|
||||||
|
UpdateProgress(qMin(++m_progressEstimate / 10, 99));
|
||||||
|
|
||||||
|
if (QThread::currentThread()->isInterruptionRequested())
|
||||||
|
{
|
||||||
|
// QProcess is unable to kill its child processes so we need to ask the operating system to do that for us
|
||||||
|
auto killProcessArgumentsResult = ConstructKillProcessCommandArguments(QString::number(m_buildProjectProcess->processId()));
|
||||||
|
if (!killProcessArgumentsResult.IsSuccess())
|
||||||
|
{
|
||||||
|
return AZ::Failure(killProcessArgumentsResult.GetError());
|
||||||
|
}
|
||||||
|
auto killProcessArguments = killProcessArgumentsResult.GetValue();
|
||||||
|
|
||||||
|
|
||||||
|
QProcess killBuildProcess;
|
||||||
|
|
||||||
|
|
||||||
|
killBuildProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
killBuildProcess.start(killProcessArguments.front(), killProcessArguments.mid(1));
|
||||||
|
killBuildProcess.waitForFinished();
|
||||||
|
|
||||||
|
logStream << "Killing Project Build.";
|
||||||
|
logStream << killBuildProcess.readAllStandardOutput();
|
||||||
|
m_buildProjectProcess->kill();
|
||||||
|
logFile.close();
|
||||||
|
QStringToAZTracePrint(BuildCancelled);
|
||||||
|
return AZ::Failure(BuildCancelled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_buildProjectProcess->exitStatus() != QProcess::ExitStatus::NormalExit || m_buildProjectProcess->exitCode() != 0)
|
||||||
|
{
|
||||||
|
QString error = tr("Building project failed. See log for details.");
|
||||||
|
QStringToAZTracePrint(error);
|
||||||
|
return AZ::Failure(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AZ::Success();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace O3DE::ProjectManager
|
} // namespace O3DE::ProjectManager
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <AzCore/Outcome/Outcome.h>
|
#include <AzCore/Outcome/Outcome.h>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QProcessEnvironment>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QProcess)
|
QT_FORWARD_DECLARE_CLASS(QProcess)
|
||||||
@@ -44,6 +45,12 @@ namespace O3DE::ProjectManager
|
|||||||
AZ::Outcome<void, QString> BuildProjectForPlatform();
|
AZ::Outcome<void, QString> BuildProjectForPlatform();
|
||||||
void QStringToAZTracePrint(const QString& error);
|
void QStringToAZTracePrint(const QString& error);
|
||||||
|
|
||||||
|
// Command line argument builders
|
||||||
|
AZ::Outcome<QStringList, QString> ConstructCmakeGenerateProjectArguments(const QString& thirdPartyPath) const;
|
||||||
|
AZ::Outcome<QStringList, QString> ConstructCmakeBuildCommandArguments() const;
|
||||||
|
AZ::Outcome<QStringList, QString> ConstructKillProcessCommandArguments(const QString& pidToKill) const;
|
||||||
|
|
||||||
|
|
||||||
QProcess* m_configProjectProcess = nullptr;
|
QProcess* m_configProjectProcess = nullptr;
|
||||||
QProcess* m_buildProjectProcess = nullptr;
|
QProcess* m_buildProjectProcess = nullptr;
|
||||||
ProjectInfo m_projectInfo;
|
ProjectInfo m_projectInfo;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ namespace O3DE::ProjectManager
|
|||||||
inline constexpr static int ProjectPreviewImageWidth = 210;
|
inline constexpr static int ProjectPreviewImageWidth = 210;
|
||||||
inline constexpr static int ProjectPreviewImageHeight = 280;
|
inline constexpr static int ProjectPreviewImageHeight = 280;
|
||||||
inline constexpr static int ProjectTemplateImageWidth = 92;
|
inline constexpr static int ProjectTemplateImageWidth = 92;
|
||||||
|
inline constexpr static int ProjectCommandLineTimeoutSeconds = 30;
|
||||||
|
|
||||||
static const QString ProjectBuildDirectoryName = "build";
|
static const QString ProjectBuildDirectoryName = "build";
|
||||||
extern const QString ProjectBuildPathPostfix;
|
extern const QString ProjectBuildPathPostfix;
|
||||||
@@ -21,4 +22,8 @@ namespace O3DE::ProjectManager
|
|||||||
static const QString ProjectBuildErrorLogName = "CMakeProjectBuildError.log";
|
static const QString ProjectBuildErrorLogName = "CMakeProjectBuildError.log";
|
||||||
static const QString ProjectCacheDirectoryName = "Cache";
|
static const QString ProjectCacheDirectoryName = "Cache";
|
||||||
static const QString ProjectPreviewImagePath = "preview.png";
|
static const QString ProjectPreviewImagePath = "preview.png";
|
||||||
|
|
||||||
|
static const QString ProjectCMakeCommand = "cmake";
|
||||||
|
static const QString ProjectCMakeBuildTargetEditor = "Editor";
|
||||||
|
|
||||||
} // namespace O3DE::ProjectManager
|
} // namespace O3DE::ProjectManager
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
#include <QSpacerItem>
|
#include <QSpacerItem>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
|
|
||||||
|
#include <AzCore/std/chrono/chrono.h>
|
||||||
|
|
||||||
namespace O3DE::ProjectManager
|
namespace O3DE::ProjectManager
|
||||||
{
|
{
|
||||||
namespace ProjectUtils
|
namespace ProjectUtils
|
||||||
@@ -507,5 +509,33 @@ namespace O3DE::ProjectManager
|
|||||||
|
|
||||||
return ProjectManagerScreen::Invalid;
|
return ProjectManagerScreen::Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AZ::Outcome<QString, QString> ExecuteCommandResult(
|
||||||
|
const QString& cmd,
|
||||||
|
const QStringList& arguments,
|
||||||
|
const QProcessEnvironment& processEnv,
|
||||||
|
int commandTimeoutSeconds /*= ProjectCommandLineTimeoutSeconds*/)
|
||||||
|
{
|
||||||
|
QProcess execProcess;
|
||||||
|
execProcess.setProcessEnvironment(processEnv);
|
||||||
|
execProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
execProcess.start(cmd, arguments);
|
||||||
|
if (!execProcess.waitForStarted())
|
||||||
|
{
|
||||||
|
return AZ::Failure(QObject::tr("Unable to start process for command '%1'").arg(cmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!execProcess.waitForFinished(commandTimeoutSeconds * 1000 /* Milliseconds per second */))
|
||||||
|
{
|
||||||
|
return AZ::Failure(QObject::tr("Process for command '%1' timed out at %2 seconds").arg(cmd).arg(commandTimeoutSeconds));
|
||||||
|
}
|
||||||
|
int resultCode = execProcess.exitCode();
|
||||||
|
if (resultCode != 0)
|
||||||
|
{
|
||||||
|
return AZ::Failure(QObject::tr("Process for command '%1' failed (result code %2").arg(cmd).arg(resultCode));
|
||||||
|
}
|
||||||
|
QString resultOutput = execProcess.readAllStandardOutput();
|
||||||
|
return AZ::Success(resultOutput);
|
||||||
|
}
|
||||||
} // namespace ProjectUtils
|
} // namespace ProjectUtils
|
||||||
} // namespace O3DE::ProjectManager
|
} // namespace O3DE::ProjectManager
|
||||||
|
|||||||
@@ -9,8 +9,11 @@
|
|||||||
|
|
||||||
#include <ScreenDefs.h>
|
#include <ScreenDefs.h>
|
||||||
#include <ProjectInfo.h>
|
#include <ProjectInfo.h>
|
||||||
|
#include <ProjectManagerDefs.h>
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QProcessEnvironment>
|
||||||
|
|
||||||
#include <AzCore/Outcome/Outcome.h>
|
#include <AzCore/Outcome/Outcome.h>
|
||||||
|
|
||||||
namespace O3DE::ProjectManager
|
namespace O3DE::ProjectManager
|
||||||
@@ -28,8 +31,17 @@ namespace O3DE::ProjectManager
|
|||||||
bool ReplaceProjectFile(const QString& origFile, const QString& newFile, QWidget* parent = nullptr, bool interactive = true);
|
bool ReplaceProjectFile(const QString& origFile, const QString& newFile, QWidget* parent = nullptr, bool interactive = true);
|
||||||
|
|
||||||
bool FindSupportedCompiler(QWidget* parent = nullptr);
|
bool FindSupportedCompiler(QWidget* parent = nullptr);
|
||||||
AZ::Outcome<void, QString> FindSupportedCompilerForPlatform();
|
AZ::Outcome<QString, QString> FindSupportedCompilerForPlatform();
|
||||||
|
|
||||||
ProjectManagerScreen GetProjectManagerScreen(const QString& screen);
|
ProjectManagerScreen GetProjectManagerScreen(const QString& screen);
|
||||||
|
|
||||||
|
AZ::Outcome<QString, QString> ExecuteCommandResult(
|
||||||
|
const QString& cmd,
|
||||||
|
const QStringList& arguments,
|
||||||
|
const QProcessEnvironment& processEnv,
|
||||||
|
int commandTimeoutSeconds = ProjectCommandLineTimeoutSeconds);
|
||||||
|
|
||||||
|
AZ::Outcome<QProcessEnvironment, QString> GetCommandLineProcessEnvironment();
|
||||||
|
|
||||||
} // namespace ProjectUtils
|
} // namespace ProjectUtils
|
||||||
} // namespace O3DE::ProjectManager
|
} // namespace O3DE::ProjectManager
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ namespace O3DE::ProjectManager
|
|||||||
{
|
{
|
||||||
for (auto engine : allEngines)
|
for (auto engine : allEngines)
|
||||||
{
|
{
|
||||||
AZ::IO::FixedMaxPath enginePath(Py_To_String(engine["path"]));
|
AZ::IO::FixedMaxPath enginePath(Py_To_String(engine));
|
||||||
if (enginePath.Compare(m_enginePath) == 0)
|
if (enginePath.Compare(m_enginePath) == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user