CMake-gui를 Qt5환경으로 빌드하기

빌드하게 매우 귀찮아 CMake를 MSI 패키지로 설치를 하다가 매우 오랜만에 직접 빌드해보았다. (대신 MSYS2를 깔아야한다.) 전에는 Qt4를 사용했기때문에 쉽게 빌드된거같은데 Qt5를 사용한 GUI 환경을 빌드하려하니 구글링도 안되어 꽤나 삽질했다. CMakeLists.txt를 열어보면 Qt5를 지원하는 모양이였지만 find_package(Qt5Widgets QUIET)구문이 어떻게 동작하는지 알 수 없어 리눅스 환경에서 bootstrap을 실행하여 생성된 CMakeCache.txt 파일을 직접 분석하여 찾아본 결과 -DBUILD_QtDialog=ON -DQT_QMAKE_EXECUTABLE=D:\OpenSource\Qt5.15.0.x64\bin\qmake.exe -DQt5Widgets_DIR=D:\OpenSource\Qt5.15.0.x64\lib\cmake\Qt5Widgets 이렇게 변수를 설정하면 된다는것을 알게되었다.

자세한 내용은 CMake 소스코드에서 README.rst 파일을 열어보면 되고 이미 빌드된 CMake가 없는 상태에서 간략한 빌드과정은

MSYS2를 설치한다. 설치완료 후 MSYS2를 실행하고 pacman -S --needed git base-devel mingw-w64-x86_64-gcc 명령으로 필요한 패키지를 설치한다. (git는 필요없어보이지만 README.rst에서 설치하라고하니..) 그 후 exit 명령으로 쉘을 종료하고 시작메뉴에서 MSYS2 MinGW 64bit를 실행한다. 이렇게 기본 빌드환경은 끝.

3.18.1버전의 cmake를 압축 풀었다면 폴더 이름이 cmake-3.18.1일것이다. 압축 푼 경로가 D:\OpenSource\cmake-3.18.1 이라면 cd /d/OpenSource 명령으로 폴더 이동 후 임의 폴더 생성한다. (cmake-build1로 만들었다.) cmake-build1 폴더에서 ../cmake-3.18.1/configure –prefix=/d/OpenSource/cmake-bootstrap 명령을 실행 후 make && make install 명령을 실행하여 빌드 및 바이너리를 설치한다. 이렇게 bootstrap 환경은 완료.

Visual Studio의 64비트 툴 콘솔을 실행하여 set PATH=%PATH%;C:\msys64\mingw64\bin 명령을 수행 후(msys2를 기본 경로에 설치했을경우) D:\OpenSource\cmake-build2 폴더를 생성 & 이동하여 ../cmake-bootstrap/bin/cmake ..\cmake-3.18.1 -DCMAKE_INSTALL_PREFIX=D:\OpenSource\cmake -DBUILD_QtDialog=ON -DQT_QMAKE_EXECUTABLE=D:\OpenSource\Qt5.15.0.x64\bin\qmake.exe -DQt5Widgets_DIR=D:\OpenSource\Qt5.15.0.x64\lib\cmake\Qt5Widgets 이렇게 실행하면 Visual Studio Solution 파일(CMake.sln)이 생성된다. (nmake 타겟으로 생성가능하지만 VS 솔루션 파일에서 빌드하면 병렬빌드가 되기에 그냥 기본 타겟으로 생성하였다.) 이제 솔루션 파일을 열고 빌드 형식을 Release / x64로 설정하여 CMakePredefinedTargets/ALL_BUILD 프로젝트를 우클릭하여 빌드 메뉴를 선택한다. 모두 빌드되면 CMakePredefinedTargets/INSTALL 프로젝트를 우클릭하여 빌드 메뉴를 선택하면 CMAKE_INSTALL_PREFIX로 설정된 D:\OpenSource\cmake에 CMake가 설치된다.

