├── example ├── main.cpp ├── src │ └── world.cpp ├── hello.cpp └── CMakeLists.txt ├── .gitignore ├── appveyor.yml ├── .travis.yml ├── LICENSE ├── README.md └── CXXModules.cmake /example/main.cpp: -------------------------------------------------------------------------------- 1 | import hello; 2 | import world; 3 | 4 | int main (void) 5 | { 6 | greeter(world()); 7 | } 8 | -------------------------------------------------------------------------------- /example/src/world.cpp: -------------------------------------------------------------------------------- 1 | export module world; 2 | 3 | export const char* world() 4 | { 5 | return "World"; 6 | } 7 | -------------------------------------------------------------------------------- /example/hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | export module hello; 4 | 5 | export void greeter(const char *name) 6 | { 7 | printf("Hello %s!\n", name); 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeCache.txt 2 | CMakeFiles 3 | CMakeScripts 4 | Testing 5 | Makefile 6 | cmake_install.cmake 7 | install_manifest.txt 8 | compile_commands.json 9 | CTestTestfile.cmake 10 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | 3 | image: Visual Studio 2017 4 | 5 | environment: 6 | matrix: 7 | - GENERATOR: Visual Studio 15 2017 Win64 8 | 9 | before_build: 10 | - cmake -Bbuild -Hexample -G "%GENERATOR%" 11 | 12 | build_script: 13 | - cmake --build build 14 | 15 | test_script: 16 | - build\Debug\main.exe 17 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # Required CMake 3 | cmake_minimum_required(VERSION 3.2.3) 4 | 5 | # Include file with required functions 6 | include(../CXXModules.cmake) 7 | 8 | # Use special function for creating C++ modules library. 9 | # Same as add_library but also creates interface files 10 | # and add required flags for current compiler 11 | add_module_library(hello_world 12 | hello.cpp 13 | src/world.cpp 14 | ) 15 | 16 | # Create executable target 17 | add_module_executable(main 18 | main.cpp 19 | ) 20 | 21 | # Link C++ modules library to the executable 22 | target_link_module_libraries(main hello_world) 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | language: cpp 3 | 4 | addons: 5 | apt: 6 | packages: 7 | - cmake 8 | 9 | matrix: 10 | include: 11 | - os: linux 12 | addons: 13 | apt: 14 | sources: 15 | - llvm-toolchain-xenial-7 16 | packages: 17 | - clang-7 18 | env: 19 | - MATRIX_EVAL="CC=clang-7 && CXX=clang++-7" 20 | 21 | - os: linux 22 | addons: 23 | apt: 24 | sources: 25 | - llvm-toolchain-xenial-8 26 | packages: 27 | - clang-8 28 | env: 29 | - MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" 30 | 31 | before_install: 32 | - eval "${MATRIX_EVAL}" 33 | 34 | script: 35 | - cmake -Bbuild -Hexample 36 | - cmake --build build 37 | - ./build/main 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jiří Fatka 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CMake C++ Modules 2 | 3 | CMake module for C++ modules TS projects. 4 | 5 | ## Warning 6 | 7 | This is an experimental CMake module which uses current implementation of C++ Modules TS. There are a lot of issues and shouldn't be used in production code. 8 | 9 | ## Supported compilers 10 | 11 | * Clang 7 12 | * MSVC 13 | * [WIP] GCC 14 | 15 | ## Usage 16 | 17 | Download `CXXModules.cmake` file and include it into your CMake project. 18 | 19 | The basic usage is put the file in same directory as `CMakeLists.txt`: 20 | 21 | ```cmake 22 | include(CXXModules.cmake) 23 | ``` 24 | 25 | Alternatively the file can stored in a path referenced in `CMAKE_MODULE_PATH` so you can only type: 26 | 27 | ```cmake 28 | include(CXXModules) 29 | ``` 30 | 31 | Now you have access to special functions which enable C++ modules support. 32 | 33 | * `target_enable_cxx_modules` - enable C++ modules support for project. It just set compiler options for C++ modules. 34 | * `add_module_library` - same as CMake's `add_library` but generate C++ module interface files from given source 35 | files and store that in `CXX_MODULES_INTERFACE_FILES` target property and set `CXX_MODULES_INTERFACE_TARGETS` which contains 36 | target names for creating interface files. 37 | * `add_module_executable` - same as `add_executable` but enable C++ modules support. 38 | * `target_link_module_libraries` - same as `target_link_libraries` but generate C++ modules interface files import 39 | flags for target. 40 | 41 | ## Example 42 | 43 | ```cmake 44 | # Required CMake 45 | cmake_minimum_required(VERSION 3.2.3) 46 | 47 | # Include file with required functions 48 | include(CXXModules.cmake) 49 | 50 | # Use special function for creating C++ modules library. 51 | # Same as add_library but also creates interface files 52 | # and add required flags for current compiler 53 | add_module_library(hello_world 54 | hello_world.cpp 55 | ) 56 | 57 | # Create executable target 58 | add_module_executable(main 59 | main.cpp 60 | ) 61 | 62 | # Link C++ modules library to the executable 63 | target_link_module_libraries(main hello_world) 64 | ``` 65 | -------------------------------------------------------------------------------- /CXXModules.cmake: -------------------------------------------------------------------------------- 1 | # ########################################################################## # 2 | # Copyright (c) 2018 Jiří Fatka 3 | # 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be included in all 12 | # copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | # SOFTWARE. 21 | # ########################################################################## # 22 | 23 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 24 | # Clang 25 | set(CXX_MODULES_CHECK -fmodules-ts) 26 | set(CXX_MODULES_FLAGS -fmodules-ts) 27 | set(CXX_MODULES_EXT pcm) 28 | set(CXX_MODULES_CREATE_FLAGS -fmodules-ts -x c++-module --precompile) 29 | set(CXX_MODULES_USE_FLAG -fmodule-file=) 30 | set(CXX_MODULES_OUTPUT_FLAG -o) 31 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 32 | # GCC 33 | message(FATAL_ERROR "GCC is not supported yet") 34 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") 35 | # MSVC 36 | # compiler flags for modules were changed at version 16.8 37 | if (MSVC_VERSION LESS 1928) 38 | set(CXX_MODULES_CHECK /experimental:module) 39 | set(CXX_MODULES_FLAGS /experimental:module /module:interface) 40 | set(CXX_MODULES_EXT ifc) 41 | set(CXX_MODULES_CREATE_FLAGS -c) 42 | set(CXX_MODULES_USE_FLAG /module:reference) 43 | set(CXX_MODULES_OUTPUT_FLAG /module:output) 44 | else() 45 | set(CXX_MODULES_CHECK /experimental:module) 46 | set(CXX_MODULES_FLAGS /experimental:module /interface) 47 | set(CXX_MODULES_EXT ifc) 48 | set(CXX_MODULES_CREATE_FLAGS -c) 49 | set(CXX_MODULES_USE_FLAG /reference) 50 | set(CXX_MODULES_OUTPUT_FLAG /ifcOutput) 51 | endif() 52 | else () 53 | message(FATAL_ERROR "Unsupported compiler") 54 | endif () 55 | 56 | # ########################################################################## # 57 | 58 | # Compiler flags support tests 59 | include(CheckCXXCompilerFlag) 60 | include(CMakePushCheckState) 61 | 62 | # Check if used compiler version supports modules 63 | check_cxx_compiler_flag(${CXX_MODULES_CHECK} CXX_MODULES) 64 | 65 | # ########################################################################## # 66 | 67 | ## 68 | ## Check if current compiler supports C++ modules. If compiler doesn't support 69 | ## modules it fails with fatal error. 70 | ## 71 | function (_check_cxx_modules_support) 72 | if (NOT CXX_MODULES) 73 | message(FATAL_ERROR "Compiler doesn't support C++ modules (TS)") 74 | endif () 75 | endfunction () 76 | 77 | # ########################################################################## # 78 | 79 | ## 80 | ## Enable C++ modules for project. 81 | ## 82 | ## This function adds appropriate compiler flags to the target. 83 | ## 84 | function (target_enable_cxx_modules TARGET) 85 | _check_cxx_modules_support() 86 | 87 | # Add modules flag 88 | target_compile_options(${TARGET} PRIVATE ${CXX_MODULES_FLAGS}) 89 | endfunction () 90 | 91 | # ########################################################################## # 92 | 93 | ## 94 | ## Create an executable with C++ support 95 | ## 96 | function (add_module_executable TARGET) 97 | _check_cxx_modules_support() 98 | 99 | add_executable(${TARGET} ${ARGN}) 100 | 101 | # Enable modules for target 102 | target_enable_cxx_modules(${TARGET}) 103 | endfunction () 104 | 105 | # ########################################################################## # 106 | 107 | ## 108 | ## Create C++ module library. 109 | ## 110 | ## Sets target property CXX_MODULES_INTERFACE_FILES and CXX_MODULES_INTERFACE_TARGETS 111 | ## 112 | function (add_module_library TARGET) 113 | _check_cxx_modules_support() 114 | 115 | # Get sources 116 | set(_sources) 117 | 118 | # Filter source files 119 | foreach (_arg ${ARGN}) 120 | list(FIND "STATIC;SHARED;MODULE;EXCLUDE_FROM_ALL;OBJECT;UNKNOWN;IMPORTED" ${_arg} _skip) 121 | 122 | if (${_skip} GREATER_EQUAL 0) 123 | continue () 124 | endif () 125 | 126 | if (${_arg} MATCHES "ALIAS") 127 | message(FATAL_ERROR "Alias library is not supported") 128 | endif () 129 | 130 | # TODO: limit sources extensions? 131 | 132 | list(APPEND _sources ${_arg}) 133 | endforeach () 134 | 135 | # Allow to use CXX compiler on C++ module files 136 | set_source_files_properties(${_sources} PROPERTIES LANGUAGE CXX) 137 | 138 | # Create normal library 139 | add_library(${TARGET} ${ARGN}) 140 | 141 | # Enable modules for target 142 | target_enable_cxx_modules(${TARGET}) 143 | 144 | set(_interface_files) 145 | set(_interface_targets) 146 | 147 | # Create targets for interface files 148 | foreach (_source ${_sources}) 149 | set(_o_file ${_source}.${CXX_MODULES_EXT}) 150 | set(_i_file ${CMAKE_CURRENT_SOURCE_DIR}/${_source}) 151 | 152 | # TODO: CXX flags might be different 153 | set(_cmd ${CMAKE_CXX_COMPILER} "$,\t>" ${CXX_MODULES_CREATE_FLAGS} ${_i_file} ${CXX_MODULES_OUTPUT_FLAG} ${_o_file}) 154 | 155 | get_filename_component(_o_file_dir ${_o_file} DIRECTORY) 156 | 157 | if (_o_file_dir) 158 | file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_o_file_dir}) 159 | endif() 160 | 161 | # Create interface build target 162 | add_custom_command( 163 | OUTPUT ${_o_file} 164 | COMMAND ${_cmd} 165 | DEPENDS ${_i_file} 166 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 167 | ) 168 | 169 | # Replace directory separators with something else 170 | string(REPLACE "/" "__" _o_file_target ${_o_file}) 171 | string(PREPEND _o_file_target "module_") 172 | 173 | # Create interface build target 174 | add_custom_target(${_o_file_target} 175 | COMMAND ${_cmd} 176 | DEPENDS ${_o_file} 177 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 178 | ) 179 | 180 | list(APPEND _interface_files ${_o_file}) 181 | list(APPEND _interface_targets ${_o_file_target}) 182 | endforeach () 183 | 184 | # Store property with interface files 185 | set_target_properties(${TARGET} 186 | PROPERTIES CXX_MODULES_INTERFACE_FILES "${_interface_files}" 187 | ) 188 | 189 | set_target_properties(${TARGET} 190 | PROPERTIES CXX_MODULES_INTERFACE_TARGETS "${_interface_targets}" 191 | ) 192 | endfunction () 193 | 194 | # ########################################################################## # 195 | 196 | ## 197 | ## Link a (C++ module) library to (C++ module) target. 198 | ## 199 | ## Use target property CXX_MODULES_INTERFACE_FILES and CXX_MODULES_INTERFACE_TARGETS 200 | ## 201 | function (target_link_module_libraries TARGET) 202 | _check_cxx_modules_support() 203 | 204 | # Enable modules for target 205 | target_enable_cxx_modules(${TARGET}) 206 | 207 | foreach (_arg ${ARGN}) 208 | list(FIND "PUBLIC;PRIVATE;INTERFACE" ${_arg} _skip) 209 | 210 | if (${_skip} GREATER_EQUAL 0) 211 | continue () 212 | endif () 213 | 214 | # Get interface files from library 215 | get_target_property(_interface_targets ${_arg} CXX_MODULES_INTERFACE_TARGETS) 216 | 217 | foreach (_target ${_interface_targets}) 218 | add_dependencies(${TARGET} ${_target}) 219 | endforeach () 220 | 221 | # Get interface files from library 222 | get_target_property(_interface_files ${_arg} CXX_MODULES_INTERFACE_FILES) 223 | 224 | foreach (_file ${_interface_files}) 225 | # TODO: might be different on different compilers 226 | target_compile_options(${TARGET} PRIVATE ${CXX_MODULES_USE_FLAG}${CMAKE_CURRENT_BINARY_DIR}/${_file}) 227 | endforeach () 228 | endforeach () 229 | 230 | # Normal link 231 | target_link_libraries(${TARGET} ${ARGN}) 232 | endfunction () 233 | 234 | # ########################################################################## # 235 | --------------------------------------------------------------------------------