Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Aegisub build with Meson on Windows #76

Merged
merged 20 commits into from
Nov 8, 2020

Conversation

Myaamori
Copy link
Contributor

@Myaamori Myaamori commented Oct 28, 2020

This PR includes a number of wraps and fixes to compile options that make it possible to build Aegisub on Windows using Meson. It should now be enough to simply install VS2019, Meson and Ninja and compile Aegisub using

meson --buildtype=debugoptimized -Ddefault_library=static -Db_vscrt=mdd builddir
ninja -C builddir src/aegisub.exe

This PR depends on TypesettingTools/libass/pull/7 to avoid linking issues with fribidi when building statically.

Tested on:

  • Linux (shared build using system dependencies)
  • Linux (static build using static Boost, ICU, FFMS2 and FFmpeg)
  • Windows (full static build)

Summary of changes:

  • New Boost wrap (only compiles required modules)
  • New ICU wrap
  • New FFMS2
  • New FFmpeg wrap using the GStreamer Meson port
  • New NASM wrap for automatically downloading a nasm binary on Windows
  • Various fixes to wxWidgets, libass and LuaJIT options

Known issues:

  • wxWidgets is always built in debug mode, regardless of the build type, and since it links against the debug runtime on Windows (/MDd), -Db_vscrt=mdd is required to avoid linking issues
  • While Aegisub does seem to be fully functional, basically any action will result in a wx assertion error, likely because of a version incompatibility - we need to either fix the assertions or downgrade wxWidgets
  • FFmpeg does not compile without optimizations
  • There are linking warnings about Aegisub violating the one definition rule when compiling on Windows
  • ninja clean doesn't remove e.g. the temporary files generated by icupkg
  • What files to install and where isn't properly specified
  • The ICU wrap is incredibly ugly (see below)

While the Boost and FFMS2 wraps are straightforward enough, the ICU wrap is rather ugly due to how complicated the ICU build process is.

In order to build the icudata library we first need to compile the icupkg binary, which processes icudt67l.dat and outputs icudata.lst - this is probably where any filtering of the file goes. Afterwards, the pkgdata binary takes the icudata.lst file and produces the icudata library - either a static or dynamic one depending on the arguments. The other libraries, such as icuuc and icui18n, can then link against icudata.

There are two main problems here: The first is the fact that pkgdata itself produces the library file. It manually constructs an object file and then spawns the compiler/linker/archiver as subprocesses. In order to specify the compiler and flags to use, for non-MSVC compilers pkgdata requires an icupkg.inc text file that specifies a variety of parameters. Unfortunately, Meson has no easy way to get the current compiler flags, so in order to generate a text file that can be passed to pkgdata I wrote a Python script which reads the compiler flags from builddir/meson-info/intro-targets.json.

Another issue here is that since pkgdata is run as a custom_target, Meson does not recognize the resulting binary as a library object, and if you pass it to the linker it will fail to correctly set the rpath of targets that link against it in the case of a shared library. To get around this, I always build icudata as a static library, and create a dummy shared library which simply wraps the static library using link_whole in the case where default_library is shared.

The second main problem is the fact that while the utility libraries such as icuuc and icui18n depend on icudata, pkgdata and icupkg in turn depend on the utility libraries, resulting in a circular dependency. The autotools build system solves this by first building a stub stubdata library, which is an empty library that simply declares the symbols expected by the other libraries. icuuc, icui18n, icuio and icutu are then built against stubdata, and icupkg and pkgdata are in turned linked against these. From a Meson perspective, however, the question is how to make the utility libraries link against the full icudata library rather than stubdata. For shared libraries, we would have to somehow manipulate the rpath to ensure that icudata is prioritized, while for static libraries we have to tell Meson not to automatically pull in stubdata when linking.

I couldn't figure out either one, so the solution I ended up with was to build the libraries twice, once linking against stubdata and then again linking against icudata. This is incredibly wasteful, but it's still the simplest, least hacky, and most predictable solution I could come up with. If we want to support cross compilation we would have to do something similar either way.

@Myaamori
Copy link
Contributor Author

By the way, one thing I didn't look at is what subproject dependencies we'd want to promote to the main project. I know I saw warnings mentioning how e.g. one subproject has a fontconfig wrap available, which isn't being used at the moment since we'd have to manually promote it.

Copy link
Member

@CoffeeFlux CoffeeFlux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for doing this!

I haven't looked at the new subprojects yet (ICU, boost, ffms2) and expect I'll have thoughts on those, but I wanted to get the Aegisub bits reviewed first.

subprojects/zlib.wrap Outdated Show resolved Hide resolved
subprojects/luajit/meson.build Show resolved Hide resolved
subprojects/luajit/src/host/meson.build Show resolved Hide resolved
subprojects/luajit/src/host/meson.build Show resolved Hide resolved
subprojects/luajit/src/host/meson.build Show resolved Hide resolved
subprojects/iconv/meson.build Show resolved Hide resolved
meson.build Outdated Show resolved Hide resolved
subprojects/wxWidgets.wrap Show resolved Hide resolved
.gitignore Outdated Show resolved Hide resolved
.gitignore Outdated Show resolved Hide resolved
Copy link
Member

@CoffeeFlux CoffeeFlux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly stylistic nits. The ffms2 and boost wrappers are straightforward and seem good, assuming the flags are right. ICU is a bit of a mess, but it passes the smell test and since you've documented how it works in the PR description I think we can check it in as-is.

I'll test all this on my MBP and see if I get anything interesting out of it.

subprojects/packagefiles/ffms2/meson.build Outdated Show resolved Hide resolved
subprojects/packagefiles/boost/libs/regex/meson.build Outdated Show resolved Hide resolved
subprojects/packagefiles/boost/libs/thread/meson.build Outdated Show resolved Hide resolved
subprojects/packagefiles/icu/source/meson.build Outdated Show resolved Hide resolved
@CoffeeFlux
Copy link
Member

For my own reference:

Once this is merged into meson-vs2019, the changes from here need to be rebased onto this branch before doing further work: https://github.com/TypesettingTools/Aegisub/commits/meson

@CoffeeFlux CoffeeFlux merged commit 93a8f30 into TypesettingTools:meson-vs2019 Nov 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants