Static libraries do not load dynamic functions and ignore initializer/finalizers
This happens on macOS.
Compile a C3 static library with
fn void test_c3() @export("test_c3") {
Allocator allocator = allocator::heap();
(void)allocator::new_array(allocator, int, 4);
}
Compile a C executable with
extern void test_c3();
int main(int argc, char** argv) {
test_c3();
return 0;
}
and link against the C3 library. The program crashes, seemingly because the allocator interface is broken.
For now -Wl,-all_load before linking the static library works.
If you do this with a C library, using the attribute((constructor)) I think you see the same thing (the constructor isn't called)
The problem here is that if you include a static library, then unless the symbol can be traced it is deleted. While enforcing load works, this is not ideal.
We have the following situations:
- C3 static library with C main
- C3 static library x 2 with C main
- C3 static library with C3 main
- C3 static library x 2 with C3 main
On MacOS the constructors and destructors are placed in a special section. This will merge them. So this section is all that is needed to be retained in the 3/4 situation.
In 1/2 we also need to retain the loader of them.
On Linux/Wasm/Windows we rely on initializers. Here the problem is actually somewhat harder to fix.
For Objective-C, Clang requires a special -ObjC directive to make the methods in Objective-C classes be retained despite no direct dependency. This problem is similar to the same problem.
There are two ways to keep something from a static library:
- retrain a symbol that in turn links to it.
- take everything from the static lib
If we only dealt with a single static library, then we could create a $c3load function which would reference everything.
We would then use -symbol $c3load and it would be loaded.
However, if we have multiple static libraries this symbol would be overlapping. Can this be made to work? Or is a unique name needed, eg -symbol mylib$load?
Another alternative would be a linker script. This is a worse user experience I think, but if embedded in a linker, then perhaps it's possible.
Googling there seems to be no simple solution, but perhaps it's possible to do something clever.
This should now work if you build a static lib as it will build everything in a single module.
I think this should work so I close it, and reopen it if it is a problem again.