Docker + MinGWでWindowsアプリをビルドしてみた

ランチャーアプリを書いてるついでに、Docker + Mingwでビルドしてみた。

CMakeLists.txt

ビルドシステムにはcmake + makeを使うので、CMakeLists.txtを書く。と言っても、なんか特別なことはなく普通のCMakeLists.txt

CMAKE_MINIMUM_REQUIRED(VERSION 3.25)
PROJECT(BLauncher5 CXX)
SET(CMAKE_CXX_STANDARD 17)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_CXX_EXTENSIONS OFF)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D UNICODE=1 -D _UNICODE=1")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
ADD_EXECUTABLE(BLauncher5
    src/main.cpp
    src/window/hide_window.cpp
    src/window/main_window.cpp
    src/window/button.cpp
    src/item/catalog.cpp
    src/util/log.cpp
    src/item/page.cpp
)
TARGET_SOURCES(BLauncher5 PRIVATE src/resource.rc)

TARGET_LINK_LIBRARIES(BLauncher5 gdi32 comctl32 shlwapi)
TARGET_LINK_OPTIONS(BLauncher5 PUBLIC -static-libgcc -static-libstdc++)

ADD_CUSTOM_TARGET(Doxygen cd ../ && doxygen)

強いて変わったところを上げると、libstdc++とかを静的リンクにしてくるらい。GPL例外だからGPLにはならないはず。

Dockerfile

ビルドするDockerファイル

FROM debian:12-slim

RUN apt-get update && apt-get upgrade -y && apt-get install -y mingw-w64 cmake make
RUN echo "cd /src" > /build.sh && \
    echo "if [ -d build ]; then" >> /build.sh && \
    echo "    rm -rf build" >> /build.sh && \
    echo "fi" >> /build.sh && \
    echo "mkdir build" >> /build.sh && \
    echo "cd build" >> /build.sh && \
    echo "CXX=x86_64-w64-mingw32-g++ CC=x86_64-w64-mingw32-gcc cmake -DCMAKE_RC_COMPILER=x86_64-w64-mingw32-windres -DCMAKE_SYSTEM_NAME=Windows .." >> /build.sh && \
    echo "make" >> /build.sh

CMD ["sh", "/build.sh"]

ベースのOSには使い慣れたDebianを使用。mingw-w64cmakemakeをインストールして、ビルドするスクリプトを作成。

cmakeするときにCCとCXXでmingwのgccを指定。あとリソースコンパイラとしてmingwのwindresを指定。さらにCMAKE_SYSTEM_NAMEでWindows向けにビルドすることを指定。CMAKE_SYSTEM_NAMEを設定しなくてもexeファイルはできるけど、リソースがつかなくなるので、無いと困る。

Docker実行

$ sudo docker build -t blauncher5_builder:latest --rm=true .
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
            Install the buildx component to build images with BuildKit:
            https://docs.docker.com/go/buildx/

Sending build context to Docker daemon   1.72MB
Step 1/4 : FROM debian:12-slim
 ---> 19e789b9b50f
Step 2/4 : RUN apt-get update && apt-get upgrade -y && apt-get install -y mingw-w64 cmake make
 ---> Using cache
 ---> 7ddd82e0a735
Step 3/4 : RUN echo "cd /src" > /build.sh &&     echo "if [ -d build ]; then" >> /build.sh &&     echo "    rm -rf build" >> /build.sh &&     echo "fi" >> /build.sh &&     echo "mkdir build" >> /build.sh &&     echo "cd build" >> /build.sh &&     echo "CXX=x86_64-w64-mingw32-g++ CC=x86_64-w64-mingw32-gcc cmake -DCMAKE_RC_COMPILER=x86_64-w64-mingw32-windres -DCMAKE_SYSTEM_NAME=Windows .." >> /build.sh &&     echo "make" >> /build.sh
 ---> Using cache
 ---> 1507911c25e5
