@@ -610,6 +610,345 @@ the following style significantly:
610
610
611
611
The key part of the tip is to reduce the duplications from the text includes.
612
612
613
+ Ideas for converting to modules
614
+ -------------------------------
615
+
616
+ For new libraries, we encourage them to use modules completely from day one if possible.
617
+ This will be pretty helpful to make the whole ecosystems to get ready.
618
+
619
+ For many existing libraries, it may be a breaking change to refactor themselves
620
+ into modules completely. So that many existing libraries need to provide headers and module
621
+ interfaces for a while to not break existing users.
622
+ Here we provide some ideas to ease the transition process for existing libraries.
623
+ **Note that the this section is only about helping ideas instead of requirement from clang **.
624
+
625
+ Let's start with the case that there is no dependency or no dependent libraries providing
626
+ modules for your library.
627
+
628
+ ABI non-breaking styles
629
+ ~~~~~~~~~~~~~~~~~~~~~~~
630
+
631
+ export-using style
632
+ ^^^^^^^^^^^^^^^^^^
633
+
634
+ .. code-block :: c++
635
+
636
+ module;
637
+ #include "header_1.h"
638
+ #include "header_2.h"
639
+ ...
640
+ #include "header_n.h"
641
+ export module your_library;
642
+ export namespace your_namespace {
643
+ using decl_1;
644
+ using decl_2;
645
+ ...
646
+ using decl_n;
647
+ }
648
+
649
+ As the example shows, you need to include all the headers containing declarations needs
650
+ to be exported and `using ` such declarations in an `export ` block. Then, basically,
651
+ we're done.
652
+
653
+ export extern-C++ style
654
+ ^^^^^^^^^^^^^^^^^^^^^^^
655
+
656
+ .. code-block :: c++
657
+
658
+ module;
659
+ #include "third_party/A/headers.h"
660
+ #include "third_party/B/headers.h"
661
+ ...
662
+ #include "third_party/Z/headers.h"
663
+ export module your_library;
664
+ #define IN_MODULE_INTERFACE
665
+ extern "C++" {
666
+ #include "header_1.h"
667
+ #include "header_2.h"
668
+ ...
669
+ #include "header_n.h"
670
+ }
671
+
672
+ Then in your headers (from ``header_1.h `` to ``header_n.h ``), you need to define the macro:
673
+
674
+ .. code-block :: c++
675
+
676
+ #ifdef IN_MODULE_INTERFACE
677
+ #define EXPORT export
678
+ #else
679
+ #define EXPORT
680
+ #endif
681
+
682
+ And you should put ``EXPORT `` to the beginning of the declarations you want to export.
683
+
684
+ Also it is suggested to refactor your headers to include thirdparty headers conditionally:
685
+
686
+ .. code-block :: c++
687
+
688
+ #ifndef IN_MODULE_INTERFACE
689
+ #include "third_party/A/headers.h"
690
+ #endif
691
+
692
+ #include "header_x.h"
693
+
694
+ ...
695
+
696
+ This may be helpful to get better diagnostic messages if you forgot to update your module
697
+ interface unit file during maintaining.
698
+
699
+ The reasoning for the practice is that the declarations in the language linkage are considered
700
+ to be attached to the global module. So the ABI of your library in the modular version
701
+ wouldn't change.
702
+
703
+ While this style looks not as convenient as the export-using style, it is easier to convert
704
+ to other styles.
705
+
706
+ ABI breaking style
707
+ ~~~~~~~~~~~~~~~~~~
708
+
709
+ The term ``ABI breaking `` sounds terrifying generally. But you may want it here if you want
710
+ to force your users to introduce your library in a consistent way. E.g., they either include
711
+ your headers all the way or import your modules all the way.
712
+ The style prevents the users to include your headers and import your modules at the same time
713
+ in the same repo.
714
+
715
+ The pattern for ABI breaking style is similar with export extern-C++ style.
716
+
717
+ .. code-block :: c++
718
+
719
+ module;
720
+ #include "third_party/A/headers.h"
721
+ #include "third_party/B/headers.h"
722
+ ...
723
+ #include "third_party/Z/headers.h"
724
+ export module your_library;
725
+ #define IN_MODULE_INTERFACE
726
+ #include "header_1.h"
727
+ #include "header_2.h"
728
+ ...
729
+ #include "header_n.h"
730
+
731
+ #if the number of .cpp files in your project are small
732
+ module :private;
733
+ #include "source_1.cpp"
734
+ #include "source_2.cpp"
735
+ ...
736
+ #include "source_n.cpp"
737
+ #else // the number of .cpp files in your project are a lot
738
+ // Using all the declarations from thirdparty libraries which are
739
+ // used in the .cpp files.
740
+ namespace third_party_namespace {
741
+ using third_party_decl_used_in_cpp_1;
742
+ using third_party_decl_used_in_cpp_2;
743
+ ...
744
+ using third_party_decl_used_in_cpp_n;
745
+ }
746
+ #endif
747
+
748
+ (And add `EXPORT ` and conditional include to the headers as suggested in the export
749
+ extern-C++ style section)
750
+
751
+ Remember that the ABI get changed and we need to compile our source files into the
752
+ new ABI format. This is the job of the additional part of the interface unit:
753
+
754
+ .. code-block :: c++
755
+
756
+ #if the number of .cpp files in your project are small
757
+ module :private;
758
+ #include "source_1.cpp"
759
+ #include "source_2.cpp"
760
+ ...
761
+ #include "source_n.cpp"
762
+ #else // the number of .cpp files in your project are a lot
763
+ // Using all the declarations from thirdparty libraries which are
764
+ // used in the .cpp files.
765
+ namespace third_party_namespace {
766
+ using third_party_decl_used_in_cpp_1;
767
+ using third_party_decl_used_in_cpp_2;
768
+ ...
769
+ using third_party_decl_used_in_cpp_n;
770
+ }
771
+ #endif
772
+
773
+ In case the number of your source files are small, we may put everything in the private
774
+ module fragment directly. (it is suggested to add conditional include to the source
775
+ files too). But it will make the compilation of the module interface unit to be slow
776
+ when the number of the source files are not small enough.
777
+
778
+ **Note that the private module fragment can only be in the primary module interface unit
779
+ and the primary module interface unit containing private module fragment should be the only
780
+ module unit of the corresponding module. **
781
+
782
+ In that case, you need to convert your source files (.cpp files) to module implementation units:
783
+
784
+ .. code-block :: c++
785
+
786
+ #ifndef IN_MODULE_INTERFACE
787
+ // List all the includes here.
788
+ #include "third_party/A/headers.h"
789
+ ...
790
+ #include "header.h"
791
+ #endif
792
+
793
+ module your_library;
794
+
795
+ // Following off should be unchanged.
796
+ ...
797
+
798
+ The module implementation unit will import the primary module implicitly.
799
+ We don't include any headers in the module implementation units
800
+ here since we want to avoid duplicated declarations between translation units.
801
+ This is the reason why we add non-exported using declarations from the third
802
+ party libraries in the primary module interface unit.
803
+
804
+ And if you provide your library as ``libyour_library.so ``, you probably need to
805
+ provide a modular one ``libyour_library_modules.so `` since you changed the ABI.
806
+
807
+ What if there are headers only inclued by the source files
808
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
809
+
810
+ The above practice may be problematic if there are headers only included by the source
811
+ files. If you're using private module fragment, you may solve the issue by including them
812
+ in the private module fragment. While it is OK to solve it by including the implementation
813
+ headers in the module purview if you're using implementation module units, it may be
814
+ suboptimal since the primary module interface units now containing entities not belongs
815
+ to the interface.
816
+
817
+ If you're a perfectionist, maybe you can improve it by introducing internal module partition unit.
818
+
819
+ The internal module partition unit is an importable module unit which is internal
820
+ to the module itself. The concept just meets the headers only included by the source files.
821
+
822
+ We don't show code snippet since it may be too verbose or not good or not general.
823
+ But it may not be too hard if you can understand the points of the section.
824
+
825
+ Providing a header to skip parsing redundant headers
826
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
827
+
828
+ It is a problem for clang to handle redeclarations between translation units.
829
+ Also there is a long standing issue in clang (`problematic include after import <https://github.com/llvm/llvm-project/issues/61465 >`_).
830
+ But even if the issue get fixed in clang someday, the users may still get slower compilation speed
831
+ and larger BMI size. So it is suggested to not include headers after importing the corresponding
832
+ library.
833
+
834
+ However, it is not easy for users if your library are included by other dependencies.
835
+
836
+ So the users may have to write codes like:
837
+
838
+ .. code-block :: c++
839
+
840
+ #include "third_party/A.h" // #include "your_library/a_header.h"
841
+ import your_library;
842
+
843
+ or
844
+
845
+ .. code-block :: c++
846
+
847
+ import your_library;
848
+ #include "third_party/A.h" // #include "your_library/a_header.h"
849
+
850
+ For such cases, we suggest the libraries providing modules and the headers at the same time
851
+ to provide a header to skip parsing all the headers in your libraries. So the users can
852
+ import your library as the following style to skip redundant handling:
853
+
854
+ .. code-block :: c++
855
+
856
+ import your_library;
857
+ #include "your_library_imported.h"
858
+ #include "third_party/A.h" // #include "your_library/a_header.h" but got skipped
859
+
860
+ The implementation of ``your_library_imported.h `` can be a set of controlling macros or
861
+ an overall controlling macro if you're using `#pragma once `. So you can convert your
862
+ headers to:
863
+
864
+ .. code-block :: c++
865
+
866
+ #pragma once
867
+ #ifndef YOUR_LIBRARY_IMPORTED
868
+ ...
869
+ #endif
870
+
871
+ Importing modules
872
+ ~~~~~~~~~~~~~~~~~
873
+
874
+ When there are dependent libraries providing modules, we suggest you to import that in
875
+ your module.
876
+
877
+ Most of the existing libraries would fall into this catagory once the std module gets available.
878
+
879
+ All dependent libraries providing modules
880
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
881
+
882
+ Life gets easier if all the dependent libraries providing modules.
883
+
884
+ You need to convert your headers to include thirdparty headers conditionally.
885
+
886
+ Then for export-using style:
887
+
888
+ .. code-block :: c++
889
+
890
+ module;
891
+ import modules_from_third_party;
892
+ #define IN_MODULE_INTERFACE
893
+ #include "header_1.h"
894
+ #include "header_2.h"
895
+ ...
896
+ #include "header_n.h"
897
+ export module your_library;
898
+ export namespace your_namespace {
899
+ using decl_1;
900
+ using decl_2;
901
+ ...
902
+ using decl_n;
903
+ }
904
+
905
+ For export extern-C++ style:
906
+
907
+ .. code-block :: c++
908
+
909
+ export module your_library;
910
+ import modules_from_third_party;
911
+ #define IN_MODULE_INTERFACE
912
+ extern "C++" {
913
+ #include "header_1.h"
914
+ #include "header_2.h"
915
+ ...
916
+ #include "header_n.h"
917
+ }
918
+
919
+ For ABI breaking style,
920
+
921
+ .. code-block :: c++
922
+
923
+ export module your_library;
924
+ import modules_from_third_party;
925
+ #define IN_MODULE_INTERFACE
926
+ #include "header_1.h"
927
+ #include "header_2.h"
928
+ ...
929
+ #include "header_n.h"
930
+
931
+ #if the number of .cpp files in your project are small
932
+ module :private;
933
+ #include "source_1.cpp"
934
+ #include "source_2.cpp"
935
+ ...
936
+ #include "source_n.cpp"
937
+ #endif
938
+
939
+ We don't need the non-exported using declarations if we're using implementation module
940
+ units now. We can import thirdparty modules directly in the implementation module
941
+ units.
942
+
943
+ Partial dependent libraries providing modules
944
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
945
+
946
+ In this case, we have to mix the use of ``include `` and ``import `` in the module of our
947
+ library. The key point here is still to remove duplicated declarations in translation
948
+ units as much as possible. If the imported modules provide headers to skip parsing their
949
+ headers, we should include that after the including. If the imported modules don't provide
950
+ the headers, we can make it ourselves if we still want to optimize it.
951
+
613
952
Known Problems
614
953
--------------
615
954
0 commit comments