Qt 5.12.12 Arm 타겟 빌드 (Win32 호스트)

참조사항

Qt 버전별 툴체인 권장버전: https://wiki.qt.io/MinGW
MinGW-w64의 스레드 모델, 예외 처리 모델의 자세한 내용: http://blog.tcltk.co.kr/?p=3836

필요환경

Perl: https://strawberryperl.com/releases.html
Python: https://www.python.org/downloads/
MinGW: https://sourceforge.net/projects/mingw-w64/files/
GCC (Raspberry Pi): https://gnutoolchains.com/raspberry/

Perl이나 Python이 이미 시스템에 설치되어 있다면 환경변수에 경로가 설정되어 있는지 확인하여 그대로 사용하면 되며, 시스템에 설치하지 않고 Qt 빌드에 잠깐 사용을 원한다면 Perl은 Portable Edition, Python 3는 Embeddable Package로 받으면 된다.

이 글에서 압축을 푸는 위치는 D:\OpenSource를 기준으로 한다. 단 Python은 압축 파일 내 폴더없이 압축되어 있으므로 압축 해제 시 ‘여기에 압축 풀기’가 아닌 ‘python-3.9.9-embed-amd64에 압축풀기’와 같은 방법으로 해제한다.

환경변수

set PATH=D:\OpenSource\mingw64\bin;D:\OpenSource\strawberry-perl-5.32.1.1-64bit-portable\perl\bin;D:\OpenSource\python-3.9.9-embed-amd64;%PATH%

Perl 5.32.1.1 64bit Portable Edition, Python 3.9.9 Embeddable Package, MinGW 는 참조사항의 링크 내용을 따라서 버전을 선택하면 되며 현재 글에서 사용한 컴파일러 posix보다는 더 나은 퍼포먼스를 위해 x86_64-win32-seh 사용, GCC (Raspberry Pi)는 대상 OS에 맞는 버전으로 사용.

참고: 윈 10 최근 버전은 python 명령이 스토어에 연결된 단축 명령 형식으로 재공되므로 원하지 않는 오류가 발생할 수 있다. 이러한 경우가 발생하는것을 원하지 않는다면 시작 – 설정 실행, 앱 항목에서 ‘앱 및 기능’ 레이블의 하단 ‘앱 실행 별칭’ 링크로 이동하여 ‘앱 설치 관리자’항목으로 지정된 python.exe와 python3.exe 항목을 ‘끔’으로 변경하면 별칭과의 충돌을 피할 수 있다.

빌드설정

..\qt-everywhere-src-5.12.12\configure -opensource -confirm-license -platform win32-g++ -device linux-rasp-pi3-g++ -device-option CROSS_COMPILE=C:\SysGCC\raspberry\bin\arm-linux-gnueabihf- -sysroot C:/SysGCC/raspberry/arm-linux-gnueabihf/sysroot -prefix /opt/Qt5.12.12 -extprefix D:\OpenSource\Qt5.12.12.gcc-arm -hostprefix D:\OpenSource\Qt5.12.12.gcc-arm -release -eglfs -opengl es2 -no-use-gold-linker -nomake examples -nomake tests -skip qtscript

shadow 빌드를 기준으로 한다. (설정이 잘못되거나 처음부터 다시 빌드해야 할 경우 빌드 폴더를 지우고 다시 폴더를 만들어서 진행하면 make distclean보다 훨씬 깔끔하게 다시 빌드할 수 있기때문이다.)

Qt 소스경로: D:\OpenSource\qt-everywhere-src-5.12
Qt빌드경로: D:\OpenSource\Qt5.12.12.gcc-arm.build
Qt설치경로: D:\OpenSource\Qt5.12.12.gcc-arm

gold 링커가 더 성능 좋다고하지만 MinGW 쉘 환경이 아니라면 링커가 실행되지 않으므로 -no-use-gold-linker 옵션을 추가, device 값은 linux-rasp-pi3-vc4-g++도 있으나 손봐야 하는 환경도 있고 타겟 보드에 Qt를 빌드하여 넣는 것이 아닌 윈도에서 타겟 보드에서 실행할 프로그램을 크로스 빌드 하기위한 Qt 이므로 별 의미 없다.

examples는 필요한 예제를 나중에 따로 빌드해도 되고 꽤나 시간을 많이 잡아먹기때문에 nomake 처리하였고, 크로스 빌드에선 tests를 빌드하는지 모르겠지만 테스트도 보통 시간을 많이 잡아먹기 때문에 일단 nomake에 추가.

sysroot 옵션은 VideoCore의 그래픽 가속 라이브러리 링크를 위해서이다. 이 옵션이 없으면 OpenGL ES 인터페이스가 비활성화된다. X Window를 사용하지않고 eglfs를 사용한다면 필수.

