shinchiro/mpv-winbuild-cmake

Switch to llvm-mingw

Closed this issue · 17 comments

Hi,

I know, this is not a trivial change, but let me explain. GCC specifically on Windows does not get much development. It works, but at this point I would consider it legacy toolchain, that is used by acclimation.

Bugs like https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412 are particularity worrisome, while we don't crash with AVX2. It is completely unusable with AVX512. And general feature set of Windows only features is let say minimal.

Using https://github.com/mstorsjo/llvm-mingw would allow us to take advantage of more mature Windows support.

  • .pdb generation support that would greatly simplify debugging crashes with provided binaries by this repo or similar builders
  • supporting arm Windows, not sure if there is need for builds like that, but there is a possibility to support that
  • better interop with MSVC, with even ability to use the same scripts and build locally with x86_64-pc-windows-msvc

and many more advantages that llvm based toolchain would have.

fyi, there's a branch I made when experimenting with clang toolchain. There's still limitation as llvm's dlltool does not support delay load import as far as I know. Some libraries still failed to compile under clang toolchain. So yeah, its not direct replacement with gcc toolchain

There's still limitation as llvm's dlltool does not support delay load import as far as I know.

I think they do support delayed load. From quick search there might be some differences to binutils. If anything they may be closer to MSVC link behavior, but I didn't go into details.

Some packages still failed to compile under clang toolchain. So yeah, its not direct replacement with gcc toolchain

I wouldn't expect it to be drop-in replacement, but from my experience clang on Windows works quite good. Some adjustment might be needed, but I don't expect hard blockers. As example MSYS2 has clang environment and most if not all packages are available in clang version. I might try your branch, because it is hard to discuss when I don't know what are the problems.

I made a quick look and looks like minor problems. For delayed load, same as for MSVC you have to pass /delayedload:name.dll to linker, not generate import lib. There is no such thing as delayed import lib in MSVC world and clang for that matter. Might still need a .lib file with imports, I didn't test that, beyond building. In which case we would need to create normal .lib with -l not -y.

mbedtls just need disabled warnings, libjxl need remove of alignment flags workaround and so on. Nothing scary to fix. I made those changes below and it almost passes. I have issue with rust, but it is likely problem on my end.

