이 페이지에서

macOS용 Qt - 특정 문제

이 페이지에서는 Qt의 macOS 지원과 관련된 주요 문제점을 설명합니다. macOS 관련 용어 및 구체적인 절차는 https://developer.apple.com/에서 확인할 수 있습니다.

Aqua

Aqua 스타일은 macOS 플랫폼의 핵심 요소입니다. Cocoa와 마찬가지로, Qt는 macOS 휴먼 인터페이스 가이드라인( Human Interface Guidelines)에 설명된 것과 유사한 모양의 위젯을 제공합니다. Qt Widgets는 외관과 사용감을 구현하기 위해 내부적으로 AppKit을 사용하지만, 각 개별 Qt Widgets를 래핑된 네이티브 컨트롤로 표현하지는 않는다는 점에 유의하십시오.

Qt Widgets 갤러리 페이지에는 macOS 플랫폼 테마를 사용하는 애플리케이션의 예시 이미지가 포함되어 있습니다.

macOS용 Qt 속성

다음은 macOS에서 애플리케이션을 세부적으로 조정하는 데 사용할 수 있는 유용한 속성 목록입니다:

macOS는 항상 화면을 더블 버퍼링하므로, ` Qt::WA_PaintOnScreen ` 속성은 아무런 효과가 없습니다. 또한 페인트 이벤트 외부에서 페인팅하는 것은 불가능하므로 `Qt::WA_PaintOutsidePaintEvent`도 효과가 없습니다.

마우스 오른쪽 클릭

QContextMenuEvent 클래스는 macOS 애플리케이션에 마우스 오른쪽 버튼 클릭 기능을 제공합니다. 이는 컨텍스트 메뉴 이벤트, 예를 들어 팝업 선택 항목을 표시하는 메뉴로 매핑됩니다. 이것이 마우스 오른쪽 버튼 클릭의 가장 일반적인 용도이며, macOS의 단일 버튼 마우스 지원 환경에서는 Control 키를 누른 채 클릭하는 동작으로 매핑됩니다.

국제화

macOS의 애플리케이션은 애플리케이션의 ` Info.plist `의 일부로 지원되는 언어를 선언합니다. 그런 다음 시스템은 애플리케이션이 지원하는 언어와 사용자의 언어 환경 설정을 대조하여 애플리케이션이 실행될 로케일을 결정합니다. 이는 결과적으로 ` QLocale::uiLanguages()`를 통해 반영되는 언어 순서와, AppKit과 같은 시스템 프레임워크가 메뉴 제목 및 문자열과 같은 현지화된 리소스를 어떻게 불러오는지 결정합니다.

Qt 애플리케이션은 기본적으로 번역되어 제공되지 않으므로, CMake 및 qmake 프로젝트용으로 생성된 기본 Info.plist 파일은 CFBundleAllowMixedLocalizationsYES 로 설정되어, 애플리케이션 자체에 해당 현지화 버전이 없더라도 시스템 프레임워크가 사용자의 언어 기본 설정에 가장 잘 맞는 현지화 버전을 선택할 수 있도록 합니다. qt_add_translations를 통해 애플리케이션에 번역을 추가하면 CFBundleAllowMixedLocalizations 해당 키는 자동으로 제거되고, CFBundleLocalizations로 대체되며, 여기에는 지원하는 모든 언어가 나열됩니다. qmake 의 경우 이 과정을 수동으로 수행해야 합니다.

Qt는 메뉴 바를 감지하여 Mac 기본 메뉴 바로 변환합니다. 기존 Qt 애플리케이션에 이를 적용하는 작업은 일반적으로 자동으로 이루어집니다. 그러나 특별한 요구 사항이 있는 경우, 현재 Qt 구현은 활성화된 창(예: QGuiApplication::focusWindow())부터 시작하여 다음 테스트를 적용함으로써 메뉴 바를 선택합니다:

  1. 창에 QMenuBar 가 있으면 이를 사용합니다.
  2. 창이 모달인 경우, 해당 창의 메뉴 바가 사용됩니다. 메뉴 바가 지정되지 않은 경우, 기본 메뉴 바가 사용됩니다(아래 설명 참조).
  3. 창에 부모가 없는 경우, 기본 메뉴 바가 사용됩니다(아래에 설명된 대로).

이러한 테스트는 위의 규칙 중 하나가 충족될 때까지 부모 창 체인을 따라 위쪽으로 계속 진행됩니다. 다른 모든 방법이 실패하면 기본 메뉴 바가 생성됩니다. Qt의 기본 메뉴 바는 빈 메뉴 바입니다. 그러나 부모가 없는 QMenuBar 을 생성하여 다른 기본 메뉴 바를 만들 수 있습니다. 가장 먼저 생성된 것이 기본 메뉴 바로 지정되며, 기본 메뉴 바가 필요할 때마다 사용됩니다.