D:\OpenSource\cmake\bin\cmake-gui.exe 파일을 실행하면 DLL 종속성 오류가 뜰것이다. 명령 프롬포트에서 D:\OpenSource\cmake\bin 폴더로 이동 후 D:\OpenSource\Qt5.15.0.x64\bin\windeployqt.exe cmake-gui.exe 명령을 실행하면 종속된 파일이 전부 복사되고 이제 cmake-gui.exe를 실행하면 아래와같이 GUI 환경의 cmake 프로그램이 실행된다.

이제 필요한것들을 빌드해야겠다. 실행도 깔끔하게 잘 되니 이것으로 끝!

mariadb 빌드 시 외부 라이브러리 링크

원래부터 그랬는지 기억이 나지않지만 cmake기반의 빌드 시스템이 필수가 되었다. 기본 옵션으로는 TokuDB를 위해 jemalloc가 필요한데… TokuDB를 사용하지않으려면 “cmake -DWITH_JEMALLOC=no” 이렇게 실행하여 Makefile을 생성하면 되지만 임시로 이것저것 굴리기위한 일반 사용자 계정으로 돌릴 로컬 디비를 구측하는 중이라 사용해보고싶었다.

소스코드 및 빌드 경로: /opt/mariadb-local/src
PREFIX 경로: /opt/mariadb-local/usr

jemalloc는 /opt/mariadb-local/src에 다운로드하여 빌드 및 설치(./configure --prefix=/opt/mariadb-local/usr && make && make install)

mariadb는
cmake -DBUILD_CONFIG=mysql_release -DWITH_JEMALLOC=yes -DCMAKE_INSTALL_PREFIX=/opt/mariadb-local/usr -DCMAKE_REQUIRED_FLAGS="-I/opt/mariadb-local/usr/include" -DCMAKE_REQUIRED_LIBRARIES="-L/opt/mariadb-local/usr/lib"
명령으로 Makefile 생성. 환경변수는 이곳에서 참조하였다. 이제 빌드하면 DokuDB를 사용가능한 mariadb로 빌드가된다. 아마 더 필요한 라이브러리가 있다면 /opt/mariadb-local/usr에 필요한 라이브러리를 더 빌드하여 설치하면 될것으로 보인다.

추가

모듈을 링크할 때 jemalloc를 링크할 수 없는 오류가 발생하므로 –DCMAKE_MODULE_LINKER_FLAGS="-L/opt/mariadb-local/usr/lib" 옵션을 추가해야함.

기본테이블 생성을 위한 mysql_install_db 스크립트 실행은 아래와같이 실행 (소스코드는 mariadb-10.4.11 폴더이지만 mariadb-10.4.11-build 에서 빌드하였다.)
/opt/mariadb-local/usr $ ./scripts/mysql_install_db --builddir=/opt/mariadb-local/src/mariadb-10.4.11-build --basedir=/opt/mariadb-local/usr --datadir=/opt/mariadb-local/usr/data --defaults-file=/opt/mariadb-local/usr/my.cnf --user=$LOGNAME

첫 실행시엔 비밀번호가 설정되어있지않으므로 root 계정으로 mysql -h 127.0.0.1 -P 3307 -u root와같이 실행하여 암호를 바꿔야한다. (localhost로 hostname을 넘기면 포트번호가 무시되는것같다.) 만약 root권한을 가질 수 없다면 mysql_install_db에 --auth-root-authentication-method=normal 옵션을 추가하여 실행해야한다. (이미 설치되었다면 data 폴더의 내용을 지우고 실행해야된다.)

my.cnf 파일의 내용
[client]
port=3307
socket=/opt/mariadb-local/usr/mariadb.sock

[mysqld]
port=3307
socket=/opt/mariadb-local/usr/mariadb.sock
datadir=/opt/mariadb-local/usr/data
language=/opt/mariadb-local/usr/share/korean

로컬용 실행 스크립트
#!/bin/sh
./bin/mariadbd --defaults-file=/opt/mariadb-local/usr/my.cnf

