├── .gitignore ├── Makefile.h ├── README.md ├── clmod.py ├── testall ├── Makefile ├── modall_if.cppm ├── modall_ifpart.cppm ├── modall_impl.cpp ├── modall_part.cppm └── modall_test.cpp ├── testallcpp ├── Makefile ├── modall_if.cpp ├── modall_ifpart.cpp ├── modall_impl.cpp ├── modall_part.cpp └── modall_test.cpp ├── testallixx ├── Makefile ├── modall_if.ixx ├── modall_ifpart.ixx ├── modall_impl.cpp ├── modall_part.cpp └── modall_test.cpp └── testsimple ├── Makefile ├── modsimple_if.cppm └── modsimple_test.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | ~* 3 | *.bak 4 | *.swp 5 | *.swo 6 | *.tmp 7 | *.stackdump 8 | *.obj 9 | *.o 10 | *.exe 11 | *.ifc 12 | gcm.cache 13 | -------------------------------------------------------------------------------- /Makefile.h: -------------------------------------------------------------------------------- 1 | 2 | #========================================================== 3 | # General Flags 4 | #========================================================== 5 | 6 | #GCCFLAGS=-g -Wall -ansi -fhonor-std 7 | #GCCFLAGS=-g -ansi -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wtraditional -pedantic 8 | GCCWARNFLAGS = --pedantic --pedantic-errors -Wall -Wextra -Wnon-virtual-dtor -Wconversion -D_GLIBCXX_DEBUG 9 | FLAGSUNUSED = -Wno-unused-parameter -Wno-unused-variable -Wno-unused-but-set-variable 10 | GCCFLAGS = -O2 $(GCCWARNFLAGS) $(FLAGSUNUSED) 11 | GCCFLAGSNOWARN = -O2 $(FLAGSUNUSED) 12 | LDFLAGS = -O2 13 | 14 | #---------------------------------------------------- 15 | # Default: std C++20 with gcc 11.0 16 | 17 | PATHDEF = /cygdrive/p/gcc/gcc110 18 | CXX = $(PATHDEF)/bin/g++110 19 | CXXFLAGS = --std=c++20 $(GCCFLAGS) 20 | CXXFLAGSNOWARN = --std=c++20 $(GCCFLAGSNOWARN) 21 | LDFLAGS = -latomic 22 | 23 | .cpp: 24 | $(CXX) $(CXXFLAGSNOWARN) $(INCLUDES) $*.cpp $(LDFLAGS20) -o $*raw.exe 25 | @echo PATH=\"$(PATH20)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 26 | @chmod +x $*.exe 27 | @echo "- OK: $* calls $*raw.exe" 28 | .cxx: 29 | sed -f $(TTT2CPP) < $< > $*.cpp 30 | $(CXX) $(CXXFLAGSNOWARN) $(INCLUDES) $*.cpp $(LDFLAGS) -o $*raw.exe 31 | @echo PATH=\"$(PATHDEF)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 32 | @chmod +x $*.exe 33 | rm $*.cpp 34 | @echo "- OK: $* calls $*raw.exe" 35 | 36 | 37 | #========================================================== 38 | # gcc compiler-specific targets 39 | #========================================================== 40 | 41 | #---------------------------------------------------- 42 | # gcc 4.8 (with C++11) 43 | 44 | .SUFFIXES: .48 45 | PATH48 = /cygdrive/p/gcc/gcc48 46 | CXX48 = $(PATH48)/bin/g++48 47 | CXXFLAGS48 = --std=c++11 $(GCCFLAGS) 48 | #LDFLAGS48 = -latomic 49 | LDFLAGS48 = 50 | .cpp.48: 51 | $(CXX48) $(CXXFLAGS48) $(INCLUDES) $*.cpp $(LDFLAGS48) -o $*48raw.exe 52 | @echo PATH=\"$(PATH48)/bin:\$$PATH\" ./$*48raw.exe '$$*' > $*.exe 53 | @chmod +x $*.exe 54 | @echo "- OK: $* calls $*48raw.exe" 55 | .cxx.48: 56 | sed -f $(TTT2CPP) < $*.cxx > $*.cpp 57 | $(CXX72) $(CXXFLAGS48) $(INCLUDES) $*.cpp $(LDFLAGS48) -o $*48raw.exe 58 | @echo PATH=\"$(PATH48)/bin:\$$PATH\" ./$*48raw.exe '$$*' > $*.exe 59 | @chmod +x $*.exe 60 | @echo "- OK: $* calls $*48raw.exe" 61 | rm $*.cpp 62 | 63 | #---------------------------------------------------- 64 | # gcc 6.1 (with C++14): 65 | 66 | .SUFFIXES: .61 67 | PATH61 = /cygdrive/p/gcc/gcc61 68 | CXX61 = $(PATH61)/bin/g++61 69 | CXXFLAGS61 = --std=c++14 $(GCCFLAGS) 70 | LDFLAGS61 = -latomic 71 | .cpp.61: 72 | $(CXX61) $(CXXFLAGS61) $(INCLUDES) $*.cpp $(LDFLAGS61) -o $*61raw.exe 73 | @echo PATH=\"$(PATH61)/bin:\$$PATH\" ./$*61raw.exe '$$*' > $*.exe 74 | @chmod +x $*.exe 75 | @echo "- OK: $* calls $*61raw.exe" 76 | .cxx.61: 77 | sed -f $(TTT2CPP) < $*.cxx > $*.cpp 78 | $(CXX72) $(CXXFLAGS61) $(INCLUDES) $*.cpp $(LDFLAGS61) -o $*61raw.exe 79 | @echo PATH=\"$(PATH61)/bin:\$$PATH\" ./$*61raw.exe '$$*' > $*.exe 80 | @chmod +x $*.exe 81 | @echo "- OK: $* calls $*61raw.exe" 82 | rm $*.cpp 83 | 84 | #---------------------------------------------------- 85 | # gcc 7.2 (with C++17): 86 | 87 | .SUFFIXES: .72 88 | PATH72 = /cygdrive/p/gcc/gcc72 89 | CXX72 = $(PATH72)/bin/g++72 90 | CXXFLAGS72 = --std=c++17 $(GCCFLAGS) 91 | LDFLAGS72 = -latomic 92 | .cpp.72: 93 | $(CXX72) $(CXXFLAGS72) $(INCLUDES) $*.cpp $(LDFLAGS72) -o $*72raw.exe 94 | @echo PATH=\"$(PATH72)/bin:\$$PATH\" ./$*72raw.exe '$$*' > $*.exe 95 | @chmod +x $*.exe 96 | @echo "- OK: $* calls $*72raw.exe" 97 | .cxx.72: 98 | sed -f $(TTT2CPP) < $*.cxx > $*.cpp 99 | $(CXX72) $(CXXFLAGS72) $(INCLUDES) $*.cpp $(LDFLAGS72) -o $*72raw.exe 100 | @echo PATH=\"$(PATH72)/bin:\$$PATH\" ./$*72raw.exe '$$*' > $*.exe 101 | @chmod +x $*.exe 102 | @echo "- OK: $* calls $*72raw.exe" 103 | rm $*.cpp 104 | 105 | #---------------------------------------------------- 106 | # gcc 8.2 (with C++17): 107 | 108 | .SUFFIXES: .82 109 | PATH82 = /cygdrive/p/gcc/gcc82 110 | CXX82 = $(PATH82)/bin/g++82 111 | CXXFLAGS82 = --std=c++17 $(GCCFLAGS) 112 | LDFLAGS82 = -latomic 113 | .cpp.82: 114 | $(CXX82) $(CXXFLAGS82) $(INCLUDES) $*.cpp $(LDFLAGS82) -o $*82raw.exe 115 | @echo PATH=\"$(PATH82)/bin:\$$PATH\" ./$*82raw.exe '$$*' > $*.exe 116 | @chmod +x $*.exe 117 | @echo "- OK: $* calls $*82raw.exe" 118 | .cxx.82: 119 | sed -f $(TTT2CPP) < $*.cxx > $*.cpp 120 | $(CXX82) $(CXXFLAGS82) $(INCLUDES) $*.cpp $(LDFLAGS82) -o $*82raw.exe 121 | @echo PATH=\"$(PATH82)/bin:\$$PATH\" ./$*82raw.exe '$$*' > $*.exe 122 | @chmod +x $*.exe 123 | @echo "- OK: $* calls $*82raw.exe" 124 | rm $*.cpp 125 | 126 | #---------------------------------------------------- 127 | # gcc 9.2 (with C++17): 128 | 129 | .SUFFIXES: .92 130 | PATH92 = /cygdrive/p/gcc/gcc92 131 | CXX92 = $(PATH92)/bin/g++92 132 | CXXFLAGS92 = --std=c++17 $(GCCFLAGS) 133 | LDFLAGS92 = -latomic 134 | .cpp.92: 135 | $(CXX92) $(CXXFLAGS92) $(INCLUDES) $*.cpp $(LDFLAGS92) -o $*92raw.exe 136 | @echo PATH=\"$(PATH92)/bin:\$$PATH\" ./$*92raw.exe '$$*' > $*.exe 137 | @chmod +x $*.exe 138 | @echo "- OK: $* calls $*92raw.exe" 139 | .cxx.92: 140 | sed -f $(TTT2CPP) < $*.cxx > $*.cpp 141 | $(CXX92) $(CXXFLAGS92) $(INCLUDES) $*.cpp $(LDFLAGS92) -o $*92raw.exe 142 | @echo PATH=\"$(PATH92)/bin:\$$PATH\" ./$*92raw.exe '$$*' > $*.exe 143 | @chmod +x $*.exe 144 | @echo "- OK: $* calls $*92raw.exe" 145 | rm $*.cpp 146 | 147 | #---------------------------------------------------- 148 | # gcc 10.1 (with C++20): 149 | 150 | .SUFFIXES: .101 151 | PATH101 = /cygdrive/p/gcc/gcc101 152 | CXX101 = $(PATH92)/bin/g++101 153 | CXXFLAGS101 = --std=c++2a $(GCCFLAGS) 154 | LDFLAGS101 = -latomic 155 | .cpp.101: 156 | $(CXX101) $(CXXFLAGS101) $(INCLUDES) $*.cpp $(LDFLAGS101) -o $*101raw.exe 157 | @echo PATH=\"$(PATH101)/bin:\$$PATH\" ./$*101raw.exe '$$*' > $*.exe 158 | @chmod +x $*.exe 159 | @echo "- OK: $* calls $*101raw.exe" 160 | .cxx.101: 161 | sed -f $(TTT2CPP) < $*.cxx > $*.cpp 162 | $(CXX101) $(CXXFLAGS101) $(INCLUDES) $*.cpp $(LDFLAGS101) -o $*101raw.exe 163 | @echo PATH=\"$(PATH101)/bin:\$$PATH\" ./$*101raw.exe '$$*' > $*.exe 164 | @chmod +x $*.exe 165 | @echo "- OK: $* calls $*101raw.exe" 166 | rm $*.cpp 167 | 168 | #---------------------------------------------------- 169 | # gcc 11.0 (with C++20): 170 | 171 | .SUFFIXES: .110 172 | PATH110 = /cygdrive/p/gcc/gcc110 173 | CXX110 = $(PATH92)/bin/g++110 174 | CXXFLAGS110 = --std=c++2a $(GCCFLAGS) 175 | LDFLAGS110 = -latomic 176 | .cpp.110: 177 | $(CXX110) $(CXXFLAGS110) $(INCLUDES) $*.cpp $(LDFLAGS110) -o $*110raw.exe 178 | @echo PATH=\"$(PATH110)/bin:\$$PATH\" ./$*110raw.exe '$$*' > $*.exe 179 | @chmod +x $*.exe 180 | @echo "- OK: $* calls $*110raw.exe" 181 | .cxx.110: 182 | sed -f $(TTT2CPP) < $*.cxx > $*.cpp 183 | $(CXX92) $(CXXFLAGS110) $(INCLUDES) $*.cpp $(LDFLAGS110) -o $*110raw.exe 184 | @echo PATH=\"$(PATH110)/bin:\$$PATH\" ./$*110raw.exe '$$*' > $*.exe 185 | @chmod +x $*.exe 186 | @echo "- OK: $* calls $*110raw.exe" 187 | rm $*.cpp 188 | 189 | #---------------------------------------------------- 190 | # gcc 12.0 (with C++20): 191 | 192 | .SUFFIXES: .12 193 | PATH12 = /cygdrive/p/gcc/gcc12 194 | CXX12 = $(PATH92)/bin/g++12 195 | CXXFLAGS12 = --std=c++2a $(GCCFLAGS) 196 | LDFLAGS12 = -latomic 197 | .cpp.12: 198 | $(CXX12) $(CXXFLAGS12) $(INCLUDES) $*.cpp $(LDFLAGS12) -o $*12raw.exe 199 | @echo PATH=\"$(PATH12)/bin:\$$PATH\" ./$*12raw.exe '$$*' > $*.exe 200 | @chmod +x $*.exe 201 | @echo "- OK: $* calls $*101raw.exe" 202 | .cxx.12: 203 | sed -f $(TTT2CPP) < $*.cxx > $*.cpp 204 | $(CXX12) $(CXXFLAGS12) $(INCLUDES) $*.cpp $(LDFLAGS12) -o $*12raw.exe 205 | @echo PATH=\"$(PATH101)/bin:\$$PATH\" ./$*101raw.exe '$$*' > $*.exe 206 | @chmod +x $*.exe 207 | @echo "- OK: $* calls $*101raw.exe" 208 | rm $*.cpp 209 | 210 | 211 | #========================================================== 212 | # gcc C++-specific targets 213 | #========================================================== 214 | 215 | #---------------------------------------------------- 216 | # gcc with C++03 mode: 217 | .SUFFIXES: .03 218 | PATH03 = /cygdrive/p/gcc/gcc48 219 | CXX03 = $(PATH03)/bin/g++48 220 | CXXFLAGS03 = --std=c++03 $(GCCFLAGS) 221 | LDFLAGS03 = 222 | .cpp.03: 223 | $(CXX03) $(CXXFLAGS03) $(INCLUDES) $*.cpp $(LDFLAGS03) -o $*03raw.exe 224 | @echo PATH=\"$(PATH03)/bin:\$$PATH\" ./$*03raw.exe '$$*' > $*.exe 225 | @chmod +x $*.exe 226 | @echo "- OK: $* and $*03 call $*03raw.exe" 227 | .cxx.03: 228 | sed -f $(TTT2CPP) < $*.cxx > $*.cpp 229 | $(CXX03) $(CXXFLAGS03) $(INCLUDES) $*.cpp $(LDFLAGS03) -o $*03raw.exe 230 | @echo PATH=\"$(PATH03)/bin:\$$PATH\" ./$*03raw.exe '$$*' > $*.exe 231 | @chmod +x $*.exe 232 | @echo "- OK: $* and $*03 call $*03raw.exe" 233 | rm $*.cpp 234 | 235 | #---------------------------------------------------- 236 | # gcc with C++11 mode: 237 | .SUFFIXES: .11 238 | PATH11 = /cygdrive/p/gcc/gcc72 239 | CXX11 = $(PATH11)/bin/g++72 240 | CXXFLAGS11 = --std=c++11 $(GCCFLAGS) 241 | LDFLAGS11 = 242 | .cpp.11: 243 | $(CXX11) $(CXXFLAGS11) $(INCLUDES) $*.cpp $(LDFLAGS11) -o $*raw.exe 244 | @echo PATH=\"$(PATH11)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 245 | @chmod +x $*.exe 246 | @echo "- OK: $* calls $*raw.exe" 247 | .cxx.11: 248 | sed -f $(TTT2CPP) < $< > $*.cpp 249 | $(CXX11) $(CXXFLAGS11) $(INCLUDES) $*.cpp $(LDFLAGS11) -o $*raw.exe 250 | @echo PATH=\"$(PATH11)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 251 | @chmod +x $*.exe 252 | @echo "- OK: $* calls $*raw.exe" 253 | rm $*.cpp 254 | 255 | #---------------------------------------------------- 256 | # gcc with C++14 mode: 257 | .SUFFIXES: .14 258 | PATH14 = /cygdrive/p/gcc/gcc72 259 | CXX14 = $(PATH14)/bin/g++72 260 | CXXFLAGS14 = --std=c++14 $(GCCFLAGS) 261 | LDFLAGS14 = 262 | .cpp.14: 263 | $(CXX14) $(CXXFLAGS14) $(INCLUDES) $*.cpp $(LDFLAGS14) -o $*raw.exe 264 | @echo PATH=\"$(PATH14)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 265 | @chmod +x $*.exe 266 | @echo "- OK: $* calls $*raw.exe" 267 | .cxx.14: 268 | sed -f $(TTT2CPP) < $< > $*.cpp 269 | $(CXX14) $(CXXFLAGS14) $(INCLUDES) $*.cpp $(LDFLAGS14) -o $*raw.exe 270 | @echo PATH=\"$(PATH14)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 271 | @chmod +x $*.exe 272 | @echo "- OK: $* calls $*raw.exe" 273 | rm $*.cpp 274 | 275 | #---------------------------------------------------- 276 | # gcc with C++17 mode: 277 | .SUFFIXES: .17 278 | PATH17 = /cygdrive/p/gcc/gcc92 279 | CXX17 = $(PATH17)/bin/g++92 280 | CXXFLAGS17 = --std=c++17 $(GCCFLAGS) 281 | LDFLAGS17 = -latomic 282 | .cpp.17: 283 | $(CXX92) $(CXXFLAGS17) $(INCLUDES) $*.cpp $(LDFLAGS17) -o $*raw.exe 284 | @echo PATH=\"$(PATH17)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 285 | @chmod +x $*.exe 286 | @echo "- OK: $* calls $*raw.exe" 287 | .cxx.17: 288 | sed -f $(TTT2CPP) < $< > $*.cpp 289 | $(CXX92) $(CXXFLAGS17) $(INCLUDES) $*.cpp $(LDFLAGS17) -o $*raw.exe 290 | @echo PATH=\"$(PATH17)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 291 | @chmod +x $*.exe 292 | @echo "- OK: $* calls $*raw.exe" 293 | rm $*.cpp 294 | 295 | #---------------------------------------------------- 296 | # gcc with C++20 mode with concepts: 297 | .SUFFIXES: .20 298 | PATH20 = /cygdrive/p/gcc/gcc120 299 | CXX20 = $(PATH20)/bin/g++120 300 | CXXFLAGS20 = --std=c++20 -fconcepts -fmodules-ts $(GCCFLAGS) 301 | LDFLAGS20 = -latomic 302 | .cpp.20: 303 | $(CXX20) $(CXXFLAGS20) $(INCLUDES) $*.cpp $(LDFLAGS20) -o $*raw.exe 304 | @echo PATH=\"$(PATH20)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 305 | @chmod +x $*.exe 306 | @echo "- OK: $* calls $*raw.exe" 307 | .cxx.20: 308 | sed -f $(TTT2CPP) < $< > $*.cpp 309 | $(CXX20) $(CXXFLAGS20) $(INCLUDES) $*.cpp $(LDFLAGS20) -o $*raw.exe 310 | @echo PATH=\"$(PATH20)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 311 | @chmod +x $*.exe 312 | rm $*.cpp 313 | @echo "- OK: $* calls $*raw.exe" 314 | .cxxm.20: 315 | sed -f $(TTT2CPP) < $< > $*.cppm 316 | $(CXX20) $(CXXFLAGS20) $(INCLUDES) $*.cpp $(LDFLAGS20) -o $*raw.exe 317 | @echo PATH=\"$(PATH20)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 318 | @chmod +x $*.exe 319 | rm $*.cpp 320 | @echo "- OK: $* calls $*raw.exe" 321 | 322 | 323 | #========================================================== 324 | # clang 325 | #========================================================== 326 | 327 | #---------------------------------------------------- 328 | # clang 3.9 for Nico: 329 | .SUFFIXES: .clang 330 | CXXCLANG = clang++ 331 | CXXFLAGSCLANG = --std=c++14 $(GCCFLAGS) 332 | LDFLAGSCLANG = -latomic 333 | .cpp.clang: 334 | $(CXXCLANG) $(CXXFLAGSCLANG) $(INCLUDES) $*.cpp $(LDFLAGSCLANG) -o $*clangraw.exe 335 | @echo ./$*clangraw.exe '$$*' > $*clang.exe 336 | @echo ./$*clangraw.exe '$$*' > $*.exe 337 | @echo "- OK: $* and $*clang call $*clangraw.exe" 338 | .cxx.clang: 339 | sed -f $(TTT2CPP) < $*.cxx > $*.cpp 340 | $(CXXCLANG) $(CXXFLAGSCLANG) $(INCLUDES) $*.cpp $(LDFLAGSCLANG) -o $*clangraw.exe 341 | @echo ./$*clangraw.exe '$$*' > $*clang.exe 342 | @echo ./$*clangraw.exe '$$*' > $*.exe 343 | @echo "- OK: $* and $*clang call $*clangraw.exe" 344 | 345 | #---------------------------------------------------- 346 | 347 | # clang C++17 348 | .SUFFIXES: .clang17 349 | CXXCLANG17 = clang++ 350 | CXXFLAGSCLANG17 = --std=c++1z $(GCCFLAGS) 351 | LDFLAGSCLANG17 = -latomic 352 | .cpp.clang17: 353 | $(CXXCLANG17) $(CXXFLAGSCLANG17) $(INCLUDES) $*.cpp $(LDFLAGSCLANG17) -o $*clang17raw.exe 354 | @echo ./$*clang17raw.exe '$$*' > $*clang.exe 355 | @echo ./$*clang17raw.exe '$$*' > $*.exe 356 | @echo "- OK: $* and $*clang call $*clang17raw.exe" 357 | .cxx.clang17: 358 | sed -f $(TTT2CPP) < $*.cxx > $*.cpp 359 | $(CXXCLANG17) $(CXXFLAGSCLANG) $(INCLUDES) $*.cpp $(LDFLAGSCLANG) -o $*clang17raw.exe 360 | @echo ./$*clang17raw.exe '$$*' > $*clang.exe 361 | @echo ./$*clang17raw.exe '$$*' > $*.exe 362 | @echo "- OK: $* and $*clang call $*clangraw.exe" 363 | 364 | 365 | #---------------------------------------------------- 366 | # clang 367 | 368 | #CXX = xcrun clang++ 369 | #CXXFLAGS = -std=c++11 -stdlib=libc++ -Wall 370 | #LDFLAGS = -stdlib=libc++ 371 | 372 | #---------------------------------------------------- 373 | # Visual Studio: use suffix .win 374 | 375 | WINFLAGS = /Ox /MT /EHsc /W4 /Zc:strictStrings /wd4189 /wd4101 376 | CXXFLAGSWIN = $(WINFLAS) 377 | .SUFFIXES: .win 378 | .cpp.win: 379 | cl $(WINFLAGS) $*.cpp /Fe$* 380 | 381 | #---------------------------------------------------- 382 | # Visual Studio: use suffix .win17 383 | 384 | WIN17FLAGS = /std:c++17 /permissive- $(WINFLAGS) 385 | CXXFLAGSWIN17 = $(WIN17FLAGS) 386 | .SUFFIXES: .win17 387 | .cpp.win17: 388 | cl $(WIN17FLAGS) $*.cpp /Fe$* 389 | 390 | #---------------------------------------------------- 391 | # Visual Studio: use suffix .win20 392 | 393 | WIN20FLAGS = /std:c++20 /permissive- $(WINFLAGS) 394 | CXXFLAGSWIN20 = $(WIN17FLAGS) 395 | .SUFFIXES: .win20 396 | .cxx.win20: 397 | sed -f $(TTT2CPP) < $*.cxx > $*.cpp 398 | cl $(WIN20FLAGS) $*.cpp /Fe$* 399 | .cxxm.win20: 400 | sed -f $(TTT2CPP) < $*.cxxm > $*.cppm 401 | cl $(WIN20FLAGS) $*.cppm /Fe$* 402 | 403 | #---------------------------------------------------- 404 | # Visual Studio: use suffix .winL 405 | 406 | WINLFLAGS = /std:c++latest /permissive- $(WINFLAGS) 407 | CXXFLAGSWINL = $(WINLFLAGS) 408 | .SUFFIXES: .winL 409 | .cxx.winL: 410 | sed -f $(TTT2CPP) < $*.cxx > $*.cpp 411 | cl $(WINLFLAGS) $*.cpp /Fe$* 412 | .cxxm.winL: 413 | sed -f $(TTT2CPP) < $*.cxxm > $*.cppm 414 | cl $(WINLFLAGS) $*.cppm /Fe$* 415 | 416 | 417 | #---------------------------------------------------- 418 | 419 | 420 | TTT2CPP = ../ttt2cpp.sed 421 | 422 | help:: 423 | @echo "all: progs" 424 | 425 | all:: headers progs 426 | html:: headers cpp 427 | 428 | # .cxx: TeX C/C++ Files (new style) 429 | # .hxx: TeX header files (new style) 430 | # .ott: generated output 431 | # .ctt: TeX C/C++ Files 432 | # .htt: TeX header files 433 | # .itt: stdin 434 | # .ott: generated stdout 435 | # .argtt: command line args 436 | .SUFFIXES: .ctt .htt .cxx .hxx .cxxm .cpp .hpp .itt .ott .argtt .oxx .cppm 437 | 438 | .hxx.hpp: 439 | sed -f $(TTT2CPP) < $< > $*.hpp 440 | .cxx.cpp: 441 | sed -f $(TTT2CPP) < $< > $*.cpp 442 | .cxxm.cppm: 443 | sed -f $(TTT2CPP) < $< > $*.cppm 444 | .htt.hpp: 445 | sed -f $(TTT2CPP) < $< > $*.hpp 446 | .ctt.cpp: 447 | sed -f $(TTT2CPP) < $< > $*.cpp 448 | #.cpp: 449 | # $(CXX) $(CXXFLAGS) $(INCLUDES) $*.cpp $(LDFLAGS) -o $*raw.exe 450 | # @echo PATH=\"$(PATH)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 451 | # @echo PATH=\"$(PATH)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 452 | # @echo "- OK: $* calls $*raw.exe" 453 | 454 | #FS_INCL=/cygdrive/p/boost/cygwin/include 455 | ##FS_LIB=/cygdrive/p/boost/cygwin/lib -lboost_filesystem -lboost_system -static 456 | ##FS_LIB=/cygdrive/p/boost/cygwin/lib libboost_filesystem.a libboost_system.a 457 | #FS_LIB=/cygdrive/p/boost/cygwin/lib -Wl,-Bstatic -lboost_system -lboost_filesystem -lboost_system -Wl,-Bdynamic 458 | #.cxx: 459 | # sed -f $(TTT2CPP) < $< > $*.cpp 460 | # $(CXX) $(CXXFLAGS) $(INCLUDES) -I$(FS_INCL) $*.cpp $(LDFLAGS) -L$(FS_LIB) -o $*raw.exe 461 | # @echo PATH=\"$(PATHDEF)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 462 | # @echo PATH=\"$(PATHDEF)/bin:\$$PATH\" ./$*raw.exe '$$*' > $*.exe 463 | # @echo "- OK: $* calls $*raw.exe" 464 | # rm $*.cpp 465 | 466 | 467 | ############ clean and delete ########################## 468 | help:: 469 | @echo 'clean: remove all except generated executables' 470 | @echo 'delete: remove every generated file' 471 | clean:: 472 | rm -rf *.o *.obj *.exe *~ 473 | rm -rf *.ifc gcm.cache 474 | 475 | delete:: clean 476 | rm -rf *.exe 477 | 478 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # clmod.py 2 | 3 | A script to let Visual C++ deal easily with C++20 programs using modules. 4 | 5 | ## Why? 6 | 7 | C++20 introduced modules. 8 | Unfortunately it is still not possible to write C++ programs using modules that are portable 9 | without significant effort. 10 | The reason is that the different compiler vendors could not agree on a common way to treat module files. 11 | While gcc/g++ does not require any special suffix, other compiler do it (with different recommended suffixes). 12 | 13 | In fact, Visual C++ does 14 | - require **special suffixes** for specific module files and/or 15 | **special options** to be set when compiling some module files 16 | - not allow to request a compilation of different module files with ONE command 17 | - does neither document the requested file suffixes nor the necessary command-line options 18 | 19 | Here is what Visual C++ needs in detail for module files: 20 | - **Interface files** (module interface or interface partition) 21 | need suffix `.ixx` or the option `/interface` 22 | - **Internal partitions** need the option `/internalPartition` 23 | (the suffix doesn't matter; they recommend the usual suffix such as .cpp). 24 | - **Module implementation units** need no specific module treatment 25 | (use the usual suffix with no special option) 26 | - Options `/interface` and `/internalPartition` may not be used together 27 | 28 | This is a significant restriction because other compilers do neither need 29 | special suffixes nor special options but also do not know what to do with the 30 | `.ixx` suffix Microsoft recommends. 31 | 32 | To circumvent this restriction and bring the idea of portable module files 33 | to life, I have implemented a Python script that gives Visual C++ the flexibility it should have. 34 | 35 | The attached script 36 | **clmod.py** 37 | is a Python script that allows to 38 | - use arbitrary file name suffixes for module files 39 | - allows to pass all files with one command line 40 | 41 | This does not mean that different file suffixes may not make sense to deal 42 | with C++ module files. But it helps until we see an established portable 43 | supported policy for them. 44 | 45 | ## For example 46 | 47 | Assume for a module ModAll (see the subdirectory testall), 48 | we have: 49 | - **modall_if.cppm** : The module interface unit 50 | - **modall_ifpart.cppm** : An interface partition unit 51 | - **modall_part.cppm** : An internal partition 52 | - **modall_impl.cpp** : An implementation unit 53 | 54 | and to test this we have: 55 | - **modall_test.cpp** : A traditional translation unit 56 | 57 | Calling: 58 | 59 | clmod.py /std:c++latest modall_part.cppm modall_ifpart.cppm modall_if.cppm modall_impl.cpp modall_test.cpp /Femodall.exe 60 | 61 | will automatically do the right thing: 62 | 63 | cl /std:c++latest /Femodall.exe /TP /c /internalPartition modall_part.cppm 64 | cl /std:c++latest /Femodall.exe /TP /c /interface modall_ifpart.cppm 65 | cl /std:c++latest /Femodall.exe /TP /c /interface modall_if.cppm 66 | cl /std:c++latest /Femodall.exe /TP /c modall_impl.cpp 67 | cl /std:c++latest /Femodall.exe /TP /c modall_test.cpp 68 | cl /std:c++latest /Femodall.exe modall_part.obj modall_ifpart.obj modall_if.obj modall_impl.obj modall_test.obj 69 | 70 | Note that the order of the files matters; the script will not sort that out for you. 71 | (Files that import modules need the pre-compiled module code, which is compiler-specific, and circular imports are not possible). 72 | 73 | As you can see, the script passes all options to both the compile and the link command (passing link options such as `/Femodall.exe` to the compile command is not necessary but also doesn't hurt). 74 | That might not work with all options. 75 | `/c` (compile only) is handled by the script to not start the linker. 76 | 77 | For simple tests with C++20 modules the script should works fine. 78 | Let us hope that Microsoft soon adds corresponding flexibility to deal with module files themselves. 79 | 80 | I have opened bug reports for that: 81 | - https://developercommunity.visualstudio.com/t/Using-modules-I-cant-compile-all-C-fi/10015356 82 | (this bug was officially rejected) 83 | - https://developercommunity.visualstudio.com/t/Csource-files-should-be-able-to-have-t/10013381 84 | 85 | And if you like this way to deal with C++ examples using modules, please open a bur report yourself. 86 | I have an inofficial feedback that they will provide it once they see the demand. So far they do not see it. 87 | 88 | 89 | 90 | ## Tests 91 | 92 | I have provided the following subdirectories to test the script: 93 | - **testsimple**: a simple module example using only a module interface 94 | - **testall**: a full module example using for all module units the extension `.cppm` 95 | - **testallixx**: a full module example using Visual C++ conventions (`.ixx` for interface files) 96 | - **testallcpp**: a full module example using `.cpp` for all files (as gcc supports) 97 | 98 | ## More 99 | 100 | For more details how to implement and deal with C++20 modules 101 | see 102 | 103 | > C++20 - The Complete Guide by Nicolai M. Josuttis 104 | > 105 | > http://cppstd20.com 106 | 107 | ## Feedback 108 | 109 | I am happy about any constructive feedback. 110 | Please use the feedback address of my C++20 book: http://cppstd20.com/feedback 111 | 112 | ## License 113 | 114 | The code is licensed under a Creative Commons Attribution 4.0 International License. 115 | 116 | http://creativecommons.org/licenses/by/4.0/ 117 | 118 | 119 | -------------------------------------------------------------------------------- /clmod.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | ############################################################################## 3 | # Python script to let Visual C++ deal with C++ source code using modules 4 | # - supporting arbitrary file suffixes 5 | # - without the need to use undocumented options 6 | # - passing all files one one command line 7 | # 8 | # Can also be used as skeleton for other tools to handle C++ units differently. 9 | # 10 | # Special handling: 11 | # Pass "-debug" to have verbose output 12 | ############################################################################## 13 | 14 | import sys 15 | import os 16 | import re 17 | import subprocess 18 | 19 | ############################################################################## 20 | # global flags 21 | ############################################################################## 22 | 23 | debug = False # may be turned on with -debug 24 | 25 | 26 | ############################################################################## 27 | # getModulesType() 28 | # - parses the give file to find out its unit type: 29 | # - returns: 30 | # "tu" for traditional translation unit 31 | # "ifm" for primary module interface unit 32 | # "ifp" for interface partition unit 33 | # "int" for internal partition unit 34 | # "impl" for module im0plementation unit 35 | ############################################################################## 36 | def getModulesType(filename): 37 | #print("\n=== getModulesOpt() for", filename) 38 | if not os.path.isfile(filename): 39 | print ("*** ERROR: '" + filename + "' doesn't exist") 40 | sys.exit(1) 41 | 42 | inGlobalModuleFragment = False 43 | inComment = False 44 | 45 | with open(filename, 'r') as f: 46 | for rawline in f: 47 | line = rawline.strip() 48 | 49 | # am I inside /* ... */ comment? 50 | if inComment: 51 | idxClose = line.find("*/") 52 | if idxClose >= 0: 53 | line = line[idxClose+2:] 54 | inComment = False 55 | else: 56 | continue 57 | 58 | # ignore // comment 59 | idx = line.find("//") 60 | if idx >= 0: 61 | line = line[:idx] 62 | 63 | # ignore /* ... */ comment 64 | idxOpen = line.find("/*") 65 | while idxOpen >= 0: 66 | idxClose = line.find("*/") 67 | 68 | if idxClose >= 0: 69 | line = line[:idxOpen] + line[idxClose+2:] 70 | else: 71 | line = line[:idxOpen] 72 | inComment = True 73 | break 74 | 75 | idxOpen = line.find("/*") 76 | 77 | # ignore empty line: 78 | if not line: 79 | continue 80 | 81 | if line.startswith("module;"): 82 | inGlobalModuleFragment = True 83 | continue 84 | 85 | # preprocessor commands in global module fragment ignored: 86 | if inGlobalModuleFragment and line.startswith("#"): 87 | continue 88 | 89 | if not line.startswith("module") and \ 90 | not line.startswith("export module"): 91 | # traditional translation unit => no special options 92 | if debug: 93 | print(" >", rawline) 94 | print(" ", filename, "is no module unit") 95 | return "tu" # RETURN "traditional translation unit" 96 | 97 | # module unit: check its type: 98 | m = re.search("export module ([a-zA-Z0-9]*):([a-zA-Z0-9]*)", line) 99 | if m: 100 | # interface partition: 101 | if debug: 102 | print(" >", rawline) 103 | print(" ", filename, "is interface partition '" + m.group(2) + 104 | "' in module '" + m.group(1) + "'") 105 | return "ifp" # RETURN "interface partition" 106 | 107 | m = re.search("export module ([a-zA-Z0-9]*)", line) 108 | if m: 109 | # primary module interface: 110 | if debug: 111 | print(" >", rawline) 112 | print(" ", filename, "is interface of module '" + m.group(1) + "'") 113 | return "ifm" # RETURN "primary module interface" 114 | 115 | m = re.search("module ([a-zA-Z0-9]*):([a-zA-Z0-9]*)", line) 116 | if m: 117 | # internal partition: 118 | if debug: 119 | print(" >", rawline) 120 | print(" ", filename, "is internal partition '" + m.group(2) + 121 | "' in module '" + m.group(1) + "'") 122 | return "int" # RETURN "internal partition" 123 | 124 | m = re.search("module ([a-zA-Z0-9]*)", line) 125 | if m: 126 | # implementation unit: 127 | if debug: 128 | print(" >", rawline) 129 | print(" ", filename, "is implementation unit of module '" + m.group(1) + "'") 130 | return "impl" # RETURN "implementation unit 131 | 132 | # could not decide: 133 | print("*** ERROR: could not categorize", filename) 134 | sys.exit(1) 135 | 136 | 137 | ############################################################################## 138 | # getModulesOpt() 139 | # - return the command line options Visual C++ need for the passed unit 140 | ############################################################################## 141 | def getModulesOpt(filename): 142 | type = getModulesType(filename) 143 | if type == "int": 144 | return "/internalPartition" 145 | if type == "ifm": 146 | return "/interface" 147 | if type == "ifp": 148 | return "/interface" 149 | if type == "impl": 150 | return "" 151 | if type == "tu": 152 | return "" 153 | # could not decide: 154 | print("*** ERROR: invalid unit type: ", type, "for", filename) 155 | sys.exit(1) 156 | 157 | 158 | ############################################################################## 159 | # run() 160 | # - runs a systemn command with the passed args 161 | ############################################################################## 162 | def run(args): 163 | # since Python 3.4 we can use run() but let's support older Python versions: 164 | # if sys.version_info[0] > 3 or \ 165 | # (sys.version_info[0] > 2 and sys.version_info[1] > 4): 166 | # p = subprocess.run(args) 167 | p = subprocess.Popen(args) 168 | p.wait() 169 | return p 170 | 171 | 172 | ############################################################################## 173 | # MAIN 174 | ############################################################################## 175 | 176 | # parse all command-line options 177 | # - separationg files (having a dot inside) 178 | # - from compiler/linker options (the rest) 179 | files = [] 180 | flags = [] 181 | compileOnly = False 182 | for opt in sys.argv[1:]: 183 | #print(opt) 184 | if (opt == "-debug"): 185 | debug = True 186 | continue 187 | if (opt == "/c"): 188 | compileOnly = False 189 | continue 190 | if opt.startswith("/"): 191 | flags.append(opt) 192 | continue 193 | if "." in opt: 194 | files.append(opt) 195 | else: 196 | flags.append(opt) 197 | 198 | #print("files: ", files) 199 | #print("flags: ", flags) 200 | 201 | # iterate over all files 202 | # - checking the unit type 203 | # - traditional non-module translation unit or 204 | # - one of the module unit types 205 | # - compile each file accordingly 206 | print("COMPILE:") 207 | objfiles = [] 208 | for filename in files: 209 | print("\n*** COMPILE '" + filename + "'") 210 | m = re.search("^(.*)\.([^.]*)$", filename) 211 | if not m: 212 | print("*** ERROR: file", filename, "has no suffix") 213 | sys.exit(1) 214 | fileopt = getModulesOpt(filename) 215 | # compile code: 216 | print("*** cl ", " ".join(flags), "/TP", "/c", fileopt, filename) 217 | if not fileopt or fileopt == "": 218 | p = run(["cl"] + flags + ["/TP", "/c", filename]) 219 | else: 220 | p = run(["cl"] + flags + ["/TP", "/c", fileopt, filename]) 221 | if p.returncode != 0: 222 | print("*** ERROR: compiling", filename, "failed") 223 | sys.exit(1) 224 | objfiles.append(m.group(1) + ".obj") 225 | 226 | # link generated object files 227 | if not compileOnly: 228 | print("\n*** LINK:") 229 | print("*** cl ", " ".join(flags), " ".join(objfiles)) 230 | p = run(["cl"] + flags + objfiles) 231 | if p.returncode != 0: 232 | print("*** ERROR: linking failed") 233 | sys.exit(1) 234 | 235 | -------------------------------------------------------------------------------- /testall/Makefile: -------------------------------------------------------------------------------- 1 | default: modall.win 2 | 3 | include ../Makefile.h 4 | 5 | ########################################### 6 | # generic rules for special module suffixes 7 | ########################################### 8 | 9 | .SUFFIXES: .cppm .cppp .obj .ixx 10 | .ixx.obj: 11 | @echo "" 12 | cl $(CXXFLAGSWINL) /TP /c /interface $*.ixx $(IFCDIRFLAGS) 13 | @echo "=== $*.obj done" 14 | @echo "" 15 | .cppm.obj: 16 | @echo "" 17 | cl $(CXXFLAGSWINL) /TP /c /interface $*.cppm $(IFCDIRFLAGS) 18 | @echo "=== $*.obj done" 19 | @echo "" 20 | .cppp.obj: 21 | @echo "" 22 | cl $(CXXFLAGSWINL) /TP /c /internalPartition $*.cppp $(IFCDIRFLAGS) 23 | @echo "=== $*.obj done" 24 | @echo "" 25 | .cpp.obj: 26 | @echo "" 27 | cl $(CXXFLAGSWINL) /c $*.cpp $(IFCDIRFLAGS) 28 | @echo "=== $*.obj done" 29 | @echo "" 30 | 31 | ########################################### 32 | # targets for Visual C++ and GCC 33 | ########################################### 34 | 35 | modall.win: modall_part.cppm modall_ifpart.cppm modall_if.cppm modall_impl.cpp modall_test.cpp 36 | @echo "" 37 | @echo "=== COMPILE & LINK:" 38 | ../clmod.py $(CXXFLAGSWINL) modall_part.cppm modall_ifpart.cppm modall_if.cppm modall_impl.cpp modall_test.cpp $(LDFLAGSWIN) /Femodall.exe 39 | #rm -f *.obj *.ifc 40 | @echo "- OK: modall.exe done" 41 | 42 | modall.gcc: modall_part.cppm modall_ifpart.cppm modall_if.cppm modall_impl.cpp modall_test.cpp 43 | @echo "" 44 | @echo "=== COMPILE & LINK:" 45 | $(CXX20) $(CXXFLAGS20) -xc++ modall_part.cppm -xc++ modall_ifpart.cppm -xc++ modall_if.cppm modall_impl.cpp modall_test.cpp $(LDFLAGS20) -o modall.exe 46 | #rm -rf *.o gcm.cache 47 | @echo "- OK: modall.exe done" 48 | 49 | -------------------------------------------------------------------------------- /testall/modall_if.cppm: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | module; // start module unit with global module fragment 14 | 15 | #include 16 | 17 | // THE module interface 18 | export module ModAll; 19 | 20 | // import and export interface partition Person: 21 | export import :Person; 22 | 23 | // export a string and a generic function: 24 | export namespace ModAll { 25 | 26 | auto modName() { 27 | return "ModAll"; 28 | } 29 | 30 | void printColl(auto&& coll) { 31 | for (const auto& elem : coll) { 32 | std::cout << elem << ' '; 33 | } 34 | std::cout << '\n'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /testall/modall_ifpart.cppm: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | module; // start module unit with global module fragment 14 | 15 | #include 16 | 17 | // Moule interface partition: 18 | export module ModAll:Person; 19 | 20 | import :Name; // import internal partition to have type Name 21 | 22 | // export a string and a generic function: 23 | export namespace ModAll { 24 | 25 | class Person { 26 | private: 27 | Name name; 28 | int value = 0; 29 | public: 30 | Person(std::string n, int v = 0) 31 | : name{std::move(n)}, value{v} { 32 | } 33 | friend std::ostream& operator<< (std::ostream&, const Person&); 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /testall/modall_impl.cpp: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | module; // start module unit with global module fragment 14 | 15 | #include 16 | 17 | // module implementation unit: 18 | module ModAll; 19 | 20 | import :Name; // import internal partition to have type Name 21 | 22 | namespace ModAll { 23 | 24 | std::ostream& operator<< (std::ostream& strm, const Person& p) 25 | { 26 | return strm << '[' << p.name << ": " << p.value << ']'; 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /testall/modall_part.cppm: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | module; // start module unit with global module fragment 14 | 15 | #include 16 | #include 17 | 18 | // internal partition: 19 | module ModAll:Name; 20 | 21 | class Name { 22 | private: 23 | std::string name; 24 | public: 25 | Name(std::string n) 26 | : name{std::move(n)} { 27 | assert(!name.empty()); // require non-empty name 28 | } 29 | 30 | friend std::ostream& operator<< (std::ostream& strm, const Name& n) { 31 | return strm << n.name; 32 | } 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /testall/modall_test.cpp: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | #include 14 | 15 | import ModAll; 16 | 17 | int main() 18 | { 19 | std::cout << "test " << ModAll::modName() << '\n'; 20 | ModAll::Person p1{"Kim", 42}; 21 | std::cout << "p1: " << p1 << '\n'; 22 | } 23 | -------------------------------------------------------------------------------- /testallcpp/Makefile: -------------------------------------------------------------------------------- 1 | default: modall.win 2 | 3 | include ../Makefile.h 4 | 5 | ########################################### 6 | # generic rules for special module suffixes 7 | ########################################### 8 | 9 | .SUFFIXES: .cppm .cppp .obj .ixx 10 | .ixx.obj: 11 | @echo "" 12 | cl $(CXXFLAGSWINL) /TP /c /interface $*.ixx $(IFCDIRFLAGS) 13 | @echo "=== $*.obj done" 14 | @echo "" 15 | .cppm.obj: 16 | @echo "" 17 | cl $(CXXFLAGSWINL) /TP /c /interface $*.cppm $(IFCDIRFLAGS) 18 | @echo "=== $*.obj done" 19 | @echo "" 20 | .cppp.obj: 21 | @echo "" 22 | cl $(CXXFLAGSWINL) /TP /c /internalPartition $*.cppp $(IFCDIRFLAGS) 23 | @echo "=== $*.obj done" 24 | @echo "" 25 | .cpp.obj: 26 | @echo "" 27 | cl $(CXXFLAGSWINL) /c $*.cpp $(IFCDIRFLAGS) 28 | @echo "=== $*.obj done" 29 | @echo "" 30 | 31 | ########################################### 32 | # targets for Visual C++ and GCC 33 | ########################################### 34 | 35 | modall.win: modall_part.cpp modall_ifpart.cpp modall_if.cpp modall_impl.cpp modall_test.cpp 36 | @echo "" 37 | @echo "=== COMPILE & LINK:" 38 | ../clmod.py $(CXXFLAGSWINL) modall_part.cpp modall_ifpart.cpp modall_if.cpp modall_impl.cpp modall_test.cpp $(LDFLAGSWIN) /Femodall.exe 39 | #rm -f *.obj *.ifc 40 | @echo "- OK: modall.exe done" 41 | 42 | modall.gcc: modall_part.cpp modall_ifpart.cpp modall_if.cpp modall_impl.cpp modall_test.cpp 43 | @echo "" 44 | @echo "=== COMPILE & LINK:" 45 | $(CXX20) $(CXXFLAGS20) modall_part.cpp modall_ifpart.cpp modall_if.cpp modall_impl.cpp modall_test.cpp $(LDFLAGS20) -o modall.exe 46 | #rm -rf *.o gcm.cache 47 | @echo "- OK: modall.exe done" 48 | 49 | -------------------------------------------------------------------------------- /testallcpp/modall_if.cpp: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | module; // start module unit with global module fragment 14 | 15 | #include 16 | 17 | // THE module interface 18 | export module ModAll; 19 | 20 | // import and export interface partition Person: 21 | export import :Person; 22 | 23 | // export a string and a generic function: 24 | export namespace ModAll { 25 | 26 | auto modName() { 27 | return "ModAll"; 28 | } 29 | 30 | void printColl(auto&& coll) { 31 | for (const auto& elem : coll) { 32 | std::cout << elem << ' '; 33 | } 34 | std::cout << '\n'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /testallcpp/modall_ifpart.cpp: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | module; // start module unit with global module fragment 14 | 15 | #include 16 | 17 | // Moule interface partition: 18 | export module ModAll:Person; 19 | 20 | import :Name; // import internal partition to have type Name 21 | 22 | // export a string and a generic function: 23 | export namespace ModAll { 24 | 25 | class Person { 26 | private: 27 | Name name; 28 | int value = 0; 29 | public: 30 | Person(std::string n, int v = 0) 31 | : name{std::move(n)}, value{v} { 32 | } 33 | friend std::ostream& operator<< (std::ostream&, const Person&); 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /testallcpp/modall_impl.cpp: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | module; // start module unit with global module fragment 14 | 15 | #include 16 | 17 | // module implementation unit: 18 | module ModAll; 19 | 20 | import :Name; // import internal partition to have type Name 21 | 22 | namespace ModAll { 23 | 24 | std::ostream& operator<< (std::ostream& strm, const Person& p) 25 | { 26 | return strm << '[' << p.name << ": " << p.value << ']'; 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /testallcpp/modall_part.cpp: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | module; // start module unit with global module fragment 14 | 15 | #include 16 | #include 17 | 18 | // internal partition: 19 | module ModAll:Name; 20 | 21 | class Name { 22 | private: 23 | std::string name; 24 | public: 25 | Name(std::string n) 26 | : name{std::move(n)} { 27 | assert(!name.empty()); // require non-empty name 28 | } 29 | 30 | friend std::ostream& operator<< (std::ostream& strm, const Name& n) { 31 | return strm << n.name; 32 | } 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /testallcpp/modall_test.cpp: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | #include 14 | 15 | import ModAll; 16 | 17 | int main() 18 | { 19 | std::cout << "test " << ModAll::modName() << '\n'; 20 | ModAll::Person p1{"Kim", 42}; 21 | std::cout << "p1: " << p1 << '\n'; 22 | } 23 | -------------------------------------------------------------------------------- /testallixx/Makefile: -------------------------------------------------------------------------------- 1 | default: modall.win 2 | 3 | include ../Makefile.h 4 | 5 | ########################################### 6 | # generic rules for special module suffixes 7 | ########################################### 8 | 9 | .SUFFIXES: .cppm .cppp .obj .ixx 10 | .ixx.obj: 11 | @echo "" 12 | cl $(CXXFLAGSWINL) /TP /c /interface $*.ixx $(IFCDIRFLAGS) 13 | @echo "=== $*.obj done" 14 | @echo "" 15 | .cppm.obj: 16 | @echo "" 17 | cl $(CXXFLAGSWINL) /TP /c /interface $*.cppm $(IFCDIRFLAGS) 18 | @echo "=== $*.obj done" 19 | @echo "" 20 | .cppp.obj: 21 | @echo "" 22 | cl $(CXXFLAGSWINL) /TP /c /internalPartition $*.cppp $(IFCDIRFLAGS) 23 | @echo "=== $*.obj done" 24 | @echo "" 25 | .cpp.obj: 26 | @echo "" 27 | cl $(CXXFLAGSWINL) /c $*.cpp $(IFCDIRFLAGS) 28 | @echo "=== $*.obj done" 29 | @echo "" 30 | 31 | ########################################### 32 | # targets for Visual C++ and GCC 33 | ########################################### 34 | 35 | modall.win: modall_part.cpp modall_ifpart.ixx modall_if.ixx modall_impl.cpp modall_test.cpp 36 | @echo "" 37 | @echo "=== COMPILE & LINK:" 38 | ../clmod.py $(CXXFLAGSWINL) modall_part.cpp modall_ifpart.ixx modall_if.ixx modall_impl.cpp modall_test.cpp $(LDFLAGSWIN) /Femodall.exe 39 | #rm -f *.obj *.ifc 40 | @echo "- OK: modall.exe done" 41 | 42 | modall.gcc: modall_part.cpp modall_ifpart.ixx modall_if.ixx modall_impl.cpp modall_test.cpp 43 | @echo "" 44 | @echo "=== COMPILE & LINK:" 45 | $(CXX20) $(CXXFLAGS20) modall_part.cpp -xc++ modall_ifpart.ixx -xc++ modall_if.ixx modall_impl.cpp modall_test.cpp $(LDFLAGS20) -o modall.exe 46 | #rm -rf *.o gcm.cache 47 | @echo "- OK: modall.exe done" 48 | 49 | -------------------------------------------------------------------------------- /testallixx/modall_if.ixx: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | module; // start module unit with global module fragment 14 | 15 | #include 16 | 17 | // THE module interface 18 | export module ModAll; 19 | 20 | // import and export interface partition Person: 21 | export import :Person; 22 | 23 | // export a string and a generic function: 24 | export namespace ModAll { 25 | 26 | auto modName() { 27 | return "ModAll"; 28 | } 29 | 30 | void printColl(auto&& coll) { 31 | for (const auto& elem : coll) { 32 | std::cout << elem << ' '; 33 | } 34 | std::cout << '\n'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /testallixx/modall_ifpart.ixx: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | module; // start module unit with global module fragment 14 | 15 | #include 16 | 17 | // Moule interface partition: 18 | export module ModAll:Person; 19 | 20 | import :Name; // import internal partition to have type Name 21 | 22 | // export a string and a generic function: 23 | export namespace ModAll { 24 | 25 | class Person { 26 | private: 27 | Name name; 28 | int value = 0; 29 | public: 30 | Person(std::string n, int v = 0) 31 | : name{std::move(n)}, value{v} { 32 | } 33 | friend std::ostream& operator<< (std::ostream&, const Person&); 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /testallixx/modall_impl.cpp: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | module; // start module unit with global module fragment 14 | 15 | #include 16 | 17 | // module implementation unit: 18 | module ModAll; 19 | 20 | import :Name; // import internal partition to have type Name 21 | 22 | namespace ModAll { 23 | 24 | std::ostream& operator<< (std::ostream& strm, const Person& p) 25 | { 26 | return strm << '[' << p.name << ": " << p.value << ']'; 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /testallixx/modall_part.cpp: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | module; // start module unit with global module fragment 14 | 15 | #include 16 | #include 17 | 18 | // internal partition: 19 | module ModAll:Name; 20 | 21 | class Name { 22 | private: 23 | std::string name; 24 | public: 25 | Name(std::string n) 26 | : name{std::move(n)} { 27 | assert(!name.empty()); // require non-empty name 28 | } 29 | 30 | friend std::ostream& operator<< (std::ostream& strm, const Name& n) { 31 | return strm << n.name; 32 | } 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /testallixx/modall_test.cpp: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | #include 14 | 15 | import ModAll; 16 | 17 | int main() 18 | { 19 | std::cout << "test " << ModAll::modName() << '\n'; 20 | ModAll::Person p1{"Kim", 42}; 21 | std::cout << "p1: " << p1 << '\n'; 22 | } 23 | -------------------------------------------------------------------------------- /testsimple/Makefile: -------------------------------------------------------------------------------- 1 | default: modsimple.win 2 | 3 | include ../Makefile.h 4 | 5 | ########################################### 6 | # generic rules for special module suffixes 7 | ########################################### 8 | 9 | .SUFFIXES: .cppm .cppp .obj .ixx 10 | .ixx.obj: 11 | @echo "" 12 | cl $(CXXFLAGSWINL) /TP /c /interface $*.ixx $(IFCDIRFLAGS) 13 | @echo "=== $*.obj done" 14 | @echo "" 15 | .cppm.obj: 16 | @echo "" 17 | cl $(CXXFLAGSWINL) /TP /c /interface $*.cppm $(IFCDIRFLAGS) 18 | @echo "=== $*.obj done" 19 | @echo "" 20 | .cppp.obj: 21 | @echo "" 22 | cl $(CXXFLAGSWINL) /TP /c /internalPartition $*.cppp $(IFCDIRFLAGS) 23 | @echo "=== $*.obj done" 24 | @echo "" 25 | .cpp.obj: 26 | @echo "" 27 | cl $(CXXFLAGSWINL) /c $*.cpp $(IFCDIRFLAGS) 28 | @echo "=== $*.obj done" 29 | @echo "" 30 | 31 | ########################################### 32 | # targets for Visual C++ and GCC 33 | ########################################### 34 | 35 | modsimple.win: modsimple_if.cppm modsimple_test.cpp 36 | @echo "" 37 | @echo "=== COMPILE & LINK:" 38 | ../clmod.py $(CXXFLAGSWINL) modsimple_if.cppm modsimple_test.cpp $(LDFLAGSWIN) /Femodsimple.exe 39 | #rm -f *.obj *.ifc 40 | @echo "- OK: modsimple.exe done" 41 | 42 | modsimple.gcc: modsimple_if.cppm modsimple_test.cpp 43 | @echo "" 44 | @echo "=== COMPILE & LINK:" 45 | $(CXX20) $(CXXFLAGS20) -xc++ modsimple_if.cppm modsimple_test.cpp $(LDFLAGS20) -o modsimple.exe 46 | #rm -rf *.o gcm.cache 47 | @echo "- OK: modsimple.exe done" 48 | 49 | -------------------------------------------------------------------------------- /testsimple/modsimple_if.cppm: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | // THE module interface 14 | export module ModSquare; 15 | 16 | int square(int i); 17 | 18 | export class Square { 19 | private: 20 | int value; 21 | public: 22 | Square(int i) 23 | : value{square(i)} { 24 | } 25 | int getValue() const { 26 | return value; 27 | } 28 | }; 29 | 30 | export template 31 | Square toSquare(const T& x) { 32 | return Square{x}; 33 | } 34 | 35 | int square(int i) { 36 | return i * i; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /testsimple/modsimple_test.cpp: -------------------------------------------------------------------------------- 1 | //******************************************************** 2 | // The following C++ code example uses all module artefacts. 3 | // To understand it see 4 | // C++20 - The Complete Guide 5 | // by Nicolai M. Josuttis (www.josuttis.com) 6 | // http://www.cppstd20.com 7 | // 8 | // The code is licensed under a 9 | // Creative Commons Attribution 4.0 International License 10 | // http://creativecommons.org/licenses/by/4.0/ 11 | //******************************************************** 12 | 13 | #include 14 | 15 | import ModSquare; // import module ModSquare 16 | 17 | int main() 18 | { 19 | Square x = toSquare(42); 20 | std::cout << x.getValue() << '\n'; 21 | } 22 | 23 | --------------------------------------------------------------------------------