I’ve never used Rust or Zig, but for Go: (disclaimer: this is all from memory, so there may be inaccuracies or out-of-date information here)
Go does not allow circular references between modules. That restriction allows the compiler, when compiling a module, to not only put the compiled machine code in the resulting object file for that module but also the information that in C would be required to be in a header file (i.e. type definitions, function signatures, and even complete functions if they’re considered candidates for inlining, etc.). When compiling a module that imports others, the compiler reads that stuff back out of those files. Essentially a compiled Go library has it’s auto-generated “header file” baked-in.
In older versions this was actually human-readable: an early part of the object file would essentially look like trimmed-down Go when opened in a text editor. IIRC they’ve switched to a binary serialization format for this some years back, but AFAIK it still essentially works the same.
I guess when comparing to C or C++, you could compare this to automatically generating pre-compiled headers for every module, except the headers themselves are also auto-generated (as you alluded to in your post).
If by “shared library” you mean a dynamically linked one: IIRC Go does allow shared libraries to be used, but by default all Go code is linked statically (though libraries written in other languages may be dynamically linked by default, if you import a module that requires it).
I’ve never used Rust or Zig, but for Go: (disclaimer: this is all from memory, so there may be inaccuracies or out-of-date information here)
Go does not allow circular references between modules. That restriction allows the compiler, when compiling a module, to not only put the compiled machine code in the resulting object file for that module but also the information that in C would be required to be in a header file (i.e. type definitions, function signatures, and even complete functions if they’re considered candidates for inlining, etc.). When compiling a module that imports others, the compiler reads that stuff back out of those files. Essentially a compiled Go library has it’s auto-generated “header file” baked-in.
In older versions this was actually human-readable: an early part of the object file would essentially look like trimmed-down Go when opened in a text editor. IIRC they’ve switched to a binary serialization format for this some years back, but AFAIK it still essentially works the same.
I guess when comparing to C or C++, you could compare this to automatically generating pre-compiled headers for every module, except the headers themselves are also auto-generated (as you alluded to in your post).
If by “shared library” you mean a dynamically linked one: IIRC Go does allow shared libraries to be used, but by default all Go code is linked statically (though libraries written in other languages may be dynamically linked by default, if you import a module that requires it).