-
Notifications
You must be signed in to change notification settings - Fork 313
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
CMake modernization #446
CMake modernization #446
Conversation
@mikke89 Any comments so far? |
First of all, this is so much better to read, so thank you! A very welcome addition. Here are some thoughts and notes, in no particular order, not everything here needs to be addressed in this PR.
|
1143bdc
to
9d73d14
Compare
Yes.
Yes, that is correct.
I agree on both.
Adding header files as sources isn't needed. Projects do it so that IDEs like Visual Studio show them in the project structure, but isn't needed to use them. All it's actually needed is add the include directory and that's it.
Yes, the way I used Using I would like to remove C++ compiler-specific extensions as well, but they are needed with MSVC for the whole
Yeah that's a to-do.
Well, you might want to wait until the project is compatible with CMake 3.16 then.
I keep it for easier rebasing and easy access to compare with the previous implementation. Once the CMake project is completely re-written, it will be obvious to get rid of it.
Yes. I agree that is better to only enable if the plugin is enabled.
The default consumer modes should be the one resulting from running CMake without any kind of option added to it, so the presets will likely add upon to override the defaults and pre-set stuff like compilers. All the suggestions for presets are good. |
I understand, however, it's very helpful to have them listed in IDEs, so in my opinion we should add them.
The reason I prefer target_compile_features is that this sets a minimum requirement, and then this can be overriden by a parent project, or by setting the a value on the command line. By setting
We already turn off
We already have pre-compiled headers enabled on our current CMake list through a version-check, and that seems to work fine. We should be able to do the same here.
Sounds good. What do you think about adding compiler flags to the default cmake presets? In particular, I wonder if we should add our supported warning flags or not. Or otherwise leave that to a more "dev" type preset. So how do you want us to proceed with this. Do you intend to keep actively working on this PR, and implementing the features and behavior discussed here? Or would you rather that we merge this early and let other people test and contribute simultaneously? |
I'll add them as well then.
Makes sense. I'll change the code to require C++ compile features instead.
I'll enable it then.
Indeed, and increasing the minimum CMake version won't be needed that way. However, I don't have experience implementing pre-compiled headers so it's something that another dev will need to implement.
I think warning flags set based on the consideration of the project should be left for presets targeted towards library developers. Consumers might not necessarily like having their compile or CI logs full of warnings from another project when they are likely only focused on warnings triggered by the code they actually control, not to mention the fact that the kind of warnings they are interested in might not be the same as the ones the project is interested in. If they want to ignore or add certain warning flags, it should always be done explicitly by the consumer and over what they expect to be the compiler's default behavior.
I would rather work over this a bit more, mitigate some possible bugs and merge earlier. There's a lot of features of the current (old) CMake project that I simply cannot implement by myself like compatibility for macOS, Emscripten, iOS and Android and the CMake find modules for the other dependencies. Once the PR is ready to review I would also like to get other contributors to test it to ensure that the use cases I can provide support for (Linux and Windows with or without Freetype and/or rlottie) work properly and that I haven't accidentally used CMake features not available in CMake 3.10 (I use the latest stable release). As a side note, in order to track what is left I think it would be nice to create issues for each feature left to implement and add them to the 6.0 milestone. |
Alright, all of this sounds good to me. I can add the precompiled headers once this one is merged into the cmake branch. Instead of making too many individual issues, I think we should instead make a task list in #198 with all the TODOs. And alright, let's aim for RmlUi 6.0, might be a bit ambitious but we'll try, depends mostly on the amount of feedback we get. |
76032fb
to
bce552c
Compare
893353c
to
1fb0555
Compare
788684a
to
6b13b51
Compare
@mikke89 I think I have amended the PR enough to be good to review again. Should I rebase to latest Also, here's the list of to-dos I've come up with:
Markdown source for the list: - [ ] `RMLUI_ENABLE_RTTI_AND_EXCEPTIONS`: defaulting to `ON`
- [ ] `RMLUI_ENABLE_PRECOMPILED_HEADERS`: Precompiled headers haven't been implemented. Defaulting to `ON`
- [ ] `RMLUI_ENABLE_THIRDPARTY_CONTAINERS`: defaulting to `ON`
- [ ] `RMLUI_USE_MATRIX_ROW_MAJOR`: defaulting to `OFF`
- [ ] `RMLUI_USE_CUSTOM_CONFIGURATION`: defaulting to `OFF`
- [ ] `RMLUI_WARNINGS_AS_ERRORS`: This option should not be implemented because implementing it means handling differences in how warnings are specified based on the compiler. If wanted, this should be implemented using a developer-oriented CMake preset that adds the desired warning flag to`CMAKE_<LANG>_FLAGS` .
- [ ] `RMLUI_BUILD_UNIVERSAL_BINARIES`: This option should not be implemented. [As specified in CMake's documentation](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-or-watchos), the choice of target architectures for Apple platforms should be left to the consumer's choice.
- [ ] **Add the rest of the samples**
- [ ] **Lua support via plugin:** For Lua, CMake already provides a [find module](https://cmake.org/cmake/help/latest/module/FindLua.html).
- [ ] **SVG support via plugin:** Since lunasvg already uses CMake as a meta-build system, rather than creating a find module for the RmlUi project, the ideal approach would be to contribute a package config file to the upstream project.
- [ ] **Tests:** Add tests from `Tests` folder to the build project. Usage of [CTest](https://cmake.org/cmake/help/latest/manual/ctest.1.html) might be worth looking at.
- [ ] **Implement installing and exporting:** [Reference from Modern CMake guide](https://cliutils.gitlab.io/modern-cmake/chapters/install.html). Aside from implementing CMake config files, implementing automatic generation of pkg-config (`.pc`) files at install time should be investigated. Since the project is now also heavily target-oriented, we can now fill in the details of the pkg-config definitions and CMake package config files such as which compiler definitions the consumer needs to use by checking the `INTERFACE_` target properties of the targets that need to be exported, similar to how CMake would do on its own if RmlUi was a target built inside the same project.
- [ ] **Bring back AppVeyor CI:** For this, usage of [CPack](https://cmake.org/cmake/help/book/mastering-cmake/chapter/Packaging%20With%20CPack.html) should be investigated. Usage of CPack requires installing and exporting to be implemented first.
- [ ] **Platform-support:** Building for iOS and Android is still untested. The Android SDK provides its own CMake toolchain files and iOS is supported by both [upstream CMake](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-or-watchos) and the one shipped along with the iOS SDK out of the box. Therefore there should be no need to write platform nor toolchain files to support both platforms.
- [ ] **Tracy:** Tracy seems to now support being built using CMake and also has a CMake package config file of their own, however its usage is undocumented. Its setup is simple enough to be able to write a simple find module for it.
- [ ] **Revise the naming of the CMake options**
- [ ] **Implement automatic selection of the backend:** If the amount of code is considerable implement it in a separate `.cmake` file to improve conciseness and not to crowd the main `CMakeLists.txt` file in the Samples folder.
- [ ] **Implement creation of macOS framework bundles:** CMake already provides integration with macOS framework files. Contrary to what was done before, I would recommend building both the core library and the debugger library as separate frameworks.
- [ ] **Create CMake presets and initial cache files:** As discussed to ease building.
- [ ] **Document how to interface the new build project:** Likely the last step once the feature freeze has been reached. Mention as well some of the standard conventions of CMake like the fact that you can set up some of the build options [directly on the environment](https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html), use CMake toolchain files in case the compiler they want to use isn't automatically detected by CMake like in Ubuntu, where many versions of the Clang compiler may be installed but `clang` doesn't always call the desired version as well as initial cache scripts. To aid, some templates could also be made so that consumers can take advantage of these without knowing about CMake. |
Thanks for continuing to work on this! I am a bit under the weather these days, but I'll get back to you soon enough. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First of all, excellent work! Very high quality, I'm sure this will be very nice to work with for everyone, and a lot more approachable for new users. I'm looking forward to having this fully merged.
I have tested many different combinations of settings, and they generally seem to work very well for me. I only have some minor comments.
Thanks a lot for making such a comprehensive todo-list as well. I agree with everything on this list, no objections here.
In terms of naming, I'm leaning towards these guiding principles:
- Prefix with
RMLUI_
. - Drop the prefix verb entirely.
- Do not name things with negation (such as 'not', 'disable'), to avoid situations with double negation.
This means names such as:
RMLUI_SAMPLES
RMLUI_LUA_BINDINGS
RMLUI_THIRDPARTY_CONTAINERS
I believe this looks natural when used, e.g. RMLUI_PRECOMPILED_HEADERS=ON
, and also makes finding suitable names much easier and more consistent.
You don't have to rebase. When we are both happy with this PR, I will squash and merge it into the cmake branch. We can continue working on it there for some time, and possibly invite more contributors. We should make it as stable as possible and hopefully quite close in terms of feature parity with what we have today, but not necessarily fully so. Generally, we don't really need to rebase, unless there are some library-wide changes being merged (the 'effects' branch being one).
Once we determine that things are working well enough, then I will merge it all to master. I will have to do that in a single commit, to avoid any transitive complications or issues, so all the commits will have to be squashed in the end. Then it will live in master for some time, give users time to report any new issues, before finally making a new release.
I hope this plan sounds good to you, let me know if you have any comments.
Previous changes only involved the name of the definition, but not its logic on the source files that referenced it nor code on the CMake files
- Remove all mention of SFML::Main - Remove handling code for SFML <= 2.4 - Make find_package() calls for SFML quiet
@mikke89 I think I have applied all the discussed changes. Anything else? |
Very good! I'm happy to merge this into the The new CMake code is very clean and modern. There is still quite a significant todo-list, many of which should be completed before merging into master, but this is an excellent start. Once this is merged into |
I'm ok with merging it as it is right now. |
Awesome work, thanks again! |
Partial re-write of the CMake project from scratch using modern CMake conventions. Available samples: benchmark, bitmapfont, demo, lottie. Sample bitmapfont now available without FreeType. Change options names according to new convention. Add CONTRIBUTING.md guidelines.
Partial re-write of the CMake project from scratch using modern CMake conventions. Available samples: benchmark, bitmapfont, demo, lottie. Sample bitmapfont now available without FreeType. Change options names according to new convention. Add CONTRIBUTING.md guidelines.
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 <[email protected]>
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 <[email protected]>
Partial re-write of the CMake project using modern CMake conventions.
INTERFACE
targets are used. These allow to group target options like source files and libraries to link against as CMake targets that generate no build artifacts whatsoever. When a target links against anINTERFACE
target, all the properties from theINTERFACE
target will be set as if they were their own.RMLUI_
for better organization in the CMake GUI.However, since this is a partial re-write:
Only has been tested with theAll backends have been implemented and should be functional, although not every single one of them has been tested. Automatic election of the backend for samples hasn't been implemented.GLFW_GL3
platform backend and the automatic election of the backend hasn't been ported over the new CMake project.RMLUI_DISABLE_RTTI_AND_EXCEPTIONS
: Would be ideal to change it to positive logic (RMLUI_ENABLE_RTTI_AND_EXCEPTIONS
) for more clarity.RMLUI_ENABLE_PRECOMPILED_HEADERS
: Precompiled headers haven't been implemented.RMLUI_NO_THIRDPARTY_CONTAINERS
If it is preferred to have the guidelines specified in
CONTRIBUTING.md
in the documentation repo, then I will contribute them there instead.