A 'lazy' compilation mode to make writting multiplatform code easier without having to clutter the project

ryuukk_ ryuukk.dev at gmail.com
Wed Feb 22 14:23:09 UTC 2023


Hello,

My project is kinda special, i am targeting all 3 major desktop 
OS's as well as the web with WebAssembly

So my code is full of ``version(WASM) / version(Windows)``, i 
wish i didn't need to do that because it clutters the code for no 
real benefits, makes things harder to follow/read as i constantly 
need to readjust to the indentation level and need to process 
version() despite my function named properly

It's kinda repeating the C/C++ mistake with 
unreadable/unfollowable ``#ifdef`` everywhere

I try to structure my code so that i put platform specific code 
is in their own module when it's too big

But for 3-4 simple functions it gets annoying real quick

When i separate platform specific code into their own modules, i 
have then to do a lot of maintenance to then include the proper 
modules when i compile for the specific target, or when i 
refactor my code, i need to make sure my ``dub.json`` is in sync

This is kinda annoying..

So what if the compiler would follow the code path and only 
compile what is used from the module, so there is no longer a 
need to be overly noisy with bunches of ``version`` code blocks 
and extra indentation everywhere

One benefit of that mode would be faster builds when importing 
modules from phobos when one need just few functions from it 

Because right now it is very ugly, and my ``dub.json`` gets quite 
large that it becomes painful to read/edit (yeah, i'm also not a 
fan of json, it's too noisy/verbose)


```json
{
     "name": "game",
     "targetType": "executable",
     "targetName": "game",
     "targetPath": "../../bin",
     "workingDirectory": "../../bin",
     "sourcePaths": [ "src" ],
     "importPaths": [ "src" ],

     "stringImportPaths": [
         "../../bin/"
     ],

     "buildTypes": {
         "prod": {
             "buildOptions": [ "releaseMode" ],
             "versions": [ "PROD" ],
             "dflags": [
                 "-preview=rvaluerefparam",
             ],
             "dflags-ldc": [
                 "-O3",
             ],
             "dflags-windows-ldc": [
                 "-O3",
             ],
         },
         "prod-debug": {
             "buildOptions": [ "debugMode", "debugInfo" ],
             "versions": [ "PROD" ]
         },
     },

     "configurations": [
         {
             "name": "desktop",
             "mainSourceFile": "src/app.d",
             "versions": [ "GAME", "DESKTOP", "MONGOOSE", "GL_30", 
"GLFW_33", "FT_211", "BindFT_Static"],
             "sourcePaths": [
                 "../../better_d/rt",
                 "../../better_d/network",
                 "../../better_d/mongoose",
                 "../../better_d/glfw",

                 "../dawn",
                 "../kshared/",
             ],
             "importPaths": [
                 "../../better_d/",
                 "../../better_d/rt",
                 "../",
             ],
             "libs-windows": [
                 "ws2_32",
                 "Winmm",
                 "USER32",
                 "GDI32",
                 "ADVAPI32",
                 "CRYPT32",
                 "Shell32"
             ],
             "libs-linux": ["freetype", "z", "ssl", "crypto", 
"x11"],
             "sourceFiles-windows": [
                 "../../better_d/glfw/bin/windows/glfw3.lib",
                 
"../../better_d/freetype/bin/windows/freetype.lib",

                 
"../../better_d/mongoose/bin/windows/libcrypto.lib",
                 "../../better_d/mongoose/bin/windows/libssl.lib",
                 
"../../better_d/mongoose/bin/windows/mongoose.lib",

                 "../../better_d/zlib/bin/windows/zlib.lib",
             ],
             "sourceFiles-linux": [
                 "../../better_d/glfw/bin/linux/libglfw3.a",
                 "../../better_d/mongoose/bin/linux/mongoose.a",
             ],
             "dflags": [
                 "-preview=rvaluerefparam",
                 "-betterC"
             ],
             "dflags-dmd": [
                 "-preview=bitfields",
             ],
	        "lflags-windows-dmd": [ "/OPT:REF"],

             "lflags-windows": [
                 "/NODEFAULTLIB:libcmt.lib"
             ],
         },

         {
             "name": "dll",
             "versions": [ "GAME", "DESKTOP", "MONGOOSE", "GL_30", 
"GLFW_33", "FT_211", "BindFT_Static"],
             "targetType": "dynamicLibrary",
             "targetName": "gamed",
             "sourcePaths": [
                 "../../better_d/rt",
                 "../../better_d/network",
                 "../../better_d/mongoose",
                 "../../better_d/glfw",

                 "../dawn",
                 "../kshared/",
             ],
             "importPaths": [
                 "../../better_d/",
                 "../../better_d/rt",
                 "../",
             ],
             "libs-windows": [
                 "ws2_32",
                 "Winmm",
                 "USER32",
                 "GDI32",
                 "ADVAPI32",
                 "CRYPT32",
                 "Shell32"
             ],
             "libs-linux": ["freetype", "z", "ssl", "crypto", 
"x11"],
             "sourceFiles-windows": [
                 "../../better_d/glfw/bin/windows/glfw3.lib",
                 
"../../better_d/freetype/bin/windows/freetype.lib",

                 
"../../better_d/mongoose/bin/windows/libcrypto.lib",
                 "../../better_d/mongoose/bin/windows/libssl.lib",
                 
"../../better_d/mongoose/bin/windows/mongoose.lib",

                 "../../better_d/zlib/bin/windows/zlib.lib",
             ],
             "sourceFiles-linux": [
                 "../../better_d/glfw/bin/linux/libglfw3.a",
                 "../../better_d/mongoose/bin/linux/mongoose.a",
             ],
             "dflags": [
                 "-preview=rvaluerefparam",
                 "-betterC"
             ],
             "dflags-dmd": [
                 "-preview=bitfields",
             ],
	        "lflags-windows-dmd": [ "/OPT:REF" ],

             "lflags-windows": [
                 "/NODEFAULTLIB:libcmt.lib"
             ],
         },
         {
             "name": "wasm",
             "targetName": "game",
             "mainSourceFile": "src/app.d",
             "versions": [ "GAME", "WASM"],

             "sourcePaths": [
                 "../../better_d/rt",
                 "../dawn",
                 "../kshared/"
             ],

             "importPaths": [
                 "../../better_d",
                 "../",
             ],

             "dflags-ldc": [
                 "--fvisibility=hidden",
                 "-linkonce-templates",
                 "-preview=rvaluerefparam",
                 "-O3",
                 "-flto=thin",
             ],
             "lflags-ldc": [
                 "-z","stack-size=1048576",
                 "--stack-first",

                 "-allow-undefined"
             ],
             "sourceFiles": [
                 "../../better_d/zlib/bin/wasm32/zlib.a",
             ]
         }
     ]
}
```

Example of module:

```D
module rt.event;

version(Windows)
{
     enum OK = true;
     // windows specific imports/aliases
}
else version(Posix)
{
     enum OK = true;
     // posix specific imports/aliases
}
else version(WASM)
{
     enum OK = false;
}

static if(OK)
{
     // common code

     version(Windows)
     {
         // windows specific common code
     }
     else version(Posix)
     {
         // posix specific common code
     }
}
```


What if:

```D
module rt.event;

// import windows specific
import windows = ..;

// import posix specific
import posix = ..;

void poll()
{
     version (Windows)
         poll_windows();
     else version(Posix)
         poll_posix();
}


void poll_posix()
{
     posix.___();
}
void poll_windows()
{
     windows.___();
}
```

Compiler should know that if i am on windows, when i call 
``poll()`` it'll only ever call ``poll_windows()``, why fetch 
``import posix = ..;``and compile ``poll_posix()``?


``version`` is nice when i want to separate code path within a 
function, but everything outside doesn't make much sense as it 
clutters code

If a ``lazy`` compilation mode is not possible, then what about 
something that would allow something like that:

```D
module rt.event;

version(WASM)
{
     return; // no event in WASM target
}

(..)
```

or

```D
module rt.event; // exclude: WASM

(..)
```


More information about the Digitalmars-d mailing list