네이티브 메뉴 바를 사용하면 Qt 클래스에 특정 제한 사항이 적용됩니다. 아래의 제한 사항 목록 섹션에서 자세한 정보를 확인할 수 있습니다.

Qt는 ` QMenuBar`을 통해 글로벌 메뉴 바를 지원합니다. macOS 사용자는 화면 상단에 메뉴 바가 있는 것을 기대하며, Qt는 이를 반영합니다.

또한 사용자들은 특정 관례가 준수되기를 기대합니다. 예를 들어, 애플리케이션 메뉴에는 ‘정보( About)’, ‘환경 설정( Preferences)’, ‘종료( Quit)’ 등이 포함되어야 합니다. 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

Dock과의 상호작용이 가능합니다. 애플리케이션의 메인 창에서 ` QWindow::setIcon()`를 호출하여 아이콘을 설정할 수 있습니다. `setIcon()` 호출은 필요한 만큼 자주 수행할 수 있으므로, 아이콘을 쉽게 업데이트할 수 있습니다.

접근성

많은 사용자가 보조 기기를 통해 macOS를 사용합니다. Qt는 애플리케이션이 해당 플랫폼의 표준 관행을 따르도록 이 과정을 자동으로 처리하는 것을 목표로 합니다. Qt는 Apple의 접근성 프레임워크를 사용하여 장애가 있는 사용자에게 접근성을 제공합니다.

라이브러리 및 배포 지원

Qt는 프레임워크(Frameworks) 및 번들(bundles)과 같은 macOS 구조를 지원합니다. 이러한 구조는 애플리케이션 배포에 직접적인 영향을 미치므로 이를 숙지하는 것이 중요합니다.

Qt는 배포 과정을 간소화하기 위해 macdeployqt라는 배포 도구를 제공합니다. ‘Qt for macOS - 배포’ 문서에서는 배포 과정을 더 자세히 다루고 있습니다.

프레임워크로서의 Qt 라이브러리

기본적으로 Qt는 일련의 프레임워크 형태로 빌드됩니다. 프레임워크는 macOS에서 라이브러리를 배포하는 데 선호되는 방식입니다. Apple의 ‘프레임워크 프로그래밍 가이드’ 사이트에서 프레임워크에 대한 훨씬 더 자세한 정보를 확인할 수 있습니다.

프레임워크는 항상 라이브러리의 릴리스 버전과 링크된다는 점을 기억하는 것이 중요합니다. Qt 프레임워크의 디버그 버전을 사용하려면, DYLD_IMAGE_SUFFIX 환경 변수를 사용하여 디버그 버전이 로드되도록 해야 합니다:

export DYLD_IMAGE_SUFFIX=_debug

또는 Apple의 "Debugging Magic" 기술 노트에 설명된 대로 디버그 버전과 릴리스 버전을 일시적으로 서로 바꿔 사용할 수도 있습니다.

프레임워크를 사용하지 않으려면, Qt를 -no-framework 로 구성하기만 하면 됩니다.

./configure -no-framework

번들 기반 라이브러리

macOS 애플리케이션 번들(애플리케이션 디렉터리) 내에 동적 라이브러리를 사용하려면, 애플리케이션 번들 디렉터리 내에 'Frameworks'라는 이름의 하위 디렉터리를 생성하고 해당 위치에 동적 라이브러리를 배치하십시오. 애플리케이션은 동적 라이브러리의 설치 이름이 @executable_path/../Frameworks/libname.dylib 형식일 경우 해당 라이브러리를 찾을 수 있습니다.

qmake 와 Makefile을 사용하는 경우, 다음 설정을 적용하십시오: 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 파일에서 -r 플래그를 설정하고, LFLAGS 설정을 지정해야 합니다.

초기화 순서

dyld(1) 는 애플리케이션에 링크된 순서대로 전역 정적 초기화자를 호출합니다. 라이브러리가 Qt에 링크되어 있고 (자신의 라이브러리에 있는 전역 초기화자를 통해) Qt의 전역 변수를 참조하는 경우, 해당 라이브러리에 링크하기 전에 애플리케이션을 Qt에 먼저 링크해야 합니다. 그렇지 않으면 Qt의 전역 초기화자가 아직 호출되지 않았기 때문에 정의되지 않은 동작이 발생할 수 있습니다.

컴파일 시 플래그

macOS 전용 코드를 정의할 때 다음 플래그가 유용합니다:

  • Q_OS_DARWIN Qt가 macOS나 iOS와 같은 Darwin 기반 시스템에서 실행되고 있음을 감지하면 정의됩니다.
  • Q_OS_MACOS macOS 시스템에서 실행 중일 때 정의됩니다.

참고: Qt 5 이후 버전에서는` Q_WS_MAC `이 더 이상 정의되지 않습니다.

특정 버전의 macOS용 코드를 정의하려면 /usr/include/AvailabilityMacros.h에 정의된 가용성 매크로를 사용하십시오.

