macOS용 Qt - 특정 문제
이 페이지에서는 Qt의 macOS 지원과 관련된 주요 이슈를 간략하게 설명합니다. macOS 용어와 구체적인 프로세스는 https://developer.apple.com/ 에서 확인할 수 있습니다.
Aqua
Aqua 스타일은 macOS 플랫폼의 필수적인 부분입니다. Cocoa와 마찬가지로, Qt는 macOS 휴먼 인터페이스 가이드라인에 설명된 것과 유사한 위젯을 제공합니다. Qt의 위젯은 룩앤필을 위해 내부적으로 AppKit을 사용하지만, 각 개별 Qt 위젯을 래핑된 네이티브 컨트롤로 나타내지는 않습니다.
Qt Widget 갤러리 페이지에는 macOS 플랫폼 테마를 사용하는 애플리케이션의 샘플 이미지가 포함되어 있습니다.
macOS용 Qt 속성
다음은 macOS에서 애플리케이션을 조정하는 데 사용할 수 있는 유용한 어트리뷰트 세트입니다:
- Qt::AA_PluginApplication
- Qt::AA_DontUseNativeMenuBar
- Qt::AA_MacDontSwapCtrlAndMeta
- Qt::WA_MacOpaqueSizeGrip
- Qt::WA_MacShowFocusRect
- Qt::WA_MacNormalSize
- Qt::WA_MacSmallSize
- Qt::WA_MacMiniSize
- Qt::WA_MacAlwaysShowToolWindow
- Qt::Sheet
- Qt::Drawer
- Qt::MacWindowToolBarButtonHint,
- QMainWindow::unifiedTitleAndToolBarOnMac
macOS는 항상 화면을 이중 버퍼링하므로 Qt::WA_PaintOnScreen 어트리뷰트는 효과가 없습니다. 또한 페인트 이벤트 외부에서 페인트를 칠할 수 없으므로 Qt::WA_PaintOutsidePaintEvent도 효과가 없습니다.
마우스 오른쪽 클릭
QContextMenuEvent 클래스는 macOS 애플리케이션을 위한 마우스 오른쪽 클릭 지원을 제공합니다. 이는 팝업 선택 항목을 표시하는 메뉴와 같은 컨텍스트 메뉴 이벤트에 매핑됩니다. 이는 마우스 오른쪽 클릭의 가장 일반적인 사용 방법이며, macOS 원버튼 마우스 지원과 함께 컨트롤 클릭에 매핑됩니다.
국제화
macOS의 애플리케이션은 애플리케이션의 Info.plist
에서 지원되는 언어를 선언합니다. 그러면 시스템이 애플리케이션의 지원 언어를 사용자의 언어 기본 설정과 일치시켜 애플리케이션이 실행되는 로캘을 결정합니다. 그러면 QLocale::uiLanguages()를 통해 반영되는 순서 언어와 AppKit과 같은 시스템 프레임워크가 메뉴 제목 및 문자열과 같은 현지화된 리소스를 가져오는 방식이 결정됩니다.
Qt 앱은 즉시 번역되지 않으므로 CMake
및 qmake
프로젝트에 대해 기본적으로 생성된 Info.plist
는 시스템 프레임워크가 CFBundleAllowMixedLocalizations
를 YES
로 설정하여 애플리케이션 자체에 해당 지역화를 사용할 수 없더라도 시스템 프레임워크가 사용자의 언어 기본 설정에 가장 잘 맞는 지역화를 선택할 수 있도록 합니다. qt_add_translations를 통해 애플리케이션에 번역을 추가하면 CFBundleAllowMixedLocalizations
키가 자동으로 제거되고 CFBundleLocalizations
로 대체되어 지원하는 모든 언어가 나열됩니다. qmake
의 경우 이 프로세스를 수동으로 수행해야 합니다.
메뉴 바
Qt는 메뉴 바를 감지하여 Mac 네이티브 메뉴 바로 변환합니다. 이를 기존 Qt 어플리케이션에 맞추는 것은 일반적으로 자동으로 이루어집니다. 그러나 특별한 요구사항이 있는 경우, Qt 구현은 현재 활성 창(예: QGuiApplication::focusWindow())에서 시작하여 다음 테스트를 적용하여 메뉴 바를 선택합니다:
- 창에 QMenuBar 이 있으면 이 창이 사용됩니다.
- 창이 모달이면 해당 메뉴 표시줄이 사용됩니다. 메뉴 모음을 지정하지 않으면 기본 메뉴 모음이 사용됩니다(아래 문서 참조).
- 창에 부모가 없는 경우 기본 메뉴 모음이 사용됩니다(아래 문서 참조).
이러한 테스트는 위의 규칙 중 하나가 충족될 때까지 상위 창 체인까지 계속 따릅니다. 다른 모든 테스트가 실패하면 기본 메뉴 표시줄이 생성됩니다. Qt의 기본 메뉴 모음은 빈 메뉴 모음입니다. 그러나 부모가 없는 QMenuBar 을 생성하여 다른 기본 메뉴 표시줄을 만들 수 있습니다. 처음 생성된 것이 기본 메뉴 표시줄로 지정되며 기본 메뉴 표시줄이 필요할 때마다 사용됩니다.
기본 메뉴 표시줄을 사용하면 Qt 클래스에 특정 제한이 생깁니다. 아래 제한 사항 목록 섹션에 자세한 정보가 나와 있습니다.
Qt는 QMenuBar 를 통해 글로벌 메뉴 바를 지원합니다. macOS 사용자는 화면 상단에 메뉴 바가 있기를 기대하며, Qt는 이를 존중합니다.
또한 사용자는 애플리케이션 메뉴에 정보, 환경 설정, 종료 등과 같은 특정 규칙이 존중되기를 기대합니다. Qt는 이러한 규칙을 처리하지만 애플리케이션 메뉴와 직접 상호 작용할 수 있는 수단을 제공하지는 않습니다.
각 QAction 에는 응용 프로그램 메뉴 항목의 특수 배치를 제어하는 menuRole 속성이 있지만, 기본적으로 menuRole
은 TextHeuristicRole 이므로 메뉴 항목은 text 에 의해 자동 감지됩니다.
잘라내기, 복사, 붙여넣기 및 모두 선택과 같은 다른 표준 메뉴 항목은 애플리케이션과 QFileDialog 과 같은 일부 기본 대화 상자에서 모두 적용 가능합니다. 대화 상자에서 해당 편집 기능을 사용할 수 있도록 표준 바로가기를 사용하여 이러한 메뉴 항목을 만드는 것이 중요합니다. 현재로서는 MenuRole
식별자가 없지만 QAction
에 기본값 TextHeuristicRole 이 있는 경우 애플리케이션 메뉴 항목과 마찬가지로 자동으로 감지됩니다.
특수 키
macOS에서 Qt 애플리케이션에 예상되는 동작을 제공하기 위해 Qt::Key_Meta, Qt::MetaModifier, Qt::META 열거형 값은 표준 Apple 키보드의 Control 키에 해당하고 Qt::Key_Control, Qt::ControlModifier, Qt::CTRL 열거형 값은 Command 키에 해당합니다.
Dock
도크와 상호 작용할 수 있습니다. 아이콘은 애플리케이션의 메인 창에서 QWindow::setWindowIcon()을 호출하여 설정할 수 있습니다. setWindowIcon() 호출은 필요한 만큼 자주 호출할 수 있으므로 쉽게 업데이트할 수 있는 아이콘을 제공합니다.
접근성
많은 사용자가 보조 장치를 사용하여 macOS와 상호작용합니다. Qt의 목표는 애플리케이션에서 이를 자동으로 처리하여 해당 플랫폼에서 통용되는 관행에 부합하도록 하는 것입니다. Qt는 Apple의 접근성 프레임워크를 사용하여 장애가 있는 사용자에게 접근성을 제공합니다.
라이브러리 및 배포 지원
Qt는 프레임워크 및 번들과 같은 macOS 구조를 지원합니다. 이러한 구조는 애플리케이션 배포에 직접적인 영향을 미치므로 이를 숙지하는 것이 중요합니다.
Qt는 배포 프로세스를 간소화하기 위해 배포 도구인 macdeployqt를 제공합니다. 배포 프로세스에 대한 자세한 내용은 macOS용 Qt - 배포 문서를 참조하십시오.
프레임워크로서의 Qt 라이브러리
기본적으로 Qt는 프레임워크의 집합으로 빌드됩니다. 프레임워크는 macOS에서 선호하는 라이브러리 배포 방식입니다. 프레임워크에 대한 자세한 정보는 Apple의 프레임워크 프로그래밍 가이드 사이트에서 확인할 수 있습니다.
프레임워크는 항상 라이브러리의 릴리스 버전과 연동된다는 점을 기억하는 것이 중요합니다. Qt 프레임워크의 디버그 버전이 필요한 경우 DYLD_IMAGE_SUFFIX
환경 변수를 사용하여 디버그 버전이 로드되도록 합니다:
export DYLD_IMAGE_SUFFIX=_debug
또는 일시적으로 디버그 버전과 릴리스 버전을 교체할 수 있으며, 이는 Apple의 "Debugging Magic" 기술 노트에 설명되어 있습니다.
프레임워크를 사용하고 싶지 않다면 -no-framework
으로 Qt를 구성하면 됩니다.
./configure -no-framework
번들 기반 라이브러리
macOS 애플리케이션 번들(애플리케이션 디렉토리)에서 일부 동적 라이브러리를 사용하려면 애플리케이션 번들 디렉토리에 Frameworks라는 하위 디렉토리를 생성하고 동적 라이브러리를 여기에 배치합니다. 애플리케이션의 설치 이름이 @executable_path/../Frameworks/libname.dylib인 경우 동적 라이브러리를 찾을 수 있습니다.
qmake
및 메이크파일을 사용하는 경우 QMAKE_LFLAGS_SONAME
설정을 사용합니다:
QMAKE_LFLAGS_SONAME = -Wl,-install_name,@executable_path/../Frameworks/
또는 명령줄에서 install_name_tool(1)
을 사용하여 설치 이름을 수정할 수 있습니다.
DYLD_LIBRARY_PATH
환경 변수는 이러한 설정과 /usr/lib 및 유사한 기본 위치 내의 동적 라이브러리 조회와 같은 다른 기본 경로를 재정의합니다.
라이브러리 결합
Qt 동적 라이브러리를 결합한 새로운 동적 라이브러리를 빌드하려면 ld -r
플래그를 도입해야 합니다. 그러면 재배치 정보가 출력 파일에 저장되어 이 파일이 다른 ld
실행의 대상이 될 수 있습니다. 이는 .pro
파일과 LFLAGS
설정에서 -r
플래그를 설정하면 됩니다.
초기화 순서
dyld(1)
는 애플리케이션에 링크된 순서대로 전역 정적 초기화자를 호출합니다. 라이브러리가 Qt에 링크되고 Qt의 전역 초기화자를 참조하는 경우(자체 라이브러리의 전역 초기화자로부터), 라이브러리에 링크하기 전에 애플리케이션을 Qt에 링크하십시오. 그렇지 않으면 Qt의 전역 이니셜라이저가 아직 호출되지 않았기 때문에 결과가 정의되지 않습니다.
컴파일 시간 플래그
다음 플래그는 macOS 전용 코드를 정의할 때 유용합니다:
Q_OS_DARWIN
는 Qt가 사용자가 macOS나 iOS와 같은 다윈 기반 시스템을 사용 중임을 감지할 때 정의됩니다.Q_OS_MACOS
는 macOS 시스템에 있을 때 정의됩니다.
참고: Q_WS_MAC
는 Qt 5 이상에서 더 이상 정의되지 않습니다.
특정 버전의 macOS에 대한 코드를 정의하려면 /usr/include/AvailabilityMacros.h에 정의된 가용성 매크로를 사용하십시오.
런타임 버전 확인에 대한 정보는 QSysInfo 및 QOperatingSystemVerison 설명서를 참조하세요.
macOS 네이티브 API 액세스
번들 경로에 액세스하기
macOS 애플리케이션은 디렉터리( .app로 끝나는)로 구성되어 있습니다. 이 디렉터리에는 하위 디렉터리와 파일이 포함되어 있습니다. 플러그인 및 온라인 문서와 같은 항목을 이 번들 안에 배치하는 것이 유용할 수 있습니다. 다음 코드는 애플리케이션 번들의 경로를 반환합니다:
#ifdef Q_OS_MAC QString 번들 경로 = QString::fromNSString(NSBundle.mainBundle.bundlePath); qDebug() << "Bundle path =" << bundlePath; #endif
NSBundle API 사용에 대한 자세한 내용은 Apple의 개발자 웹사이트를 참조하세요.
QCoreApplication::applicationDirPath()를 사용하여 번들 내의 바이너리 경로를 확인할 수 있습니다.
네이티브 코코아 패널 사용
Qt의 이벤트 디스패처는 Cocoa가 제공하는 것보다 더 유연하며, 사용자가 모달 대화 상자가 화면에 표시되는지 여부를 고려할 필요 없이 이벤트 디스패처( QEventLoop::exec)를 실행할 수 있습니다(이는 Cocoa와 비교했을 때 차이점입니다). 따라서 이를 올바르게 처리하려면 Qt에서 추가 관리가 필요하며, 안타깝게도 네이티브 패널을 혼합하는 것은 어렵습니다. 현재로서는 아래 패턴을 따르는 것이 가장 좋은데, 함수를 직접 호출하지 않고 네이티브 코드로 호출을 게시하는 것입니다. 그러면 네이티브 패널이 표시되기 전에 Qt가 보류 중인 이벤트 루프 재귀를 깔끔하게 업데이트한다는 것을 알 수 있습니다:
#include <QtGui> class NativeProxyObject : public QObject { Q_OBJECT public slots: void execNativeDialogLater() { QMetaObject::invokeMethod(this, "execNativeDialogNow", Qt::QueuedConnection); } void execNativeDialogNow() { NSRunAlertPanel(@"A Native dialog", @"", @"OK", @"", @""); } }; #include "main.moc" int main(int argc, char **argv){ QApplication app(argc, argv); NativeProxyObject proxy; QPushButton button("Show native dialog"); QObject::connect(&button, SIGNAL(clicked()), &proxy, SLOT(execNativeDialogLater())); button.show(); return app.exec(); }
제한 사항
MySQL 및 macOS
정적 C 라이브러리를 동적 라이브러리에 연결할 때 -prebind
및 -multi_module
을 모두 정의하는 경우 문제가 있는 것 같습니다. Qt를 연결할 때 다음과 같은 오류 메시지가 표시되는 경우:
ld: common symbols not allowed with MH_DYLIB output format with the -multi_module option /usr/local/mysql/lib/libmysqlclient.a(my_error.o) definition of common _errbuff (size 512) /usr/bin/libtool: internal link edit command failed
싱글 모듈을 사용하여 Qt를 다시 링크하세요. 이것은 MySQL 드라이버를 Qt로 빌드할 때만 발생하는 문제입니다. 플러그인이나 정적 빌드에는 영향을 미치지 않습니다.
D-Bus 및 macOS
QtDBus 모듈은 기본적으로 macOS에서 libdbus-1 라이브러리를 동적으로 로드합니다. 즉, QtDBus 모듈에 대해 링크하는 애플리케이션은 해당 라이브러리가 없는 macOS 시스템에서도 로드되지만 D-Bus 서버에 연결하지 못하고 QDBusServer 을 사용하여 서버를 열지 못합니다.
D-Bus 기능을 사용하려면 Homebrew, Fink 또는 MacPorts 등을 통해 libdbus-1 라이브러리를 설치해야 합니다. 다른 시스템에 배포하는 경우 애플리케이션의 번들에 이러한 라이브러리를 포함할 수 있습니다. 또한 macOS에는 시스템 버스가 없으며 세션 버스는 런치가 이를 관리하도록 구성한 후에만 시작된다는 점에 유의하세요.
메뉴 동작
- 두 개 이상의 키 입력이 있는 가속기(QKeySequence)가 있는 QMenu 의 동작은 QMenu 이 Mac 기본 메뉴 모음으로 변환될 때 올바르게 표시되지 않습니다. 첫 번째 키가 표시됩니다. 그러나 바로 가기는 다른 모든 플랫폼에서와 마찬가지로 여전히 활성화됩니다.
- QMenu 기본 메뉴 표시줄에서 사용되는 객체는 일반 이벤트 핸들러를 통해 Qt 이벤트를 처리할 수 없습니다. 이러한 변경 사항을 알림 받으려면 메뉴 자체에 델리게이트를 설치하세요. 또는 QMenu::aboutToShow() 및 QMenu::aboutToHide() 신호를 사용하여 메뉴 가시성을 추적하는 것도 고려할 수 있으며, 이는 Qt가 지원하는 모든 플랫폼에서 작동하는 솔루션을 제공합니다.
- 기본적으로 Qt는
CMD+Q
바로 가기에 반응하는 기본 종료 메뉴 항목을 생성합니다. QAction::QuitRole 역할에 대해 QAction 을 생성하면 해당 메뉴 항목이 대체됩니다. 따라서 대체 동작은 QCoreApplication::quit 슬롯 또는 애플리케이션을 중지하는 사용자 정의 슬롯에 연결해야 합니다.
기본 위젯
Qt는 창 플래그 Qt::Sheet 로 표시되는 시트를 지원합니다.
일반적으로 네이티브 macOS 애플리케이션을 언급할 때 네이티브는 중개 계층을 사용하는 애플리케이션이 아니라 기본 창 시스템에 직접 인터페이스하는 애플리케이션을 의미합니다. Qt 애플리케이션은 Cocoa 애플리케이션과 마찬가지로 1등 시민으로 실행됩니다. 내부적으로 운영 체제와 통신하기 위해 Cocoa를 사용합니다.
기호 가시성 경고
C++ 라이브러리 연결의 맥락에서 함수와 객체를 심볼이라고 합니다. 심볼은 default
또는 hidden
가시성을 가질 수 있습니다.
성능상의 이유로 Qt와 다른 많은 라이브러리는 기본적으로 hidden
가시성을 사용하여 소스를 컴파일하고, 사용자 프로젝트에서 사용하려는 경우에만 default
가시성을 가진 심볼을 표시합니다.
안타깝게도 한 라이브러리가 hidden
가시성으로 컴파일되고 사용자 프로젝트 애플리케이션이나 라이브러리가 default
가시성으로 컴파일되는 경우 Apple 링커가 경고를 표시할 수 있습니다.
프로젝트 개발자가 경고를 무효화하려면 프로젝트 코드도 hidden
가시성으로 빌드해야 합니다.
CMake에서는 CMakeLists.txt
에 다음 코드를 추가하여 이 작업을 수행할 수 있습니다:
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
qmake에서는 .pro
파일에 다음 코드를 추가하면 됩니다:
CONFIG+=hide_symbols
프로젝트에서 라이브러리를 빌드하는 경우, 라이브러리에서 다른 라이브러리나 애플리케이션에서 사용하려는 심볼은 default
가시성을 명시적으로 표시해야 합니다. 예를 들어, 이러한 함수나 클래스에 Q_DECL_EXPORT 을 사용하여 주석을 달면 됩니다.
CMake Xcode 프로젝트에서 생성한 xcarchive에 dSYM 번들이 누락됨
Xcode의 버그 및 특정 CMake 제한으로 인해 CMake로 생성된 Xcode 프로젝트는 Xcode의 아카이브 작업 중에 애플리케이션의 dSYM
번들을 xcarchive
에 포함하지 못합니다.
Qt는 dSYM
번들이 xcarchive
에 포함되도록 하는 해결 방법을 제공하지만, 이 방법에는 단점이 있습니다. 즉, 다음 CMake 기능이 올바르게 작동하지 않습니다:
$<TARGET_FILE:app>
생성기 표현식이 앱 바이너리로 연결되지 않는 잘못된 경로로 확장될 수 있습니다.CMAKE_RUNTIME_OUTPUT_DIRECTORY
변수 및 관련RUNTIME_OUTPUT_DIRECTORY
대상 속성이 설정되어 있어도 무시됩니다.- 기타 알려지지 않은 문제
위의 문제를 완화하려면 다음과 같이 할 수 있습니다:
- 프로젝트 개발 중이 아닌
xcarchive
을 만들려고 할 때만 해결 방법을 활성화합니다. add_subdirectory
호출이 아닌 루트 프로젝트 디렉토리에만 실행 파일과 라이브러리를 추가하세요.
해결 방법을 사용하려면 다음 옵션을 사용하여 프로젝트를 구성합니다:
cmake . -DQT_USE_RISKY_DSYM_ARCHIVING_WORKAROUND=ON
또는 qt_add_executable
또는 qt_add_library
호출 전에 프로젝트에서 변수를 설정합니다:
set(QT_USE_RISKY_DSYM_ARCHIVING_WORKAROUND ON) ... qt_add_executable(app)
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.