I'm attempting a port of the D Runtime to a new platform, and currently studying the D Runtime codebase. I find that the "if version{} else version {}" is not so eloquently employed, and as the list of D Runtime ports grow, this is going to get out of control (if it's not already).
Ian Buclaw posted a recommendation here: http://forum.dlang.org/thread/[email protected]#post-mailman.1526.1333966829.4860.digitalmars-d:40puremagic.com
Repeated here in case the original gets lost:
** begin quote **
Personally I feel that people porting to specific architectures should
maintain their differences in separate files under a /ports directory
structure - lets say core.stdc.stdio as a cod example. The version for
bionic would be under /ports/bionic/core/stdc/stdio.d, and that is the
module that gets compiled into the library when building for bionic.
When installing, the build process generates a header file of the
bionic version of core.stdc.stdio and puts the file in the correct
/include/core/stdc/stdio.di location.
Though it is fine to say using version {} else version {} else static
assert(false); when dealing with a small set of architectures. I feel
strongly this is not practical when considering there are 23+
architectures and 12+ platforms that could be in mixed combination.
The result would either be lots of code duplications everywhere, or
just a wiry long block of spaghetti code. Every port in one file
would (eventually) make it difficult for maintainers IMO.
** end quote **
I'm filing this issue to hopefully bring attention to this and foster gradual change.
Comment #1 by ibuclaw — 2013-12-03T01:33:42Z
Thanks Mike.
I will add onto my quote from 18 months ago:
Splitting architectures and platforms into separate files won't stop the code duplication, but it will make it more manageable for maintainers of the ports. eg: I've found a bug on MIPS32 where types mismatch between D and C runtime, I know to look under /ports/mips to find the declaration.
Comment #2 by code — 2013-12-03T11:56:58Z
I agree with this and it's a know limitation of the current structure.
But until someone figures out a good layout we can at least continue to work on ports.
Comment #3 by code — 2013-12-03T17:17:01Z
(In reply to comment #2)
> But until someone figures out a good layout we can at least continue to work on
> ports.
And implements it :).
Comment #4 by code — 2013-12-04T11:52:04Z
(In reply to comment #0)
> ** begin quote **
> Personally I feel that people porting to specific architectures should
> maintain their differences in separate files under a /ports directory
> structure - lets say core.stdc.stdio as a cod example. The version for
> bionic would be under /ports/bionic/core/stdc/stdio.d, and that is the
> module that gets compiled into the library when building for bionic.
> When installing, the build process generates a header file of the
> bionic version of core.stdc.stdio and puts the file in the correct
> /include/core/stdc/stdio.di location.
That sounds almost like a feasible approach. Can you go into more detail though.
Would we create a complete copy of druntime under the ports tree or just for the files'that differ.
What about the combinatorical explosion of libcs x archs, i.e. /ports/bionic_arm, /ports/bionic_x86 and /ports/glibc_ppc? Porting the bits folders for glibc would be the straightforward solution IMO, don't know about other C libs.
How does this integrate with our core.sys.posix and core.sys.linux layers?
Comment #5 by ibuclaw — 2013-12-05T10:08:43Z
(In reply to comment #4)
> (In reply to comment #0)
> > ** begin quote **
> > Personally I feel that people porting to specific architectures should
> > maintain their differences in separate files under a /ports directory
> > structure - lets say core.stdc.stdio as a cod example. The version for
> > bionic would be under /ports/bionic/core/stdc/stdio.d, and that is the
> > module that gets compiled into the library when building for bionic.
> > When installing, the build process generates a header file of the
> > bionic version of core.stdc.stdio and puts the file in the correct
> > /include/core/stdc/stdio.di location.
>
> That sounds almost like a feasible approach. Can you go into more detail
> though.
> Would we create a complete copy of druntime under the ports tree or just for
> the files'that differ.
> What about the combinatorical explosion of libcs x archs, i.e.
> /ports/bionic_arm, /ports/bionic_x86 and /ports/glibc_ppc? Porting the bits
> folders for glibc would be the straightforward solution IMO, don't know about
> other C libs.
> How does this integrate with our core.sys.posix and core.sys.linux layers?
I'll have to sit and brood on this a little longer, but lets start with the following definition I made up just now and destroy it as seen fit.
1) For each platform, we'll assume the default standard library. Alternative libc implementation would require their own /port directory implementing the entire druntime core.stdc.* - or at least the bits that they implement.
I'm not sure how bionic would fit into the current set-up because of the whole conflict between Android/linux. Arguably the bionic libc would come under as an alternative libc implementation, and so we must throw it under /port.
2) Each platform gets it's own core.sys.xxx package. So eg: we'll have core.sys.android, core.sys.plan9, etc...
3) The platform versioning shall remain in place, leaving only architectural differences to be thrown under /port
Lets take a recent example: struct fenv_t:
Implementation:
core/stdc/fenv.d:
---
version (linux)
{
public import core.sys.linux.fenv_t;
}
ports/x86/core/sys/linux/fenv_t.d
---
module core.sys.linux.fenv_t;
version (X86) {
struct fenv_t { ... }
}
else
static assert (false, "Some build-related error");
ports/x86_64/core/sys/linux/fenv_t.d
---
module core.sys.linux.fenv_t;
version (X86_64) {
struct fenv_t { ... }
}
else
static assert (false, "Some build-related error");
ports/generic/core/sys/linux/fenv_t.d
---
module core.sys.linux.fenv_t;
static assert (false, "fenv_t uimplementated for this architecture");
During the build process of druntime, all relevant sources for the target get copied from /ports/xxx -> /imports/xxx. If no arch-specific implementation exists, then the generic one is copied which will throw the "unimplemented" static assert.
Problems that need resolving:
1) How we handle multiple architectures.
Obviously, we could go with the following structure for installed druntime installations:
/usr/include/d/core # Default target if no -mXX.
/usr/include/d/x86_64/core # Use this directory instead if -m64 is passed.
This kind of structure is already implemented in gdc, and is natural to the way things are done within gcc's framework, but this I think would require compiler changes for dmd to support.
Comment #6 by ibuclaw — 2013-12-05T10:12:50Z
(In reply to comment #5)
> 3) The platform versioning shall remain in place, leaving only architectural
> differences to be thrown under /port
>
Slight amendment to that statement:
If there are no differences between architectures. It shall be left as a common implementation for all targets supported by that platform.
Comment #7 by andrei — 2014-02-26T11:55:09Z
Is anyone working on this?
Comment #8 by ibuclaw — 2014-02-26T12:37:28Z
(In reply to comment #7)
> Is anyone working on this?
It's on my long TODO list.
Comment #9 by ibuclaw — 2014-03-02T08:54:53Z
(In reply to comment #8)
> (In reply to comment #7)
> > Is anyone working on this?
>
> It's on my long TODO list.
OK, anyone interested, get reviewing and lets agree a workable solution.
https://github.com/D-Programming-Language/druntime/pull/731