sysroot 옵션을 지정할 경우 install 경로가 $sysroot/$prefix 으로 되므로 prefix는 임의로 /opt/Qt5.12.12 로 지정하였다. 실제 설치위치는 extprefix와 hostprefix로 지정한다. (extprefix는 라이브러리, hostprefix는 qmake등 호스트 레벨의 실행파일의 설치 위치)

device 옵션으로 pi3를 지정하면 이곳의 글 6번 항목 내용처럼 qtscript 모듈에서 빌드 오류가 뜬다. 쓰지않으니 skip 처리하였다.

빌드 및 바이너리 설치

아래와같이 명령어를 입력하면 된다. j옵션의 숫자는 CPU 스레드 수 또는 +1 정도면 적당하다.

mingw32-make -j6
mingw32-make install

DLL 복사

G++로 빌드된 바이너리는 libstdc++이 필요하다. 해당 런타임은 D:\OpenSource\mingw64\bin 폴더에서 libgcc_s_seh-1.dll, libstdc++-6.dll 두 파일을 D:\OpenSource\Qt5.12.12.gcc-arm\bin에 복사하면 된다. posix 모델을 사용하는 MinGW를 사용하였으면 libwinpthread-1.dll 파일도 필요할것으로 보인다.

Continue reading Qt 5.12.12 Arm 타겟 빌드 (Win32 호스트)

ARM 네이티브 툴체인 만들기

buildroot로 만든 라즈베리 파이의 파일 시스템에서 파이썬으로 만들어진 데모를 돌리기위해(pip로 설치하는 모듈이 C 코드를 빌드하기때문) 툴체인 빌드에 끝까지 성공하여 과정을 기록. (참고: 구버전 buildroot는 타겟 파일 시스템에서 실행되는 컴파일러를 지원 한것으로 보인다. 아쉬운 부분.)

커널 버전은 x.y.z 중 x.y까지만 동일, glibc 버전은 타겟 시스템의 glibc 버전 2.30과 동일하게 사용했다. 대상 시스템보다 높은 버전의 glibc를 사용하여 툴체인을 만들었다면 bison, python등에서 공유 라이브러리 libc.so.6 참조에서 문제가 발생한다. (또는 glibc의 버전이 동일해도 configure 옵션에 따라서 다른 문제가 발생할수도 있다.) 만약 취미삼아 최신 glibc를 써보고싶다면 대상 시스템에서 원하는 버전의 glibc를 --prefix=/usr로 빌드 후 설치하여 업데이트 할 수 있겠지만 특별히 의미도 없고 추천할 수 없다.

Continue reading ARM 네이티브 툴체인 만들기

ARM 타겟 PHP 빌드 오류 해결

라즈베리파이에 올릴 용도로 buildroot의 LTS판 최신버전(2020.02.8)을 php 포함하여 빌드하는 중 아레와같은 빌드 에러가 발생하였다.

ext/standard/crc32.c:48:10: error: ‘armv8-a’ does not support feature ‘nothing’
 # pragma GCC target ("+nothing+crc")
          ^~~
