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

Modernize CMake #606

Merged
merged 1 commit into from
May 7, 2024
Merged

Modernize CMake #606

merged 1 commit into from
May 7, 2024

Conversation

mikke89
Copy link
Owner

@mikke89 mikke89 commented Apr 1, 2024

The CMake code has been fully rewritten with modern practices. Special thanks to @hobyst who laid the groundwork for this change, with a solid foundation and great guidelines (#446).

I am making a pull request to gather any feedback before merging into master. In particular, because this is quite a significant breaking change in terms of build setups. However, I believe the benefits are quite clear, this will make it a lot easier to work with the library.

Please let me know if you have any feedback. It would be very helpful to see this tested in as many environments as possible before merging to master, so feel free to test it in your environment to identify any issues.

The changes should be close to feature-complete with what we currently have in master. I consider this todo-list, written by @hobyst, to be pretty much completed. One thing that we are missing is any apple-specific behavior such as frameworks and universal binaries.

I will have to squash most of these commits before merging. However I kept the individual commits around so that one can lookup the motivation behind some of the changes. For the most part I would recommend looking at the full changes together.


Changes

While modernizing our CMake code, it was clear that we also needed to change our naming conventions. This leads to quite significant breaking changes for building and linking, but the result should make the library a lot easier to work with and link with.

We now try to support all setups including:

  1. Adding the library as a subdirectory directly from CMake.
  2. Building the library "in-source" without installing.
  3. Building and installing the library.
  4. Using pre-built Windows binaries.

It should be a lot easier now to simply point to the built library or sources, and have everything link correctly.

And naturally, we will continue to support package managers however we can, and that is still considered the default recommendation. However, for the most part we rely on contributors to keep supporting this. Please help out with your favorite package manager if you see missing versions, or room for improvements.

Large parts of the CI workflows have also been rewritten to accommodate these changes. Most of the Windows building and packaging procedures have been moved from Appveyor to GitHub Actions, which streamlines our testing and also helps speed up the CI builds.

New target names

We now export the following targets:

Target Description
RmlUi::RmlUi Includes all sub-libraries of the project, as listed just below
RmlUi::Core The main library
RmlUi::Debugger The debugger library
RmlUi::Lua The Lua plugin (when enabled)

When including RmlUi as a subdirectory, the targets are constructed as aliases. When using pre-built or installed binaries, they are constructed using imported targets, which are available through the exported build targets.

The internal target names have also been changed, although they are typically only needed when exploring or developing the library. They are all lowercase and contain the prefix rmlui_ to avoid colliding with names in any parent projects. Some examples are: rmlui_core, rmlui_debugger, rmlui_sample_invaders, rmlui_tutorial_drag, rmlui_unit_tests, and rmlui_visual_tests.

New library filenames

The library binaries have also changed names. These names would be suffixed by e.g. .dll on Windows, and so on.

Library Description
rmlui The core (main) library
rmlui_debugger The debugger library
rmlui_lua The Lua plugin (when enabled)

New option names

We have a new set of CMake naming conventions for the library:

  • Use RMLUI_ prefix to make all options specific to this project easily identifiable, and avoid colliding with any parent project variables.
  • Do not include negations (such as "not" and "disable"), to avoid situations with double negation.
  • Do not include a verb prefix (such as "enable" and "build"), as these are often superfluous.

The following table lists all the new option names.

Option Default value Old related option Comment
RMLUI_BACKEND auto SAMPLES_BACKEND
RMLUI_COMPILER_OPTIONS ON Automatically sets
recommended compiler flags
RMLUI_CUSTOM_CONFIGURATION OFF CUSTOM_CONFIGURATION
RMLUI_CUSTOM_CONFIGURATION_FILE CUSTOM_CONFIGURATION_FILE
RMLUI_CUSTOM_INCLUDE_DIRS CUSTOM_INCLUDE_DIRS
RMLUI_CUSTOM_LINK_LIBRARIES CUSTOM_LINK_LIBRARIES
RMLUI_CUSTOM_RTTI OFF DISABLE_RTTI_AND_EXCEPTIONS No longer modifies compiler
flags -only enables RmlUi's
custom RTTI solution so that
the user can disable language
RTTI and exceptions
RMLUI_FONT_ENGINE freetype NO_FONT_INTERFACE_DEFAULT Now takes a string with one of
the options: none, freetype
RMLUI_HARFBUZZ_SAMPLE OFF
RMLUI_INSTALL_RUNTIME_DEPENDENCIES ON Automatically install runtime
dependencies on supported
platforms (e.g. DLLs)
RMLUI_LOTTIE_PLUGIN OFF ENABLE_LOTTIE_PLUGIN
RMLUI_LUA_BINDINGS OFF BUILD_LUA_BINDINGS
RMLUI_LUA_BINDINGS_LIBRARY lua BUILD_LUA_BINDINGS_FOR_LUAJIT Now takes a string with one of
the options: lua, lua_as_cxx,
luajit
RMLUI_MATRIX_ROW_MAJOR OFF MATRIX_ROW_MAJOR
RMLUI_PRECOMPILED_HEADERS ON ENABLE_PRECOMPILED_HEADERS
RMLUI_SAMPLES OFF BUILD_SAMPLES
RMLUI_SVG_PLUGIN OFF ENABLE_SVG_PLUGIN
RMLUI_THIRDPARTY_CONTAINERS ON NO_THIRDPARTY_CONTAINERS
RMLUI_TRACY_PROFILING OFF ENABLE_TRACY_PROFILING
RMLUI_VISUAL_TESTS_RML_DIRECTORIES VISUAL_TESTS_RML_DIRECTORIES
RMLUI_VISUAL_TESTS_COMPARE_DIRECTORY VISUAL_TESTS_COMPARE_DIRECTORY
RMLUI_VISUAL_TESTS_CAPTURE_DIRECTORY VISUAL_TESTS_CAPTURE_DIRECTORY

For reference, the following options have not changed names, as these are standard options used by CMake.

Unchanged options Default value
CMAKE_BUILD_TYPE
BUILD_SHARED_LIBS ON
BUILD_TESTING OFF

CMake presets

We now have CMake presets:

  • samples Enable samples but only those without extra dependencies.
  • samples-all Enable all samples, also those with extra dependencies.
  • standalone Build the library completely without any dependencies (even freetype). The idea is that it could be useful to take a quick look without dealing with dependencies, the only sample that works is bitmapfont.
  • dev Enable testing and samples.
  • dev-all Enable testing and all samples, including those that require extra dependencies.

One would still typically need to set options like CMAKE_BUILD_TYPE when using these. I also experimented with more detailed, platform-dependent presets, but found that it is not really that useful, see the following commit message for reasoning: 27cf1df.

@mikke89 mikke89 added enhancement New feature or request build Build system and compilation labels Apr 1, 2024
@mikke89 mikke89 added this to the 6.0 milestone Apr 1, 2024
@mikke89 mikke89 linked an issue Apr 1, 2024 that may be closed by this pull request
@mikke89 mikke89 mentioned this pull request Apr 1, 2024
Partial rewrite originally written by @hobyst in #446 and #551.
Remaining code and changes written by @mikke89.

These changes should generally be feature-complete with the previous CMake code, with some exceptions to legacy and certain Apple-specific behavior. Please see the changelog for breaking changes, in particular, several options, CMake targets, and file names have been changed.

The following lists some noteworthy changes:

- CMake presets now available.
- Major changes to CI automation and tests.
  - Most tests on Appveyor are moved to Github actions. This includes a completely new packaging workflow on GitHub.
  - Packaging now uses Visual Studio 2019 instead of 2017. Keep Appveyor only for testing with Visual Studio 2017.
  - Use CMake scripts for some packaging tasks to avoid avoid duplicate workflow code.
- `RmlUi::RmlUi` is now an include-all library target, while components like `RmlUi::Core` and `RmlUi::Debugger` can be chosen individually.
- Add `contributing.md` guidelines for CMake.
- Backends can now be changed without recompiling the whole library.
- Set CMake `policy_max` to a recent version. This opts in to a number of CMake improvements for users that can take advantage of that.
- Sample bitmapfont now available without FreeType.
- Runtime outputs are now placed in the binary root directory.
- Runtime dependencies can now be installed automatically, this includes dependencies from vcpkg.
- Update .editorconfig and format all CMake files consistently.
- Rename `harfbuzzshaping` sample to `harfbuzz`.
- Fix harfbuzz compatibility for older versions.
- Remove CMake warning on FreeType version.

In the following, some working notes and lessons learned are written down (authored by @mikke89):

- Avoid separate libraries for subparts of Core

  Originally, parts of core such as Elements, Layout and FontEngineDefault, were added as interface libraries. Defining these as interface libraries cause issues during export. I believe we would have to export them as separate targets, but that doesn't relly make sense from a client standpoint and causes new issues with exported source files and dependencies. It seems to be a lot less troublesome to use a single CMake library and set properties and attach sources to that directly.

- Avoid interface libraries for plugins and Lua dependencies

  Using interface libraries to add plugins causes problems when installing targets. Even trying to split the interface libraries into private and public parts did not work suitably. An issue arises when compiling the project as static libraries. Consider when we are linking targets to rmlui_core. Even when they are added as private dependencies, CMake adds it as a transient link-time dependency. This even applies to interface dependencies, which causes problems for our private interface libraries representing the plugins. In particular, CMake wants us to export these libraries, as now they are referenced from rmlui_core, but we don't want to export them, as that was the whole point of making them private and would cause new issues.

  Instead, add the SVG and Lottie source files and imported dependencies directly to Core. This simplifies things quite a bit, and seems to work reliably. For similar reasons, use imported interface targets instead of a pure interface library for the custom Lua target.

- Common options for CMake targets

  Using CMake presets to specify compiler flags, warnings in particular, is not a great experience. Presets require one to set all the flags at the same time (in a single variable). For example, we can't easily set just /WX in one profile and /MP in another. There are workarounds, but being more pragmatic, setting these flags in a cmake file is much more straightforward with proper conditionals.

- On CMake presets

  I also experimented with more detailed, platform-dependent presets, but found that it is not really that useful. In particular, we want users themselves to use whichever compilers and generators they want to rather than to constrain the choices. We strive to be agnostict toward both generators and platforms. This way, we we can also give more common build instructions regardless of platform.

  Also tested with making presets for e.g. vcpkg and mingw toolchains. However, this doesn't really make sense in presets. First of all, the choice of such a toolchain is not mutually exclusive with the current presets, so we would have to replicate most of them for each toolchain we wanted to support. Further, the exact specifics of these toolcahins, like version, platform, install location, and so on, is very specific to each case. Thus, if we wanted to handle these it would create additional dimensions to the presets, and we'd end up with a huge list of similar presets we would have to mainatain and which users would have to choose from. Or alternatively, users would have to provide a lot of their setup in any case, thereby dismissing some of the initially considered usefulness. Instead, many tools already allow you to setup a toolchain first which can then be used with a given preset. Thus, making the choice of toolchains and cmake presets orthogonal makes a lot more sense.

  One unfortunate issue from a user-friendliness perspective is that the cmake gui doesn't allow you to select a preset without a specified generator. There's an issue for this here: https://gitlab.kitware.com/cmake/cmake/-/issues/23341
  I figured accepting this for now is better than duplicating all our presets to specify different generators. But the situations is not ideal, hopefully it will be fixed soon.

- Recommended compiler flags

  The compiler flags are enabled by default to ensure users get a good experience when building the library without fiddling with options. Especially on MSVC, the default compiler flags means really slow builds (no /MP), and we also risk exposing more warnings.

Co-authored-by: Michael Ragazzon <michael.ragazzon@gmail.com>
@mikke89 mikke89 merged commit 2b54f93 into master May 7, 2024
64 checks passed
@mikke89 mikke89 deleted the cmake branch May 7, 2024 21:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
build Build system and compilation enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Modernize CMake
2 participants