로컬용 중지 스크립트
#!/bin/sh
./bin/mariadb-admin --defaults-file=/opt/mariadb-local/usr/my.cnf shutdown

실행결과
iruis@tun /opt/mariadb-local/usr $ ./run-mariadb.sh
2019-12-22  5:52:20 0 [Note] ./bin/mariadbd (mysqld 10.4.11-MariaDB) starting as process 14794 …
2019-12-22  5:52:20 0 [Note] InnoDB: Using Linux native AIO
2019-12-22  5:52:20 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
2019-12-22  5:52:20 0 [Note] InnoDB: Uses event mutexes
2019-12-22  5:52:20 0 [Note] InnoDB: Compressed tables use zlib 1.2.11
2019-12-22  5:52:20 0 [Note] InnoDB: Number of pools: 1
2019-12-22  5:52:20 0 [Note] InnoDB: Using SSE2 crc32 instructions
2019-12-22  5:52:20 0 [Note] mariadbd: O_TMPFILE is not supported on /tmp (disabling future attempts)
2019-12-22  5:52:20 0 [Note] InnoDB: Initializing buffer pool, total size = 128M, instances = 1, chunk size = 128M
2019-12-22  5:52:20 0 [Note] InnoDB: Completed initialization of buffer pool
2019-12-22  5:52:20 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread priority can be changed. See the man page of setpriority().
2019-12-22  5:52:20 0 [Note] InnoDB: 128 out of 128 rollback segments are active.
2019-12-22  5:52:20 0 [Note] InnoDB: Creating shared tablespace for temporary tables
2019-12-22  5:52:20 0 [Note] InnoDB: Setting file ‘./ibtmp1’ size to 12 MB. Physically writing the file full; Please wait …
2019-12-22  5:52:20 0 [Note] InnoDB: File ‘./ibtmp1’ size is now 12 MB.
2019-12-22  5:52:20 0 [Note] InnoDB: Waiting for purge to start
2019-12-22  5:52:20 0 [Note] InnoDB: 10.4.11 started; log sequence number 60736; transaction id 23
2019-12-22  5:52:20 0 [Note] InnoDB: Loading buffer pool(s) from /opt/mariadb-local/usr/data/ib_buffer_pool
2019-12-22  5:52:20 0 [Note] Plugin ‘FEEDBACK’ is disabled.
2019-12-22  5:52:20 0 [Note] InnoDB: Buffer pool(s) load completed at 191222  5:52:20
2019-12-22  5:52:20 0 [Note] Server socket created on IP: ‘::’.
2019-12-22  5:52:20 0 [Note] Reading of all Master_info entries succeeded
2019-12-22  5:52:20 0 [Note] Added new Master_info ” to hash table
2019-12-22  5:52:20 0 [Note] ./bin/mariadbd: ready for connections.
Version: ‘10.4.11-MariaDB’  socket: ‘/opt/mariadb-local/usr/mariadb.sock’  port: 3307  MariaDB Server

최근 버전에서는 user 테이블의 암호를 update 쿼리로 변경이 불가능하게 되었다. 무조건 root 쉘에서 /opt/mariadb-local/usr/bin/mariadb-secure-installation --defaults-file=my.cnf 와같이 실행하여 별도의 설치가 필요한데… root권한을 가지지 못한다면 datadir에 해당되는 폴더를 제거한 후 mysql_install_db 스크립트에 --auth-root-authentication-method=normal 옵션을 붙여서 설치해야 됨.

맥에서 동적 라이브러리 참조문제 (Reason: image not found)

ffmpeg를 사용해볼 겸 테스트용 프로젝트를 생성하여 아래와같이 구성.

빌드까지 문제가 없었으나 실행시키면 “Reason: image not found“라는 에러가 발생.

뜬금없이 libswresample.3.dylib를 찾을 수 없다는 에러가 발생한다. 구글링 해본 결과 otool과 install_name_tool을 사용하여 해결해야하는것으로 결론.

