Skip to content

add module support #1243

New issue

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

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

Already on GitHub? # to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 179 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ option(ENTT_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if available."
option(ENTT_USE_SANITIZER "Enable sanitizers by adding -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined flags if available." OFF)
option(ENTT_USE_CLANG_TIDY "Enable static analysis with clang-tidy" OFF)

option(ENTT_MODULES "Build as a module library (requires c++20)" ON)

if(ENTT_USE_LIBCPP)
if(NOT WIN32)
include(CheckCXXSourceCompiles)
Expand Down Expand Up @@ -224,6 +226,182 @@ if(ENTT_HAS_NATVIS)
)
endif()

if(ENTT_MODULES)

message(STATUS "Building with module support")

add_library(EnTTModules)
Copy link
Owner

Choose a reason for hiding this comment

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

Does it make sense to have a different target?
I mean, I want to compile it as a module library or to import it as a header-only library.
I don't see why I should want both. In this case, why not use the same name? It would also reduce the boilerplate and duplication.

Copy link
Author

Choose a reason for hiding this comment

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

It's a good point, actually I'm not sure how the cmake side is. Works. But definitely it makes sense aim for a single target

Copy link
Owner

Choose a reason for hiding this comment

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

Not a problem. I can merge everything on a branch and fix it on my own eventually. 👍

add_library(EnTT::Module ALIAS EnTTModules)

target_compile_features(EnTTModules PUBLIC cxx_std_20)

if(ENTT_HAS_LIBCPP)
target_compile_options(EnTTModules BEFORE PUBLIC -stdlib=libc++)
endif()

if(ENTT_HAS_SANITIZER)
target_compile_options(EnTTModules INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>)
target_link_libraries(EnTTModules INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>)
endif()