ext/standard/crc32.c:48:10: note: valid feature names are: crc simd crypto nocrypto nofp
ext/standard/crc32.c:48:10: error: ‘armv8-a’ does not support feature ‘nothing’
ext/standard/crc32.c:48:10: note: valid feature names are: crc simd crypto nocrypto nofp
ext/standard/crc32.c:49:1: error: ‘armv8-a’ does not support feature ‘nothing’
 static uint32_t crc32_aarch64(uint32_t crc, char *p, size_t nr) {
 ^~~~~~
ext/standard/crc32.c:49:1: note: valid feature names are: crc simd crypto nocrypto nofp
ext/standard/crc32.c:49:1: error: ‘armv8-a’ does not support feature ‘nothing’
ext/standard/crc32.c:49:1: note: valid feature names are: crc simd crypto nocrypto nofp
ext/standard/crc32.c: In function ‘crc32_aarch64’:
ext/standard/crc32.c:49:1: error: ‘armv8-a’ does not support feature ‘nothing’
ext/standard/crc32.c:49:1: note: valid feature names are: crc simd crypto nocrypto nofp
ext/standard/crc32.c:49:17: error: ‘armv8-a’ does not support feature ‘nothing’
 static uint32_t crc32_aarch64(uint32_t crc, char *p, size_t nr) {
                 ^~~~~~~~~~~~~
ext/standard/crc32.c:49:17: note: valid feature names are: crc simd crypto nocrypto nofp
make[1]: *** [Makefile:967: ext/standard/crc32.lo] Error 1

구글링해보니 해당 파일의 위 에러가 발생하는 “+nothing+crc” 부분을 “arch=armv8-a+crc”로 바꾸니 해결되었다. 일부러 +nothing을 넣은건지 알수없고… 에러 내용도 보면 armv8-a에선 nothing을 지원하지 않는다. 이정도로 해석된다.

저런식으로 일단 빌드 안되게 해둔것이 빌드 대상 아키텍쳐가 crc 명령을 지원하는지 유무를 빌드 된 바이너리 레벨에서 확인이 안되어서 인가? 명령이 지원 안하면 실행 시 에러가 발생할것이니 빌드 레벨에서 대상 타겟이 무엇인지 명시적으로 정의를 하는것 같기도하고 음… 나중에 생각이 나고 기회가 되면 파고들어봐야겠다.

CEF(Chromium Embedded Framework) 빌드

풀네임으로는 Chromium Embedded Framework

우연찮게도 DJMAX에서 MSVC 재배포 패키지 설치가 필요하다는 오류가 뜬다는 질문을 보고 몇버전 런타임이 필요할까 하여 리소스를 살펴보다 이건 왜이렇게 용량이 큰거지? 라는 의문으로 구글링하다 알게된 것. 그런데 또 우연스럽게도 며칠 지나지도않아서 이거 관련되어 요청이 하나 들어온게 발생하여 빌드해보았다.

쉬운방법은 cef-project 코드를 받아서 readme 파일대로 cmake만 실행하면된다. 하지만 이건 자동빌드에 의해 먼저 빌드된 엔진을 다운로드하여 부수적인 dll파일만 빌드하는것으로 보였다. 기왕이면 동일한 런타임, 컴파일러로 빌드된 라이브러리를 발드하고싶어 좀 더 보니 cef가 있다. 이쪽은 빌드과정이 흩어져있어서 아래와같이 정리.

Continue reading CEF(Chromium Embedded Framework) 빌드

ICU 라이브러리 MSVC로 빌드

매우 오랜만에 ICU를 빌드하려하다보니 Windows SDK Version이 변경되지않는 이상한 문제가 발생하였다. 이거로 두시간동안 구글링도해보고 솔루션, 프로젝트, 프로퍼티 파일을 열어보아도 답이 안나와서 결국 MSYS2에서 빌드하였다(…).

빌드방법은 간단. VC 콘솔에서 MSYS2가 설치된 폴더로 이동 후 msys2_shell.cmd -use-full-path 명령으로 실행하면 프롬포트의 환경번수가 유지되어 bash 쉘이 뜨게된다. 이제 압축을 푼 icu 폴더의 source 폴더로 이동하여 ./runConfigureICU MSYS/MSVC --prefix=/d/OpenSource/icu-67.1.x64 --enable-tests=no --enable-samples=no 이런식으로 Makefile을 생성. 그리고 원인은 모르지만 config 파일을 정확하게 지정하지 못하는데… 이건 source 폴더의 하위 폴더인 config에서 cp mh-msys-msvc mh-unknown와같이 복사 후 make하면 끝. (nmake가 아닌 make 명령. 만약 D 옵션을 알 수 없다는 오류가 뜬다면 /usr/bin/link.exe 파일의 이름을 잠깐 다른 이름으로 바꾸면 오류를 회피할 수 있다. tests를 비활성화하면 링크에서 오류가 난다.)

이것으로 삽질 끝.

만약 위와같이 rc 명령에서 오류가 난다면 data 폴더에 out폴더 생성, 그 안애 tmp 폴더를 생성하면 된다. 추가로 extra의 scptrun에서 링크오류가 발생하면 해당 폴더의 makefile을 열어서 LINK.cc를 검색하여 -o $@ 부분을 -out:$@로 변경하면 된다.

추가)
icu 70.1버전에서 data폴더에서 dirs.timestamp관련 오류가 발생한다. 패치는 이곳에서 확인가능하며 아래가 패치파일 내용.

diff --urN a/source/data/Makefile.in b/source/data/Makefile.in
--- a/source/data/Makefile.in
+++ b/source/data/Makefile.in
@@ -236,11 +236,12 @@
 ## Include the main build rules for data files
 include $(top_builddir)/$(subdir)/rules.mk
 
+PKGDATA_LIST = $(TMP_DIR)/icudata.lst
 
 ifeq ($(ENABLE_SO_VERSION_DATA),1)
 ifeq ($(PKGDATA_MODE),dll)
 SO_VERSION_DATA = $(OUTTMPDIR)/icudata.res
-$(SO_VERSION_DATA) : $(MISCSRCDIR)/icudata.rc | $(TMP_DIR)/dirs.timestamp
+$(SO_VERSION_DATA) : $(MISCSRCDIR)/icudata.rc $(PKGDATA_LIST)
 ifeq ($(MSYS_RC_MODE),1)
 	rc.exe -i$(srcdir)/../common -i$(top_builddir)/common -fo$@ $(CPPFLAGS) $<
 else
@@ -249,7 +250,6 @@
 endif
 endif
 
-PKGDATA_LIST = $(TMP_DIR)/icudata.lst
 
 
 #####################################################