August 27
https://issues.dlang.org/show_bug.cgi?id=24725

          Issue ID: 24725
           Summary: core.sys.linux: feature detect glibc functions at
                    build time
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: druntime
          Assignee: nobody@puremagic.com
          Reporter: a.horodniceanu@proton.me

This has come up as an issue in https://github.com/dlang/phobos/pull/9048 but the short version is: druntime bindings should match up what the C system headers expose, as much as possible.

The advantages is simple, it lowers the amount of manual inspection a user has to do to check for declarations inside libc or if those declarations will exist on somebody else's computer when compiling the same code. There are no disadvantages to doing this outside of needing to implement the change.

The two main ways of implementing this are:
1. Embedding some form of information when druntime is built.

This, again, can be done in two ways, either embed to full version of glibc or
embed only if a function is available. The former would require to inspect the
headers of glibc at build time and extract the `__GLIBC__` and
`__GLIBC_MINOR__` macros. The meson build system has support for this:
https://mesonbuild.com/Reference-manual_returned_compiler.html#compilerget_define,
but neither autotools, used by gdc, nor cmake, used by ldc, support this. The
other approach is performing checks for individual function which both build
systems would known how to perform. dmd has been left out because it only uses
a makefile so code has to be written manually to support this.

Embedding the version would be the best approach as the check would have to be
carried only once during the build and the `config.d` file would have `enum
__GLIBC__ = ...` and `enum __GLIBC_MINOR__ = ...` set inside it. For
convenience, `config.d` would also provide a function `__GLIBC_PREREQ` witch
does the same thing as the glibc provided macro, which is checking that the
glibc version is high enough. To provide a function that has been recently
added a modules inside `core.sys.linux` can do:
```
import core.sys.linux.config;
static if (__GLIBC_PREREQ(2, 34))
void closefrom(int);
```

This would provide the `closefrom` declaration on systems that have a glibc version of at least 2.34. This is expressive as it clearly documents on which systems the function exists. It also makes adding functions easier as the version of glibc has already been determined. The downside is that the build systems used by gdc and ldc don't support this out of the box.

The other approach involves adding an enum for each function to `config.d`
like:
```
module core.sys.linux.config;
enum HAVE_CLOSEFROM = true;
```

```
module core.sys.linux.unistd;
import core.sys.linux.config;
static if (HAVE_CLOSEFROM)
void closefrom(int);
```

The value of `HAVE_CLOSEFROM` would be generated during the build and saved inside `config.d`. In this case it is not abundantly clear how "portable" the closefrom function is, or on which systems it is available. This approach also makes it harder to subsequently add other functions as each addition would require an additional `enum` value and a check inside the build system.

Both of these approaches would lead to the same interface being exposed so the differences are only in readability/ease of implementation.

Both of these solutions would be most effective when building druntime on recent systems. If druntime is build on an older system, with the purpose of creating portable binaries like the dmd release archives, the changes wouldn't be as big as the detected glibc version would be older than what may be available on a user's system. When built on newer systems, however, these changes would be more substantial as they allow druntime to provide more definitions.

A back-and-fourth topic in the PR that started this has been whether this affects the portability of the code that uses druntime or phobos. The answer is no, for portability sake's the most relevant thing is the version of glibc you build the code against. As an example, if druntime and phobos are built against glibc-2.20 then any D application that uses those would be able to run on a system with glibc-2.20 or newer. The version of glibc the two libraries are built against refers to the version that those libraries are linked against. It has little bearing on portability which or how many functions from glibc the code uses, the minimum glibc version requirement is given during the linking step.

2. Automatically parsing C headers
This could be provided through importC and expose to the D code the same
functions as would be provided to C. This would be great if it worked, however:
- there are still a lot of edge cases that importC doesn't support:
https://github.com/dlang/dmd/blob/4a5c56d0f7f3f84ec7f6bf1f980834f72e211824/compiler/test/compilable/stdcheaders.c
- gdc doesn't support #include's with importC.

The current code, while not optimal, has the advantage that it doesn't break. For this reason I consider that either of the solutions described in 1. are worth pursueing.

--