실행파일과 dylib파일을 otool -L 명령으로 확인해보면 라이브러리 위치를 ffmpeg를 빌드할 때 prefix 대상 위치로 참조하도록 되어있다. libswresample.3.5.100.dylib 파일을 확인하면 나타나는 항목 중 첫번째 항목은 LC_ID_DYLIB, 두번째 부터 나타나는 항목은 LC_LOAD_DYLIB으로 차이가 있다. (직접 확인하려면 otool -L 대신 otool -l 옵션으로 실행하면 확인가능) 이중 LC_ID_DYLIB는 바이너리가 생성될 때 라이브러리가 참조되는 경로로 링크가되는것으로 보인다. 이 경로는 install_name_tool -id “라이브러리 경로” “라이브러리 파일”로 지정 가능하고 LC_LOAD_DYLIB는 바이너리에서 의존하는 라이브러리며 install_name_tool -change “기존경로” “새로운경로” “라이브러리 파일” 명령으로 변경 가능하다. (경로는 상대경로를 위한 예약어 비슷한 키워드가 있다. @executable_path, @loader_path, @rpath이다. 각각 의미는 구글링으로 패스.)

install_name_tool -id @executable_path/../Frameworks/libavcodec.58.54.100.dylib libavcodec.58.54.100.dylib
install_name_tool -change /Users/iruis/OpenSource/ffmpeg-4.2.1-lgpl/output/lib/libswresample.3.dylib @executable_path/../Frameworks/libswresample.3.5.100.dylib libavcodec.58.54.100.dylib

위와같은 명령으로 라이브러리 경로를 하나하나 바꾸고나면 맥의 패키지 내 복사되는 라이브러리가 참조되어 정상 로딩되어 실행된다. 덕분에 거의 반나절을 삽질한건 안비밀.

IR 송수신 모듈 (YS-IRTM)

우리나라 쇼핑몰에서는 S148 IR이라고 붙어있는곳도 있다.

IR 신호의 인코딩/디코딩을 해주기때문에 편리할거같아서 샀지만 NEC 포맷을 지키지않는 제품이 의외로 많은거같다. LG 에어컨, 선풍기리모컨이 그러한 경우. 덕분에 신호를 디코딩하지 못한다(…). NEC 포맷와 일치하지않아도 8비트 체계로 데이터가 들어오면 포맷이 맞지않아도 출력해준다면 좋았을텐데 아쉽다.

본래는 집 밖에서 에어컨을 키고 들어가기위해 뭐 좀 만들어보고 싶었는데 아무레도 송신모듈, 수신모듈, 아두이노를 써야할지도 모르겠다는 생각이 든다.

결론은 리모컨을 편하게 만들어보려했지만 실패.

Qt5 (5.11.2 기준) MySQL 함께 빌드

1. MySQL 홈페이지에서 MySQL 서버 다운로드
https://dev.mysql.com/downloads/windows/installer/8.0.html
Connector/C++은 Qt의 SQL 플러그인에서 지원안하며, Connector/C는 서버 패키지에 포함되어있다… 다른건 다 개별로 배포하면서 C 라이브러리는 서버 패키지에서 설치하도록 변경되었는지는 이유를 모르겠다.

2. Connector/C 설치
Custom 설치로 선택 후 아래와같이 트리뷰를 펼치면 x64, x86 두가지 아키텍처가 있으며 이 중 한가지만 설치가능하다(…)

필요한 아키텍처를 선탁하여 설치하면 각각 아래 경로에 설치된다. (8버전 기준)
x86: C:\Program Files (x86)\MySQL\MySQL Connector C 6.1
x64: C:\Program Files\MySQL\MySQL Connector C 6.1
폴더가 서로 다른데 왜 둘 다 설치 못하는지는 미지수.

3. 필수 유틸 설치
Python 2.7버전, 그리고 펄을 다운받아 설치한다. 설치 후 콘솔에서 python, perl 실행해보고 INCLUDE, LIB 변수 값 수정.