target_sources(EnTTModules
PRIVATE FILE_SET CXX_MODULES
FILES
src/entt.cpp

PRIVATE FILE_SET HEADERS
BASE_DIRS src
FILES
src/entt/config/config.h
src/entt/config/macro.h
src/entt/config/version.h
src/entt/container/dense_map.hpp
src/entt/container/dense_set.hpp
src/entt/container/table.hpp
src/entt/container/fwd.hpp
src/entt/core/algorithm.hpp
src/entt/core/any.hpp
src/entt/core/attribute.h
src/entt/core/bit.hpp
src/entt/core/compressed_pair.hpp
src/entt/core/enum.hpp
src/entt/core/family.hpp
src/entt/core/fwd.hpp
src/entt/core/hashed_string.hpp
src/entt/core/ident.hpp
src/entt/core/iterator.hpp
src/entt/core/memory.hpp
src/entt/core/monostate.hpp
src/entt/core/ranges.hpp
src/entt/core/tuple.hpp
src/entt/core/type_info.hpp
src/entt/core/type_traits.hpp
src/entt/core/utility.hpp
src/entt/entity/component.hpp
src/entt/entity/entity.hpp
src/entt/entity/fwd.hpp
src/entt/entity/group.hpp
src/entt/entity/handle.hpp
src/entt/entity/mixin.hpp
src/entt/entity/helper.hpp
src/entt/entity/organizer.hpp
src/entt/entity/ranges.hpp
src/entt/entity/registry.hpp
src/entt/entity/runtime_view.hpp
src/entt/entity/snapshot.hpp
src/entt/entity/sparse_set.hpp
src/entt/entity/storage.hpp
src/entt/entity/view.hpp
src/entt/graph/adjacency_matrix.hpp
src/entt/graph/dot.hpp
src/entt/graph/flow.hpp
src/entt/graph/fwd.hpp
src/entt/locator/locator.hpp
src/entt/meta/adl_pointer.hpp
src/entt/meta/container.hpp
src/entt/meta/context.hpp
src/entt/meta/factory.hpp
src/entt/meta/fwd.hpp
src/entt/meta/meta.hpp
src/entt/meta/node.hpp
src/entt/meta/pointer.hpp
src/entt/meta/policy.hpp
src/entt/meta/range.hpp
src/entt/meta/resolve.hpp
src/entt/meta/template.hpp
src/entt/meta/type_traits.hpp
src/entt/meta/utility.hpp
src/entt/poly/fwd.hpp
src/entt/poly/poly.hpp
src/entt/process/fwd.hpp
src/entt/process/process.hpp
src/entt/process/scheduler.hpp
src/entt/resource/cache.hpp
src/entt/resource/fwd.hpp
src/entt/resource/loader.hpp
src/entt/resource/resource.hpp
src/entt/signal/delegate.hpp
src/entt/signal/dispatcher.hpp
src/entt/signal/emitter.hpp
src/entt/signal/fwd.hpp
src/entt/signal/sigh.hpp
src/entt/entt.hpp
src/entt/fwd.hpp

src/entt/container/dense_map.inc
src/entt/container/dense_set.inc
src/entt/container/table.inc
src/entt/container/fwd.inc
src/entt/core/algorithm.inc
src/entt/core/any.inc
src/entt/core/attribute.inc
src/entt/core/bit.inc
src/entt/core/compressed_pair.inc
src/entt/core/enum.inc
src/entt/core/family.inc
src/entt/core/fwd.inc
src/entt/core/hashed_string.inc
src/entt/core/ident.inc
src/entt/core/iterator.inc
src/entt/core/memory.inc
src/entt/core/monostate.inc
src/entt/core/ranges.inc
src/entt/core/tuple.inc
src/entt/core/type_info.inc
src/entt/core/type_traits.inc
src/entt/core/utility.inc
src/entt/entity/component.inc
src/entt/entity/entity.inc
src/entt/entity/fwd.inc
src/entt/entity/group.inc
src/entt/entity/handle.inc
src/entt/entity/mixin.inc
src/entt/entity/helper.inc
src/entt/entity/organizer.inc
src/entt/entity/ranges.inc
src/entt/entity/registry.inc
src/entt/entity/runtime_view.inc
src/entt/entity/snapshot.inc
src/entt/entity/sparse_set.inc
src/entt/entity/storage.inc
src/entt/entity/view.inc
src/entt/graph/adjacency_matrix.inc
src/entt/graph/dot.inc
src/entt/graph/flow.inc
src/entt/graph/fwd.inc
src/entt/locator/locator.inc
src/entt/meta/adl_pointer.inc
src/entt/meta/container.inc
src/entt/meta/context.inc
src/entt/meta/factory.inc
src/entt/meta/fwd.inc
src/entt/meta/meta.inc
src/entt/meta/node.inc
src/entt/meta/pointer.inc
src/entt/meta/policy.inc
src/entt/meta/range.inc
src/entt/meta/resolve.inc
src/entt/meta/template.inc
src/entt/meta/type_traits.inc
src/entt/meta/utility.inc
src/entt/poly/fwd.inc
src/entt/poly/poly.inc
src/entt/process/fwd.inc
src/entt/process/process.inc
src/entt/process/scheduler.inc
src/entt/resource/cache.inc
src/entt/resource/fwd.inc
src/entt/resource/loader.inc
src/entt/resource/resource.inc
src/entt/signal/delegate.inc
src/entt/signal/dispatcher.inc
src/entt/signal/emitter.inc
src/entt/signal/fwd.inc
src/entt/signal/sigh.inc
)

endif()

# Install EnTT and all related files

option(ENTT_INSTALL "Install EnTT and all related files." OFF)
Expand Down Expand Up @@ -253,7 +431,7 @@ if(ENTT_INSTALL)
include(CMakePackageConfigHelpers)

