https://issues.dlang.org/show_bug.cgi?id=17596
Jonathan M Davis <issues.dl...@jmdavisprog.com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |issues.dl...@jmdavisprog.co | |m --- Comment #20 from Jonathan M Davis <issues.dl...@jmdavisprog.com> --- (In reply to Vladimir Panteleev from comment #9) > Alright, so how about: > > - We add getosreldate and INO64_FIRST to druntime > - We add both the old and new struct definitions > - We add a stat wrapper which,when getosreldate() < INO64_FIRST, translates > the old struct to the new struct and returns it. I tried that with the functions from sys/mount.h that use statfs_t, and it doesn't work. The problem is that from what I can tell, if you build a program on FreeBSD 11, it runs just fine on FreeBSD 12 - at least it did with the functions in sys/mount.h. e.g. When running a program built on FreeBSD 11 on FreeBSD 12, fstatfs reports the same version with its f_version member that it does on FreeBSD 11, and it clearly calls the FreeBSD 11 version of fstafs. objdump confirms this. If you compile a C/C++ program which uses fstatfs on FreeBSD 12 and use objdump -t on it and grep for fstatfs, it has 00000000002013e0 F *UND* 0000000000000000 fstatfs whereas if you compile it on FreeBSD 11, you get 0000000000000000 F *UND* 0000000000000011 fstatfs@@FBSD_1.0 Building a D program that does the same thing on FreeBSD 11 also results in 0000000000000000 F *UND* 0000000000000011 fstatfs@@FBSD_1.0 and it still says 0000000000000000 F *UND* 0000000000000011 fstatfs@@FBSD_1.0 if you run objdump on it in FreeBSD 12. And it runs just fine on FreeBSD 12. If I create a wrapper in druntime so that it uses the FreeBSD 11 version of stat_t if getosreldate() < INO64_FIRST, then it works just fine on FreeBSD 11 but fails miserably when running that binary on FreeBSD 12, because the binary has the FreeBSD 11 version of the function in it, and it's the FreeBSD 11 version of stat_t that it's using even though it's running on FreeBSD 12. So, from what testing I've done thus far, running D binaries built on FreeBSD 11 on FreeBSD 12 works just fine. What fails is when you try to build a program on FreeBSD 12 (including the compiler). The resulting binary doesn't work properly if it uses any of the structs that changed, because the definition in D does not match the definition in C. It may be that taking a program built on FreeBSD 11 which uses a function like fstatfs and running it on FreeBSD 12 only works because the OS itself detects which version of the function your program is built with and therefore calls the old version of the syscall internally (I don't know), but building a D program on FreeBSD 11 and running it on 12 seems to work just fine right now, whereas if you build anything with dmd on FreeBSD 12 where the definition in druntime does not match the actual FreeBSD 12 definition, then it doesn't work. So, my conclusion is that the only way to fully fix this is for the struct definitions to be versioned based on the version of FreeBSD the program is built on (which would then allow us to do the same thing that C/C++ does and have versioned headers). And arguably, assuming that there's only one version of the OS when creating bindings for the OS headers is a terrible idea to begin with. We only really get away with it like we do because of the fact that most of them don't change very often. In any case, all of the extra stuff with detecting the version of FreeBSD at runtime in D and changing which version of a struct you use based on what getosreldate() says might make it possible to run a binary built on FreeBSD 12 (with the FreeBSD 12 versions of the structs) on FreeBSD 11 (I don't know), but it breaks running a FreeBSD 11 binary on FreeBSD 12. As far as I can tell, we really only have two options: 1. Make it so that dmd actually provides a version identifier for different versions of FreeBSD (e.g. FreeBSD11 and FreeBSD12) so that we can version the definitions in druntime just like they would be in the actual C headers (since FreeBSD 11 gets different headers than FreeBSD 12). That way, we could version most stuff with FreeBSD like we always have but cleanly cope when definitions change between versions of FreeBSD by versioning those few symbols with identifiers such as FreeBSD11 or FreeBSD12. 2. Have a PR where we change all of the struct definitions that differ between FreeBSD 11 and FreeBSD 12, use a dmd binary built on FreeBSD 11 with the old code to build it, and then immediately require that everything built with that version of dmd and newer use FreeBSD 12. That's theoreticaly feasible, but it could be difficult to make work well with the auto-tester, and it would be fairly disruptive. This isn't like with Windows where we say that we support version X, but older versions work well enough for folks to get by during the transition. It's a distinct point where dmd either works with FreeBSD 11 or FreeBSD 12 but not both. Without versioning the definitions themselves, we can't provide a release of dmd that's going to work on both FreeBSD 11 and FreeBSD 12 even temporarily. As such, I am strongly inclined to argue that we add version identifiers to D for FreeBSD11 and FreeBSD12 - either that or some function that provides the version that the code is being built on which can then be used with static if instead of version, but that can't be done without compiler support, because CTFE can't call stuff like getosreldate() or uname(). --