version(StdDoc)
Jonathan M Davis
newsgroup.d at jmdavisprog.com
Sat Nov 24 04:16:00 UTC 2018
On Friday, November 23, 2018 2:47:51 PM MST Tony via Digitalmars-d-learn
wrote:
> In std.compiler there is this code:
>
> /// Which vendor produced this compiler.
> version(StdDdoc) Vendor vendor;
> else version(DigitalMars) Vendor vendor = Vendor.digitalMars;
> else version(GNU) Vendor vendor = Vendor.gnu;
> else version(LDC) Vendor vendor = Vendor.llvm;
> else version(D_NET) Vendor vendor = Vendor.dotNET;
> else version(SDC) Vendor vendor = Vendor.sdc;
> else Vendor vendor = Vendor.unknown;
>
> What is the situation in which the identifier StdDoc is set?
It's a Phobos-only replacement for the D_Ddoc version identifier and is
defined as part of the Phobos build. As the others have been complaining
about in this thread, ddoc is set up so that it takes whatever version is
currently being compiled. So, version(D_Ddoc) is the standard way to provide
documentation that is agnostic of the platform in the cases where a
documented symbol doesn't exist on all platforms, or its definition differs
such that it needs separate declarations - e.g. if the values of members in
an enum differ across systems, then you're forced to provide completely
separate enum declarations for the entire enum. If you have separate
declarations on different platforms, then in general there are only three
choices
1. Duplicate the documentation.
2. Set it up so that your documentation can only be built on one platform.
3. Use version(D_Ddoc) to provide a separate declaration just for the
documentation.
There are some cases where you can put the documentation outside the version
block and have it work - e.g.
/// my documentation
version(linux) int foo(string bar) { ... }
else version(Windows) int foo(string bar) { ... }
else ...
but that only works when you only need to document the top-level symbol
(such as with a function). It does not work with anything that needs to have
symbols inside it documented (such as with a struct, class, or enum).
Fortunately, most code does need to be versioned like this (especially if
you're trying to write platform-independent code like we try to do with
Phobos), and often, when you do need to version stuff, it's inside
implementations, but sometimes it does affect the top level. std.file has
this problem in a few places as does std.datetime with WindowsTimeZone
(since it only exists on Windows). The solution the language provides is to
use version(D_Ddoc) to version such documentation. And that's what Phobos
used to do.
The problem is that once you start using version(D_Ddoc), you _must_ have a
separate documentation build. You can't build your documentation as part of
your normal build, because you'd be getting the version(D_Ddoc) stubs
instead of the correct implementation for your platform (or instead of
nothing at all if that platform isn't supposed to have that particular
symbol). Phobos already had a separate documentation build because of how it
generates the documentation for the website, but many people's projects do
not. Most projects don't ever need to use version(D_Ddoc), because they
don't have symbols that are platform-dependent, and so before Phobos started
using it, they could compile their documentation as part of their normal
build just fine, because version(D_Ddoc) wasn't in their code anywhere. But
as soon as Phobos started using it, their code broke. If they had had a
separate documentation build, then they wouldn't have had any problems, but
as it was, their code was broken.
So, for better or worse, rather than saying that it was just bad practice to
do the documentation build as part of your normal build (and I would
strongly argue that building the documentation as part of the normal build
is bad practice given how doing so defines a new version identifier that can
affect the build), it was decided that Phobos would stop using
version(D_Ddoc) as the language intended and instead use its own custom,
version identifier for the documentation - which is why we now have
version(StdDoc) in Phobos and version(CoreDdoc) in druntime. With this
change, anyone building with the -D flag as part of their normal build
doesn't end up with version(D_Ddoc) screwing up their code because of
druntime or Phobos. Some other project they depend on could screw it up, and
if they ever use version(D_Ddoc) in their code, they'll have trouble again,
but Phobos and druntime aren't going to mess them up in that regard.
And while version(D_Ddoc) is the standard solution, because of this general
problem with folks using -D with their normal build, it's arguably best
practice at this point to create your own version identifier for your own
documentation for any library that you release that needs to version its
documentation. Otherwise, anyone using your library will have the same
problems that resulted in Phobos switching from version(D_Ddoc) to
version(StdDdoc) - which if anything shows that things work here probably
should have been handled differently.
Really, the way that -D is designed is similar to -unittest in that they're
both intended to be used for builds other than your normal build. They
create their own version identifiers and can change how the code compiles.
And as such really should not be used as part of the normal build. But just
like -unittest runs the unit tests by making them run before main, thus
making it so that you can technically have the unit tests be part of your
normal build (even if it's unwise), you can have the documentation as part
of your normal build (even if it's unwise). Arguably, just like the
complaints that Adam Ruppe and H.S. Teoh are making elsewhere in the thread,
this aspect of how the compiler and language are designed to work is not the
best designed. It works just fine if you understand the pitfalls, but having
the unit tests and documentation treated in such a way that they can be part
of the normal build instead of always replacing the normal build definitely
is an area that sometimes causes problems for people.
- Jonathan M Davis
More information about the Digitalmars-d-learn
mailing list