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)
{
"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:
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:
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:
module rt.event;
version(WASM)
{
return; // no event in WASM target
}
(..)
or
module rt.event; // exclude: WASM
(..)