QSysInfo 및 QOperatingSystemVersion 문서에는 런타임 버전 확인에 대한 정보가 포함되어 있습니다.

macOS 네이티브 API 액세스

번들 경로 액세스

macOS 애플리케이션은 디렉터리(확장자가 .app인) 형태로 구성됩니다. 이 디렉터리에는 하위 디렉터리와 파일이 포함되어 있습니다. 플러그인이나 온라인 문서와 같은 항목을 이 번들 내에 배치하는 것이 유용할 수 있습니다. 다음 코드는 애플리케이션 번들의 경로를 반환합니다:

#ifdef Q_OS_MAC
    QString bundlePath = QString::fromNSString(NSBundle.mainBundle.bundlePath);
    qDebug() << "Bundle path =" << bundlePath;
#endif

NSBundle API 사용에 대한 자세한 내용은 Apple 개발자 웹사이트를 참조하십시오.

QCoreApplication::applicationDirPath()를 사용하면 번들 내 바이너리의 경로를 확인할 수 있습니다.

네이티브 Cocoa 패널 사용

QEventLoop::execQt의 이벤트 디스패처는 Cocoa가 제공하는 것보다 더 유연하며, 사용자는 화면에 모달 대화 상자가 표시되어 있는지 여부를 신경 쓸 필요 없이 이벤트 디스패처를 회전시킬 수 있습니다(이 점이 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

-single_module 옵션을 사용하여 Qt를 다시 링크하십시오. 이 문제는 MySQL 드라이버를 Qt에 빌드할 때만 발생합니다. 플러그인이나 정적 빌드에는 영향을 미치지 않습니다.

D-Bus 및 macOS

QtDBus 모듈은 macOS에서 기본적으로 libdbus-1 라이브러리를 동적으로 로드합니다. 즉, QtDBus 모듈을 링크한 애플리케이션은 해당 라이브러리가 없는 macOS 시스템에서도 로드되지만, 어떤 D-Bus 서버에도 연결할 수 없으며 QDBusServer 를 사용하여 서버를 열 수도 없습니다.

D-Bus 기능을 사용하려면 Homebrew, Fink 또는 MacPorts 등을 통해 libdbus-1 라이브러리를 설치해야 합니다. 다른 시스템에 배포하는 경우, 해당 라이브러리를 애플리케이션 번들에 포함하는 것이 좋습니다. 또한, macOS에는 시스템 버스가 없으며, session bus는 launchd가 이를 관리하도록 구성된 후에만 시작된다는 점에 유의하십시오.

  • 네이티브 메뉴 바( QMenu )가 Mac 네이티브 메뉴 바로 변환될 때, 두 개 이상의 키 입력이 필요한 단축키(QKeySequence)가 설정된 네이티브 메뉴 바( QMenu )의 동작은 올바르게 표시되지 않습니다. 첫 번째 키만 표시됩니다. 그러나 다른 모든 플랫폼과 마찬가지로 단축키는 여전히 작동합니다.
  • QMenu 네이티브 메뉴 바에서 사용되는 객체는 일반적인 이벤트 핸들러를 통해 Qt 이벤트를 처리할 수 없습니다. 이러한 변경 사항을 알림받으려면 메뉴 자체에 델리게이트를 설정하십시오. 또는 QMenu::aboutToShow() 및 QMenu::aboutToHide() 시그널을 사용하여 메뉴의 표시 여부를 추적하는 방법을 고려해 보십시오. 이 방법은 Qt가 지원하는 모든 플랫폼에서 작동하는 해결책이 될 것입니다.
  • 기본적으로 Qt는 CMD+Q 단축키에 반응하는 네이티브 종료 메뉴 항목을 생성합니다. QAction::QuitRole 역할에 대한 QAction 을 생성하면 해당 메뉴 항목이 대체됩니다. 따라서 대체 액션은 QCoreApplication::quit 슬롯이나, 애플리케이션을 종료하는 사용자 정의 슬롯 중 하나에 연결되어야 합니다.

네이티브 위젯

Qt XML은 Qt::Sheet 창 플래그로 표시되는 시트를 지원합니다.

일반적으로 네이티브 macOS 애플리케이션을 언급할 때, ‘네이티브’란 중개 계층을 사용하는 애플리케이션이 아니라 기본 윈도우 시스템과 직접 연동되는 애플리케이션을 의미합니다. Qt 애플리케이션은 Cocoa 애플리케이션과 마찬가지로 동등한 권한을 가진 애플리케이션으로 실행됩니다. 우리는 운영 체제와 통신하기 위해 내부적으로 Cocoa를 사용합니다.

심볼 가시성 경고

C++ 라이브러리 링크 과정에서 함수와 객체는 ‘심볼(symbol)’로 지칭됩니다. 심볼은 ‘ 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)

© 2026 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.