Step 4/4 : CMD ["sh", "/build.sh"]
 ---> Using cache
 ---> 35825d7f3bd1
Successfully built 35825d7f3bd1
Successfully tagged blauncher5_builder:latest

Dockerfileを作ったら、docker buildコマンドでコンテナをビルド。これを実行すると

$ sudo docker run --name blauncher5_builder -v ".:/src" blauncher5_builder
-- The CXX compiler identification is GNU 12.0.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/x86_64-w64-mingw32-g++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /src/build
[ 11%] Building CXX object CMakeFiles/BLauncher5.dir/src/main.cpp.obj
[ 22%] Building CXX object CMakeFiles/BLauncher5.dir/src/window/hide_window.cpp.obj
[ 33%] Building CXX object CMakeFiles/BLauncher5.dir/src/window/main_window.cpp.obj
[ 44%] Building CXX object CMakeFiles/BLauncher5.dir/src/window/button.cpp.obj
[ 55%] Building CXX object CMakeFiles/BLauncher5.dir/src/item/catalog.cpp.obj
[ 66%] Building CXX object CMakeFiles/BLauncher5.dir/src/util/log.cpp.obj
[ 77%] Building CXX object CMakeFiles/BLauncher5.dir/src/item/page.cpp.obj
[ 88%] Building RC object CMakeFiles/BLauncher5.dir/src/resource.rc.res
[100%] Linking CXX executable BLauncher5.exe
[100%] Built target BLauncher5
$ sudo docker rm blauncher5_builder
blauncher5_builder

./buildディレクトリにBLauncher5.exeが作成されてた

$ ls -lh build
total 2.5M
-rwxrwxrwx 1 mattyan mattyan 2.4M Aug 22 21:08 BLauncher5.exe
-rwxrwxrwx 1 mattyan mattyan  14K Aug 22 21:08 CMakeCache.txt
drwxrwxrwx 1 mattyan mattyan 4.0K Aug 22 21:08 CMakeFiles
-rwxrwxrwx 1 mattyan mattyan  12K Aug 22 21:08 Makefile
-rwxrwxrwx 1 mattyan mattyan 1.5K Aug 22 21:08 cmake_install.cmake
開発中のランチャーアプリ

ちゃんと実行もできた。

ちなみにDLLの依存関係を見てみたら

$ objdump -p BLauncher5.exe | grep DLL
 vma:            Hint    Time      Forward  DLL       First
        DLL Name: COMCTL32.dll
        DLL Name: GDI32.dll
        DLL Name: KERNEL32.dll
        DLL Name: msvcrt.dll
        DLL Name: SHELL32.dll
        DLL Name: USER32.dll

特に変なものもないから多分大丈夫なはず。

TODO

_tprintfがおかしい?

_tprintf(_TEXT("[%s] %s:%d %s\n"), level, file, line, message);

なぜかこのコードでログを出力すると、

$ ./BLauncher5.exe
[i] /:216 c
[w] /:218 p
[i] /:222 r

%s%cとして動いてる気がする?

ちなみにWindows(msys2 + gcc)でビルドすると

$ ./BLauncher5.exe
[info] blauncher5/src/window/button.cpp:216 copied
[warn] blauncher5/src/window/button.cpp:218 page is null
[info] blauncher5/src/window/button.cpp:222 registered

ちゃんと出力される。

std::wcout << "[" << level << "] " << file << ":" << line << " " << message << std::endl;

std::wcout(UNICODE指定で内部的にTCHAR = wchar_tなので)で出力させたら、ちゃんと出力できた。

$ ./BLauncher5.exe
[info] /src/src/window/button.cpp:216 copied
[warn] /src/src/window/button.cpp:218 page is null
[info] /src/src/window/button.cpp:222 registered

gitlab ci/cdでビルドできるようにする

将来的に、「タグを打つとそれをトリガーにビルドしてzipで固めてリリースページを作る」をやりたい。いつできるかな……

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です