4. 환경변수 설정
명령 도구모음 x86 또는 x64를 실행한 후 아래와같이 실행하여 환경변수에 추가.
x86:
set INCLUDE=%INCLUDE%;C:\Program Files (x86)\MySQL\MySQL Connector C 6.1\include
set LIB=%LIB%;C:\Program Files (x86)\MySQL\MySQL Connector C 6.1\lib

x64:
set INCLUDE=%INCLUDE%;C:\Program Files\MySQL\MySQL Connector C 6.1\include
set LIB=%LIB%;C:\Program Files\MySQL\MySQL Connector C 6.1\lib

5. 빌드 준비
configure -opensource -confirm-license -prefix D:\OpenSource\Qt5.11.2.x86 -nomake examples -nomake tests -opengl dynamic -mediaplayer-backend wmf -force-debug-info
소스를 압축푼 후 해당 경로에서 위와같이 입력한다.
D:\OpenSource
– Qt5.11.2.x86.build
– qt-everywhere-src-5.11.2
이와같은 구조라면 ..\qt-everywhere-src-5.11.2\configure -opensource…. 와 같이 입력한다.
x86과 x64 타겟 둘 다 빌드하려면 이렇게 쉐도우빌드하는게 좋다. (이미 빌드, configure 완료 된 설정과 충돌이 발생하지 않기때문.) 또한 prefix를 지정하면 빌드 완료 후 nmake install하여 헤더와 바이너리파일을 소스와 오브젝트 파일 따로 둘 수 있다.

아래는 MySQL을 포함 한 configure 결과내용.

Configure summary:

Build type: win32-msvc (x86_64, CPU features: sse sse2)
Configuration: sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways shared debug_and_release release debug build_all c++11 c++14 c++1z concurrent dbus no-pkg-config release_tools stl
Build options:
  Mode ................................... debug and release (with debug info); default link: debug; optimized tools

... 중략 ...

Qt Gui:
  Accessibility .......................... yes
  FreeType ............................... yes
    Using system FreeType ................ no
  HarfBuzz ............................... yes
    Using system HarfBuzz ................ no
  Fontconfig ............................. no
  Image formats:
    GIF .................................. yes
    ICO .................................. yes
    JPEG ................................. yes
      Using system libjpeg ............... no
    PNG .................................. yes
      Using system libpng ................ no
  EGL .................................... yes
  OpenVG ................................. no
  OpenGL:
    ANGLE ................................ yes
    Combined ANGLE Library ............... no
    Desktop OpenGL ....................... no
    Dynamic OpenGL ....................... yes
    OpenGL ES 2.0 ........................ no
    OpenGL ES 3.0 ........................ no
    OpenGL ES 3.1 ........................ no
    OpenGL ES 3.2 ........................ no
  Vulkan ................................. no
  Session Management ..................... yes

... 중략 ...

Qt Sql:
  DB2 (IBM) .............................. no
  InterBase .............................. no
  MySql .................................. yes
  OCI (Oracle) ........................... no
  ODBC ................................... yes
  PostgreSQL ............................. no
  SQLite2 ................................ no
  SQLite ................................. yes
    Using system provided SQLite ......... no
  TDS (Sybase) ........................... no

... 중략 ...

Qt Multimedia:
  ALSA ................................... no
  GStreamer 1.0 .......................... no
  GStreamer 0.10 ......................... no
  Video for Linux ........................ no
  OpenAL ................................. no
  PulseAudio ............................. no
  Resource Policy (libresourceqt5) ....... no
  Windows Audio Services ................. yes
  DirectShow ............................. yes
  Windows Media Foundation ............... yes
  Media player backend ................... Windows Media Foundation
Qt WebEngine:
  Embedded build ......................... no
  Pepper Plugins ......................... yes
  Printing and PDF ....................... yes
  Proprietary Codecs ..................... no
  Spellchecker ........................... yes
  Native Spellchecker .................... no
  WebRTC ................................. yes
  Use System Ninja ....................... no
  Geolocation ............................ yes
  Use v8 snapshot ........................ yes