diff --git a/packages/libjxl.cmake b/packages/libjxl.cmake
index 1fcfffa..28df628 100644
--- a/packages/libjxl.cmake
+++ b/packages/libjxl.cmake
@@ -43,8 +43,6 @@ ExternalProject_Add(libjxl
         -DJPEGXL_ENABLE_SJPEG=OFF
         -DJPEGXL_ENABLE_AVX512=ON
         -DJPEGXL_ENABLE_AVX512_ZEN4=ON
-        -DCMAKE_CXX_FLAGS='${CMAKE_CXX_FLAGS} -msse2 -Wa,-muse-unaligned-vector-move' # fix crash on AVX2 proc (64bit) due to unaligned stack memory
-        -DCMAKE_C_FLAGS='${CMAKE_C_FLAGS} -msse2 -Wa,-muse-unaligned-vector-move'
     BUILD_COMMAND ${MAKE} -C <BINARY_DIR>
     INSTALL_COMMAND ${MAKE} -C <BINARY_DIR> install
     LOG_DOWNLOAD 1 LOG_UPDATE 1 LOG_CONFIGURE 1 LOG_BUILD 1 LOG_INSTALL 1
diff --git a/packages/luajit.cmake b/packages/luajit.cmake
index 08347d8..d6801dd 100644
--- a/packages/luajit.cmake
+++ b/packages/luajit.cmake
@@ -34,7 +34,6 @@ ExternalProject_Add(luajit
     GIT_CLONE_FLAGS "--filter=tree:0"
     GIT_REMOTE_NAME origin
     GIT_TAG v2.1-agentzh
-    PATCH_COMMAND ${EXEC} git am --3way ${CMAKE_CURRENT_SOURCE_DIR}/luajit-*.patch
     UPDATE_COMMAND ""
     CONFIGURE_COMMAND ""
     BUILD_COMMAND ${MAKE} -C <SOURCE_DIR>/src
diff --git a/packages/mbedtls.cmake b/packages/mbedtls.cmake
index 598b704..79dbb99 100644
--- a/packages/mbedtls.cmake
+++ b/packages/mbedtls.cmake
@@ -12,6 +12,7 @@ ExternalProject_Add(mbedtls
         -DUSE_STATIC_MBEDTLS_LIBRARY=ON
         -DUSE_SHARED_MBEDTLS_LIBRARY=OFF
         -DINSTALL_MBEDTLS_HEADERS=ON
+        -DMBEDTLS_FATAL_WARNINGS=OFF
     BUILD_COMMAND ${MAKE} -C <BINARY_DIR>
     INSTALL_COMMAND ${MAKE} -C <BINARY_DIR> install
     LOG_DOWNLOAD 1 LOG_UPDATE 1 LOG_CONFIGURE 1 LOG_BUILD 1 LOG_INSTALL 1
diff --git a/packages/vapoursynth-script.pc.in b/packages/vapoursynth-script.pc.in
index 0034703..ae48adb 100644
--- a/packages/vapoursynth-script.pc.in
+++ b/packages/vapoursynth-script.pc.in
@@ -8,5 +8,5 @@ Description: Library for interfacing VapourSynth with Python
 Version: @PC_VERSION@
 
 Requires: vapoursynth
-Libs: -L${libdir} -lvsscript
+Libs: -L${libdir} -l -Wl,-delayload:VSScript.dll
 Cflags: -I${includedir}
diff --git a/packages/vapoursynth.cmake b/packages/vapoursynth.cmake
index e02c3ca..1bc4b2a 100644
--- a/packages/vapoursynth.cmake
+++ b/packages/vapoursynth.cmake
@@ -12,10 +12,6 @@ endif()
 string(REPLACE "R" "" PC_VERSION ${rev})
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/vapoursynth.pc.in ${CMAKE_CURRENT_BINARY_DIR}/vapoursynth.pc @ONLY)
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/vapoursynth-script.pc.in ${CMAKE_CURRENT_BINARY_DIR}/vapoursynth-script.pc @ONLY)
-set(GENERATE_DEF ${CMAKE_CURRENT_BINARY_DIR}/vapoursynth-prefix/src/generate_def.sh)
-file(WRITE ${GENERATE_DEF}
-"#!/bin/bash
-gendef - $1.dll | sed -r -e 's|^_||' -e 's|@[1-9]+$||' > $1.def")
 
 ExternalProject_Add(vapoursynth
     URL ${link}
@@ -29,25 +25,7 @@ ExternalProject_Add(vapoursynth
     LOG_DOWNLOAD 1 LOG_UPDATE 1
 )
 
-ExternalProject_Add_Step(vapoursynth generate-def
-    DEPENDEES install
-    WORKING_DIRECTORY <SOURCE_DIR>
-    COMMAND chmod 755 ${GENERATE_DEF}
-    COMMAND ${EXEC} ${GENERATE_DEF} VSScript
-    COMMAND ${EXEC} ${GENERATE_DEF} VapourSynth
-    LOG 1
-)
-
-ExternalProject_Add_Step(vapoursynth generate-lib
-    DEPENDEES generate-def
-    WORKING_DIRECTORY <SOURCE_DIR>
-    COMMAND ${EXEC} ${TARGET_ARCH}-dlltool -d VSScript.def -y libvsscript.a ${dlltool_opts}
-    COMMAND ${EXEC} ${TARGET_ARCH}-dlltool -d VapourSynth.def -y libvapoursynth.a ${dlltool_opts}
-    LOG 1
-)
-
 ExternalProject_Add_Step(vapoursynth download-header
-    DEPENDEES generate-lib
     WORKING_DIRECTORY <SOURCE_DIR>
     COMMAND curl -sOL https://raw.githubusercontent.com/vapoursynth/vapoursynth/${rev}/include/VapourSynth.h
     COMMAND curl -sOL https://raw.githubusercontent.com/vapoursynth/vapoursynth/${rev}/include/VSScript.h
@@ -62,9 +40,6 @@ ExternalProject_Add_Step(vapoursynth manual-install
     COMMAND ${CMAKE_COMMAND} -E copy <SOURCE_DIR>/VapourSynth.h ${MINGW_INSTALL_PREFIX}/include/vapoursynth/VapourSynth.h
     COMMAND ${CMAKE_COMMAND} -E copy <SOURCE_DIR>/VSScript.h ${MINGW_INSTALL_PREFIX}/include/vapoursynth/VSScript.h
     COMMAND ${CMAKE_COMMAND} -E copy <SOURCE_DIR>/VSHelper.h ${MINGW_INSTALL_PREFIX}/include/vapoursynth/VSHelper.h
-    # Copying libs
-    COMMAND ${CMAKE_COMMAND} -E copy <SOURCE_DIR>/libvsscript.a ${MINGW_INSTALL_PREFIX}/lib/libvsscript.a
-    COMMAND ${CMAKE_COMMAND} -E copy <SOURCE_DIR>/libvapoursynth.a ${MINGW_INSTALL_PREFIX}/lib/libvapoursynth.a
     # Copying .pc files
     COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/vapoursynth.pc ${MINGW_INSTALL_PREFIX}/lib/pkgconfig/vapoursynth.pc
     COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/vapoursynth-script.pc ${MINGW_INSTALL_PREFIX}/lib/pkgconfig/vapoursynth-script.pc
diff --git a/packages/vapoursynth.pc.in b/packages/vapoursynth.pc.in
index 4d77d77..ee27dc3 100644
--- a/packages/vapoursynth.pc.in
+++ b/packages/vapoursynth.pc.in
@@ -8,6 +8,6 @@ Description: A frameserver for the 21st century
 Version: @PC_VERSION@
 
 Requires.private: zimg
-Libs: -L${libdir} -lvapoursynth
+Libs: -L${libdir} -Wl,-delayload:VapourSynth.dll
 Libs.private: -L${libdir} -lzimg
 Cflags: -I${includedir}

I tried to build vapoursynth with ffmpeg but it cannot find the vapoursynth dll eventhough I placed both .dll and import .lib (generated by gendef) in the libdir

lld: error: unable to find library -l-Wl,-delayload:VSScript.dll
lld: error: unable to find library -l-Wl,-delayload:VapourSynth.dll
clang-16: error: linker command failed with exit code 1 (use -v to see invocation)
ERROR: vapoursynth-script >= 42 not found using pkg-config

-l-Wl,-delayload:VSScript.dll

This looks wrong. Who adds -l? It should be -lVSScript -Wl,-delayload:VSScript.dll or something similar.

My bad. Actually, it is -lVSScript -Wl,-delayload=VSScript.dll without : . Only import .lib still necessary as the linker needs to read it.

@shinchiro Are you on discord or telegram or so?

I have tried clang branch.Compiling is too slow with the branch.
It takes 2~3 hours to compile the toolchain, and then almost 4 hours to compile all the dependencies and mpv.
As a comparison, with the gcc toolchain, the toolchain takes less than 1 hour to build, and about 2 hours to compile all the dependencies and mpv.

update: found out I made some mistakes, building dependencies and mpv under llvm is not slower than gcc. the 4 hours is including the time to build the toolchain.

I have tried clang branch. Compiling is too slow with the branch.

This is non problem. You should improve your workflow if that's issue for you.

cmake -> 4.277 s
ninja llvm -> 6:57.87 minutes
ninja llvm-clang -> 1:44.22 minutes
ninja mpv -> 1:57.57 minutes (but failed near the end, so even if it would be 3 minutes)

The real issue is that you should be not build tool chain every time or any of the dependencies if they are not changed. Probably the easiest form of caching is to use ccache, alternative would be to cache the packages after build.

There are a lot of possible improvements, but all in all even if it is slower for you there are solutions to mitigate that.

cmake -> 4.277 s ninja llvm -> 6:57.87 minutes ninja llvm-clang -> 1:44.22 minutes ninja mpv -> 1:57.57 minutes (but failed near the end, so even if it would be 3 minutes)

Found out I made some mistakes, building dependencies and mpv under llvm is not slower than gcc.
It's just that building the toolchain was significantly slower, with Performing configure step for 'llvm' taking the majority of the time (2h35min)

To anyone that successfully building mpv with the clang, can you test the mpv, whether it produce video output when using vo=gpu-next and gpu-api=vulkan?

It's just that building the toolchain was significantly slower, with Performing configure step for 'llvm' taking the majority of the time (2h35min)

Indeed, that would be expected. Building llvm is slow. But the compiler itself shouldn't be slower after, so building packages should stay the same.

Point is that you really shouldn't be building llvm often.

To anyone that successfully building mpv with the clang, can you test the mpv, whether it produce video output when using vo=gpu-next and gpu-api=vulkan?

I'm using clang and everything works fine. But have not tested with your scripts, might give a try later.

I decided to create a binary release/archive for clang/llvm releases and now use that as my toolchain, which essentially takes building the toolchain out of the equation if you clean everything or regularly start from scratch. It has some drawbacks if you want to use it universally anywhere on anything, for example since my containers run alpine/musl so you cant use my binary toolchain package on Ubuntu, I'm not sure how portable it would be across glibc systems if you built it on an old one like Ubuntu LTS though. You might not want that for this project but it's possible and easy to do, just in case anyone is interested for personal forks.

Edit to add: Actually you could have archive release and build from source, and let the user choose. It would also save time on github builds which could be of some benefit.

I decided to create a binary release/archive for clang/llvm releases and now use that as my toolchain, which essentially takes building the toolchain out of the equation if you clean everything or regularly start from scratch. It has some drawbacks if you want to use it universally anywhere on anything, for example since my containers run alpine/musl so you cant use my binary toolchain package on Ubuntu, I'm not sure how portable it would be across glibc systems if you built it on an old one like Ubuntu LTS though. You might not want that for this project but it's possible and easy to do, just in case anyone is interested for personal forks.

Found libwinpthread-1.dll missing error on your build.

Found libwinpthread-1.dll missing error on your build.

Strange, worked on my machines but indeed on a clean install it does happen.
I fixed it anyway, ffmpeg seems to not like libc++.dll.a,libunwind.dll.a and libwinpthread.dll.a when using llvm/clang so they have to be removed from the install. I missed libwinpthread.dll.a because it wasn't error'ing for me. mpv complained about missing libpthread.dll.a after I cleaned that up too but built fine on a clean build.

Works now, thanks.

The clang branch have been merged into master branch. This can be closed