diff --git a/src/libs/utils/hostosinfo.cpp b/src/libs/utils/hostosinfo.cpp index c5f313d5ce7..78ed7f22867 100644 --- a/src/libs/utils/hostosinfo.cpp +++ b/src/libs/utils/hostosinfo.cpp @@ -35,6 +35,10 @@ #include #endif +#ifdef Q_OS_MACOS +#include +#endif + using namespace Utils; Qt::CaseSensitivity HostOsInfo::m_overrideFileNameCaseSensitivity = Qt::CaseSensitive; @@ -70,6 +74,17 @@ HostOsInfo::HostArchitecture HostOsInfo::hostArchitecture() #endif } +bool HostOsInfo::isRunningUnderRosetta() +{ +#ifdef Q_OS_MACOS + int translated = 0; + auto size = sizeof(translated); + if (sysctlbyname("sysctl.proc_translated", &translated, &size, nullptr, 0) == 0) + return translated; +#endif + return false; +} + void HostOsInfo::setOverrideFileNameCaseSensitivity(Qt::CaseSensitivity sensitivity) { m_useOverrideFileNameCaseSensitivity = true; diff --git a/src/libs/utils/hostosinfo.h b/src/libs/utils/hostosinfo.h index 541419e432e..db2d77074b4 100644 --- a/src/libs/utils/hostosinfo.h +++ b/src/libs/utils/hostosinfo.h @@ -73,6 +73,8 @@ public: #endif } + static bool isRunningUnderRosetta(); + static QString withExecutableSuffix(const QString &executable) { return OsSpecificAspects::withExecutableSuffix(hostOs(), executable); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 8ac33da098f..142e2bf6b92 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -98,6 +98,7 @@ static Q_LOGGING_CATEGORY(cmakeBuildConfigurationLog, "qtc.cmake.bc", QtWarningM const char CONFIGURATION_KEY[] = "CMake.Configuration"; const char DEVELOPMENT_TEAM_FLAG[] = "Ios:DevelopmentTeam:Flag"; const char PROVISIONING_PROFILE_FLAG[] = "Ios:ProvisioningProfile:Flag"; +const char CMAKE_OSX_ARCHITECTURES_FLAG[] = "CMAKE_OSX_ARCHITECTURES:DefaultFlag"; const char CMAKE_QT6_TOOLCHAIN_FILE_ARG[] = "-DCMAKE_TOOLCHAIN_FILE:PATH=%{Qt:QT_INSTALL_PREFIX}/lib/cmake/Qt6/qt.toolchain.cmake"; @@ -890,6 +891,21 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id) return QString(); }); + macroExpander()->registerVariable(CMAKE_OSX_ARCHITECTURES_FLAG, + tr("The CMake flag for the architecture on macOS"), + [target] { + if (HostOsInfo::isRunningUnderRosetta()) { + if (auto *qt = QtSupport::QtKitAspect::qtVersion(target->kit())) { + const Abis abis = qt->qtAbis(); + for (const Abi &abi : abis) { + if (abi.architecture() == Abi::ArmArchitecture) + return QLatin1String("-DCMAKE_OSX_ARCHITECTURES=arm64"); + } + } + } + return QLatin1String(); + }); + addAspect(); addAspect(); @@ -939,27 +955,33 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id) } } - if (isIos(k)) { - QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(k); - if (qt && qt->qtVersion().majorVersion >= 6) { - // TODO it would be better if we could set - // CMAKE_SYSTEM_NAME=iOS and CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=YES - // and build with "cmake --build . -- -arch " instead of setting the architecture - // and sysroot in the CMake configuration, but that currently doesn't work with Qt/CMake - // https://gitlab.kitware.com/cmake/cmake/-/issues/21276 - const Id deviceType = DeviceTypeKitAspect::deviceTypeId(k); - // TODO the architectures are probably not correct with Apple Silicon in the mix... - const QString architecture = deviceType == Ios::Constants::IOS_DEVICE_TYPE - ? QLatin1String("arm64") - : QLatin1String("x86_64"); - const QString sysroot = deviceType == Ios::Constants::IOS_DEVICE_TYPE - ? QLatin1String("iphoneos") - : QLatin1String("iphonesimulator"); - initialArgs.append(CMAKE_QT6_TOOLCHAIN_FILE_ARG); - initialArgs.append("-DCMAKE_OSX_ARCHITECTURES:STRING=" + architecture); - initialArgs.append("-DCMAKE_OSX_SYSROOT:STRING=" + sysroot); - initialArgs.append("%{" + QLatin1String(DEVELOPMENT_TEAM_FLAG) + "}"); - initialArgs.append("%{" + QLatin1String(PROVISIONING_PROFILE_FLAG) + "}"); + const IDevice::ConstPtr device = DeviceKitAspect::device(k); + if (device->osType() == Utils::OsTypeMac) { + if (isIos(k)) { + QtSupport::BaseQtVersion *qt = QtSupport::QtKitAspect::qtVersion(k); + if (qt && qt->qtVersion().majorVersion >= 6) { + // TODO it would be better if we could set + // CMAKE_SYSTEM_NAME=iOS and CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH=YES + // and build with "cmake --build . -- -arch " instead of setting the architecture + // and sysroot in the CMake configuration, but that currently doesn't work with Qt/CMake + // https://gitlab.kitware.com/cmake/cmake/-/issues/21276 + const Id deviceType = DeviceTypeKitAspect::deviceTypeId(k); + // TODO the architectures are probably not correct with Apple Silicon in the mix... + const QString architecture = deviceType == Ios::Constants::IOS_DEVICE_TYPE + ? QLatin1String("arm64") + : QLatin1String("x86_64"); + const QString sysroot = deviceType == Ios::Constants::IOS_DEVICE_TYPE + ? QLatin1String("iphoneos") + : QLatin1String("iphonesimulator"); + initialArgs.append(CMAKE_QT6_TOOLCHAIN_FILE_ARG); + initialArgs.append("-DCMAKE_OSX_ARCHITECTURES:STRING=" + architecture); + initialArgs.append("-DCMAKE_OSX_SYSROOT:STRING=" + sysroot); + initialArgs.append("%{" + QLatin1String(DEVELOPMENT_TEAM_FLAG) + "}"); + initialArgs.append("%{" + QLatin1String(PROVISIONING_PROFILE_FLAG) + "}"); + } + } else { + // macOS + initialArgs.append("%{" + QLatin1String(CMAKE_OSX_ARCHITECTURES_FLAG) + "}"); } } diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp index 925c240942c..e058e11b8c0 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 421f6f2c26b..7b05e6f9efa 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -216,7 +216,11 @@ void LldbEngine::setupEngine() if (QFileInfo(runParameters().debugger.workingDirectory).isDir()) m_lldbProc.setWorkingDirectory(runParameters().debugger.workingDirectory); - m_lldbProc.setCommand(CommandLine(lldbCmd)); + if (HostOsInfo::isRunningUnderRosetta()) + m_lldbProc.setCommand(CommandLine("/usr/bin/arch", {"-arm64", lldbCmd.toString()})); + else + m_lldbProc.setCommand(CommandLine(lldbCmd)); + m_lldbProc.start(); if (!m_lldbProc.waitForStarted()) { diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index d24f190de7d..ef2ab71b06e 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -51,6 +51,8 @@ #include #include +#include + #include #include #include @@ -609,6 +611,13 @@ void QMakeStep::separateDebugInfoChanged() askForRebuild(tr("Separate Debug Information")); } +static bool isIos(const Kit *k) +{ + const Id deviceType = DeviceTypeKitAspect::deviceTypeId(k); + return deviceType == Ios::Constants::IOS_DEVICE_TYPE + || deviceType == Ios::Constants::IOS_SIMULATOR_TYPE; +} + void QMakeStep::abisChanged() { m_selectedAbis.clear(); @@ -618,20 +627,42 @@ void QMakeStep::abisChanged() m_selectedAbis << item->text(); } - if (isAndroidKit()) { - const QString prefix = "ANDROID_ABIS="; - QStringList args = m_extraArgs; - for (auto it = args.begin(); it != args.end(); ++it) { - if (it->startsWith(prefix)) { - args.erase(it); - break; + if (BaseQtVersion *qtVersion = QtKitAspect::qtVersion(target()->kit())) { + if (qtVersion->hasAbi(Abi::LinuxOS, Abi::AndroidLinuxFlavor)) { + const QString prefix = "ANDROID_ABIS="; + QStringList args = m_extraArgs; + for (auto it = args.begin(); it != args.end(); ++it) { + if (it->startsWith(prefix)) { + args.erase(it); + break; + } } - } - if (!m_selectedAbis.isEmpty()) - args << prefix + '"' + m_selectedAbis.join(' ') + '"'; - setExtraArguments(args); + if (!m_selectedAbis.isEmpty()) + args << prefix + '"' + m_selectedAbis.join(' ') + '"'; + setExtraArguments(args); - buildSystem()->setProperty(Android::Constants::ANDROID_ABIS, m_selectedAbis); + buildSystem()->setProperty(Android::Constants::ANDROID_ABIS, m_selectedAbis); + } else if (qtVersion->hasAbi(Abi::DarwinOS) && !isIos(target()->kit())) { + const QString prefix = "QMAKE_APPLE_DEVICE_ARCHS="; + QStringList args = m_extraArgs; + for (auto it = args.begin(); it != args.end(); ++it) { + if (it->startsWith(prefix)) { + args.erase(it); + break; + } + } + QStringList archs; + for (const QString &selectedAbi : qAsConst(m_selectedAbis)) { + const auto abi = Abi::abiFromTargetTriplet(selectedAbi); + if (abi.architecture() == Abi::X86Architecture) + archs << "x86_64"; + else if (abi.architecture() == Abi::ArmArchitecture) + archs << "arm64"; + } + if (!archs.isEmpty()) + args << prefix + '"' + archs.join(' ') + '"'; + setExtraArguments(args); + } } updateAbiWidgets(); @@ -668,18 +699,6 @@ void QMakeStep::askForRebuild(const QString &title) question->show(); } -bool QMakeStep::isAndroidKit() const -{ - BaseQtVersion *qtVersion = QtKitAspect::qtVersion(target()->kit()); - if (!qtVersion) - return false; - - const Abis abis = qtVersion->qtAbis(); - return Utils::anyOf(abis, [](const Abi &abi) { - return abi.osFlavor() == Abi::OSFlavor::AndroidLinuxFlavor; - }); -} - void QMakeStep::updateAbiWidgets() { if (!abisLabel) @@ -698,15 +717,23 @@ void QMakeStep::updateAbiWidgets() abisListWidget->clear(); QStringList selectedAbis = m_selectedAbis; - if (selectedAbis.isEmpty() && isAndroidKit()) { - // Prefer ARM for Android, prefer 32bit. - for (const Abi &abi : abis) { - if (abi.param() == ProjectExplorer::Constants::ANDROID_ABI_ARMEABI_V7A) - selectedAbis.append(abi.param()); - } - if (selectedAbis.isEmpty()) { + if (selectedAbis.isEmpty()) { + if (qtVersion->hasAbi(Abi::LinuxOS, Abi::AndroidLinuxFlavor)) { + // Prefer ARM for Android, prefer 32bit. for (const Abi &abi : abis) { - if (abi.param() == ProjectExplorer::Constants::ANDROID_ABI_ARM64_V8A) + if (abi.param() == ProjectExplorer::Constants::ANDROID_ABI_ARMEABI_V7A) + selectedAbis.append(abi.param()); + } + if (selectedAbis.isEmpty()) { + for (const Abi &abi : abis) { + if (abi.param() == ProjectExplorer::Constants::ANDROID_ABI_ARM64_V8A) + selectedAbis.append(abi.param()); + } + } + } else if (qtVersion->hasAbi(Abi::DarwinOS) && !isIos(target()->kit()) && HostOsInfo::isRunningUnderRosetta()) { + // Automatically select arm64 when running under Rosetta + for (const Abi &abi : abis) { + if (abi.architecture() == Abi::ArmArchitecture) selectedAbis.append(abi.param()); } } @@ -788,14 +815,6 @@ QMakeStepConfig::OsType QMakeStepConfig::osTypeFor(const Abi &targetAbi, const B QStringList QMakeStepConfig::toArguments() const { QStringList arguments; - if (archConfig == X86) - arguments << "CONFIG+=x86"; - else if (archConfig == X86_64) - arguments << "CONFIG+=x86_64"; - else if (archConfig == PowerPC) - arguments << "CONFIG+=ppc"; - else if (archConfig == PowerPC64) - arguments << "CONFIG+=ppc64"; // TODO: make that depend on the actual Qt version that is used if (osType == IphoneSimulator) diff --git a/src/plugins/qmakeprojectmanager/qmakestep.h b/src/plugins/qmakeprojectmanager/qmakestep.h index b439108436d..aecaaef04bd 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.h +++ b/src/plugins/qmakeprojectmanager/qmakestep.h @@ -185,7 +185,6 @@ private: void updateAbiWidgets(); void updateEffectiveQMakeCall(); - bool isAndroidKit() const; Utils::CommandLine m_qmakeCommand; Utils::CommandLine m_makeCommand; diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 6165d543033..d209dfa304d 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -840,6 +840,20 @@ Abis BaseQtVersion::detectQtAbis() const return qtAbisFromLibrary(d->qtCorePaths()); } +bool BaseQtVersion::hasAbi(ProjectExplorer::Abi::OS os, ProjectExplorer::Abi::OSFlavor flavor) const +{ + const Abis abis = qtAbis(); + return Utils::anyOf(abis, [&](const Abi &abi) { + if (abi.os() != os) + return false; + + if (flavor == Abi::UnknownFlavor) + return true; + + return abi.osFlavor() == flavor; + }); +} + bool BaseQtVersion::equals(BaseQtVersion *other) { if (d->m_qmakeCommand != other->d->m_qmakeCommand) diff --git a/src/plugins/qtsupport/baseqtversion.h b/src/plugins/qtsupport/baseqtversion.h index 9ea9af4b1d9..7c333b63fad 100644 --- a/src/plugins/qtsupport/baseqtversion.h +++ b/src/plugins/qtsupport/baseqtversion.h @@ -119,6 +119,7 @@ public: virtual QString toHtml(bool verbose) const; ProjectExplorer::Abis qtAbis() const; + bool hasAbi(ProjectExplorer::Abi::OS, ProjectExplorer::Abi::OSFlavor flavor = ProjectExplorer::Abi::UnknownFlavor) const; void applyProperties(QMakeGlobals *qmakeGlobals) const; virtual void addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const;