Note: No wayland-egl support detected. Cross-toolkit compatibility disabled.

Qt is now configured for building. Just run 'nmake'.
Once everything is built, you must run 'nmake install'.
Qt will be installed into 'D:\OpenSource\Qt5.11.2.x64'.

Prior to reconfiguration, make sure you remove any leftovers from
the previous build.

만약 MySQL 부분이 활성화 안되어 환경설정 후 그 부분만 다시 체크되도록 하려면 config.cache 파일을 메모장에서 열어 아래와 같이 cache.mysql로 시작하는 라인을 전부 지우고 다시 configure하면 된다.

cache.mysql._KEYS_ = result msgs source sources.5.libs sources.5.includedir sources.5.cflags sources.5.version sources.5.export
cache.mysql.result = true
cache.mysql.msgs = "Trying source 0 (type mysqlConfig) of library mysql ..." "mysql_config not found." "  => source produced no result." "Trying source 1 (type mysqlConfig) of library mysql ..." "mysql_config not found." "  => source produced no result." "Trying source 2 (type mysqlConfig) of library mysql ..." "mysql_config not found." "  => source produced no result." "Trying source 3 (type mysqlConfig) of library mysql ..." "mysql_config not found." "  => source produced no result." "Trying source 4 (type inline) of library mysql ..." "  => source failed condition \'!config.win32\'." "Trying source 5 (type inline) of library mysql ..." "+ cd /d D:\\OpenSource\\Qt5.11.2.x86.build\\config.tests\\mysql && D:\\OpenSource\\Qt5.11.2.x86.build\\qtbase\\bin\\qmake.exe \"CONFIG -= qt debug_and_release app_bundle lib_bundle\" \"CONFIG += shared warn_off console single_arch\" \"LIBS += -llibmysql\" D:/OpenSource/Qt5.11.2.x86.build/config.tests/mysql" "+ cd /d D:\\OpenSource\\Qt5.11.2.x86.build\\config.tests\\mysql && set MAKEFLAGS=& nmake" "> Microsoft(R) Program Maintenance Utility ���� 14.16.27024.1" "> Copyright (c) Microsoft Corporation. All rights reserved." "> $$escape_expand(\\t)cl -c -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W0 -EHsc /Fdmysql.vc.pdb -DUNICODE -D_UNICODE -DWIN32 -D_ENABLE_EXTENDED_ALIGNED_STORAGE -I. -ID:\\OpenSource\\qt-everywhere-src-5.11.2\\qtbase\\mkspecs\\win32-msvc -Fo @C:\\Users\\star\\AppData\\Local\\Temp\\nm8248.tmp" "> main.cpp" "> $$escape_expand(\\t)link /NOLOGO /DYNAMICBASE /NXCOMPAT /DEBUG /SUBSYSTEM:CONSOLE \"/MANIFESTDEPENDENCY:type=\'win32\' name=\'Microsoft.Windows.Common-Controls\' version=\'6.0.0.0\' publicKeyToken=\'6595b64144ccf1df\' language=\'*\' processorArchitecture=\'*\'\" /MANIFEST:embed /OUT:mysql.exe @C:\\Users\\star\\AppData\\Local\\Temp\\nm869F.tmp" " => source accepted."
cache.mysql.source = 5
cache.mysql.sources.5.libs = -llibmysql
cache.mysql.sources.5.includedir = 
cache.mysql.sources.5.cflags = 
cache.mysql.sources.5.version = 
cache.mysql.sources.5.export = 

6. 빌드
qt에서 제공하는 jom을 쓴다면 jom, 아니라면 nmake 명령으로 빌드. 주위할 점으로 시스템 로케일을 영어(미국)으로 하는게 좋다. 웹킷은 경고도 에러로 처리하고 이 편이 훨씬 깔끔하게 한번에 빌드된다.

7. 기타
귀차니즘 덕분에 이정도로 마무리. 더 자세한 내용은 이곳 참조.