install(
TARGETS EnTT
TARGETS EnTT EnTTModules
EXPORT EnTTTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
Expand Down
79 changes: 79 additions & 0 deletions src/entt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
module;

#include <entt/entt.hpp>

export module entt;

#include "entt/container/dense_map.inc"
#include "entt/container/dense_set.inc"
#include "entt/container/fwd.inc"
#include "entt/container/table.inc"
#include "entt/core/algorithm.inc"
#include "entt/core/any.inc"
#include "entt/core/attribute.inc"
#include "entt/core/bit.inc"
#include "entt/core/compressed_pair.inc"
#include "entt/core/enum.inc"
#include "entt/core/family.inc"
#include "entt/core/fwd.inc"
#include "entt/core/hashed_string.inc"
#include "entt/core/ident.inc"
#include "entt/core/iterator.inc"
#include "entt/core/memory.inc"
#include "entt/core/monostate.inc"
#include "entt/core/ranges.inc"
#include "entt/core/tuple.inc"
#include "entt/core/type_info.inc"
#include "entt/core/type_traits.inc"
#include "entt/core/utility.inc"
#include "entt/entity/component.inc"
#include "entt/entity/entity.inc"
#include "entt/entity/fwd.inc"
#include "entt/entity/group.inc"
#include "entt/entity/handle.inc"
#include "entt/entity/helper.inc"
#include "entt/entity/mixin.inc"
#include "entt/entity/organizer.inc"
#include "entt/entity/ranges.inc"
#include "entt/entity/registry.inc"
#include "entt/entity/runtime_view.inc"
#include "entt/entity/snapshot.inc"
#include "entt/entity/sparse_set.inc"
#include "entt/entity/storage.inc"
#include "entt/entity/view.inc"
#include "entt/graph/adjacency_matrix.inc"
#include "entt/graph/dot.inc"
#include "entt/graph/flow.inc"
#include "entt/graph/fwd.inc"
#include "entt/locator/locator.inc"
#include "entt/meta/adl_pointer.inc"
#include "entt/meta/container.inc"
#include "entt/meta/context.inc"
#include "entt/meta/factory.inc"
#include "entt/meta/fwd.inc"
#include "entt/meta/meta.inc"
#include "entt/meta/node.inc"
#include "entt/meta/pointer.inc"
#include "entt/meta/policy.inc"
#include "entt/meta/range.inc"
#include "entt/meta/resolve.inc"
#include "entt/meta/template.inc"
#include "entt/meta/type_traits.inc"
#include "entt/meta/utility.inc"
#include "entt/poly/fwd.inc"
#include "entt/poly/poly.inc"
#include "entt/process/fwd.inc"
#include "entt/process/process.inc"
#include "entt/process/scheduler.inc"
#include "entt/resource/cache.inc"
#include "entt/resource/fwd.inc"
#include "entt/resource/loader.inc"
#include "entt/resource/resource.inc"
#include "entt/signal/delegate.inc"
#include "entt/signal/dispatcher.inc"
#include "entt/signal/emitter.inc"
#include "entt/signal/fwd.inc"
#include "entt/signal/sigh.inc"

#include "entt/operators.inc"
#include "entt/std.inc"
3 changes: 3 additions & 0 deletions src/entt/container/dense_map.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export namespace entt {
Copy link
Owner

Choose a reason for hiding this comment

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

Do you know what the common approach is for other already existing projects, if any?
I'm not sure I like the inc file in the same dir of the code. On the other hand, modules are still such a wild beast that I don't really know what I like in general. 😅
Any other well known GH repo of which you are aware that also supports modules out there?

Copy link
Contributor

Choose a reason for hiding this comment

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

https://arewemodulesyet.org/
There are only a handful of libraries that try to support cpp20 modules
fmt is probably one of the most popular ones and it supports it with some defines instead of a bunch of .inc files. Namely these:

  • FMT_MODULE
  • FMT_EXPORT
  • FMT_BEGIN_EXPORT
  • FMT_END_EXPORT

https://github.com/fmtlib/fmt/blob/master/include/fmt/args.h#L11-L15
https://github.com/fmtlib/fmt/blob/5f6fb96df1637c3b4a2a068ab03e156ed8c3ea39/src/fmt.cc#L98-L100

I looked into what the support looks like awhile ago so I thought I'd share.

Copy link
Author

@elvisdukaj elvisdukaj Apr 5, 2025

Choose a reason for hiding this comment

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

I saw three main approaches for handling modules:

  1. fmt, tgui, use macros to know it export and not export, avoiding code duplication
  2. glm, magic_enum use a single "cppm" file which essentially exports everything.
  3. CMake use the same trick I am using here for exporting the standard template library.

I choosed the 3rd approach only because I wasn't familiar enough with the internal source code of entt. I don't think it's the best.

My considerations:

  • The 1st approach is avoiding duplications, and adding/removing something that is exported is easier because that's onlly one file to touch. The downside is that you need to clearly separate what you export or not, for instance the internal namespace maybe it's not intended to be exported.
  • The 2nd and 3rd approach are pretty similar, with the difference that you stash all the exports in a single files instead of splitting them in the equivalent header. I find it easier to touch the corresponding moudle file instead of a global file where everything is exported. The main advantage is that you can selectively choose what to export and not. In mu example for instance all the internal namespace is not exposed.

I can try to implement the 1st approach as well for having a better comparison.

As a side note, I would avoid to create new file extensions for c++ modules like (.cppm) since doesn't make much sense in my opinion and not all compilers go along with different extensions.

Copy link
Owner

Choose a reason for hiding this comment

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

I can try to implement the 1st approach as well for having a better comparison.

I don't want to waste your time, it's not necessary to implement it for all symbols. However, it would help if you could provide a small example, yeah. Something like for a single subdir or such. Is it something you can do?

Copy link
Author

Choose a reason for hiding this comment

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

It sounds like a plan, this Friday I can work on it

using ::entt::dense_map;
} // namespace entt
3 changes: 3 additions & 0 deletions src/entt/container/dense_set.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export namespace entt {
using ::entt::dense_set;
} // namespace entt
3 changes: 3 additions & 0 deletions src/entt/container/fwd.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export namespace entt {
using ::entt::table;
} // namespace entt
4 changes: 4 additions & 0 deletions src/entt/container/table.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export namespace entt {
using ::entt::basic_table;
} // namespace entt

5 changes: 5 additions & 0 deletions src/entt/core/algorithm.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export namespace entt {
using ::entt::std_sort;
using ::entt::insertion_sort;
using ::entt::radix_sort;
} // namespace entt
6 changes: 6 additions & 0 deletions src/entt/core/any.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export namespace entt {
using ::entt::basic_any;
using ::entt::any_cast;
using ::entt::make_any;
using ::entt::forward_as_any;
} // namespace entt
Empty file added src/entt/core/attribute.inc
Empty file.
6 changes: 6 additions & 0 deletions src/entt/core/bit.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export namespace entt {
using ::entt::popcount;
using ::entt::has_single_bit;
using ::entt::next_power_of_two;
using ::entt::fast_mod;
} // namespace entt
4 changes: 4 additions & 0 deletions src/entt/core/compressed_pair.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export namespace entt {
using ::entt::compressed_pair;
using ::entt::swap;
} // namespace entt
4 changes: 4 additions & 0 deletions src/entt/core/enum.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export namespace entt {
using ::entt::enum_as_bitmask;
using ::entt::enum_as_bitmask_v;
} // namespace entt
3 changes: 3 additions & 0 deletions src/entt/core/family.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export namespace entt {
using ::entt::family;
} // namespace entt
7 changes: 7 additions & 0 deletions src/entt/core/fwd.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export namespace entt {
using ::entt::any_policy;
using ::entt::id_type;
using ::entt::any;
using ::entt::hashed_string;
using ::entt::hashed_wstring;
} // namespace entt
9 changes: 9 additions & 0 deletions src/entt/core/hashed_string.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export namespace entt {
using ::entt::basic_hashed_string;

inline namespace literals {
using ::entt::literals::operator ""_hs;
using ::entt::literals::operator ""_hws;
} // namespace literals

}
3 changes: 3 additions & 0 deletions src/entt/core/ident.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export namespace entt {
using ::entt::ident;
} // namespace entt
7 changes: 7 additions & 0 deletions src/entt/core/iterator.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export namespace entt {
using ::entt::input_iterator_pointer;
using ::entt::iota_iterator;
using ::entt::operator==;
using ::entt::operator!=;
using ::entt::iterable_adaptor;
} // namespace entt
11 changes: 11 additions & 0 deletions src/entt/core/memory.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export namespace entt {
using ::entt::to_address;
using ::entt::propagate_on_container_copy_assignment;
using ::entt::propagate_on_container_move_assignment;
using ::entt::propagate_on_container_swap;
using ::entt::allocation_deleter;
using ::entt::allocate_unique;
using ::entt::uses_allocator_construction_args;
using ::entt::make_obj_using_allocator;
using ::entt::uninitialized_construct_using_allocator;
} // namespace entt
4 changes: 4 additions & 0 deletions src/entt/core/monostate.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export namespace entt {
using ::entt::monostate;
using ::entt::monostate_v;
} // namespace entt
Empty file added src/entt/core/ranges.inc
Empty file.
6 changes: 6 additions & 0 deletions src/entt/core/tuple.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export namespace entt {
using ::entt::is_tuple;
using ::entt::is_tuple_v;
using ::entt::unwrap_tuple;
using ::entt::forward_apply;
} // namespace entt
Loading