Add initial D rules to Bazel.
--
MOS_MIGRATED_REVID=102513092
diff --git a/WORKSPACE b/WORKSPACE
index fcbae48..3486acd 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -81,3 +81,17 @@
name = "android_ndk_for_testing",
actual = "//:dummy",
)
+
+new_http_archive(
+ name = "dmd-linux-x86_64",
+ url = "http://downloads.dlang.org/releases/2.x/2.067.1/dmd.2.067.1.linux.zip",
+ sha256 = "a5014886773853b4a42df19ee9591774cf281d33fbc511b265df30ba832926cd",
+ build_file = "tools/build_defs/d/dmd.BUILD",
+)
+
+new_http_archive(
+ name = "dmd-darwin-x86_64",
+ url = "http://downloads.dlang.org/releases/2.x/2.067.1/dmd.2.067.1.osx.zip",
+ sha256 = "aa76bb83c38b3f7495516eb08977fc9700c664d7a945ba3ac3c0004a6a8509f2",
+ build_file = "tools/build_defs/d/dmd.BUILD",
+)
diff --git a/examples/d/hello_lib/BUILD b/examples/d/hello_lib/BUILD
new file mode 100644
index 0000000..7ed1624
--- /dev/null
+++ b/examples/d/hello_lib/BUILD
@@ -0,0 +1,40 @@
+package(default_visibility = ["//visibility:public"])
+
+load(
+ "/tools/build_defs/d/d",
+ "d_docs",
+ "d_library",
+ "d_source_library",
+ "d_test",
+)
+
+d_library(
+ name = "greeter",
+ srcs = ["greeter.d"],
+)
+
+d_test(
+ name = "greeter_test",
+ srcs = ["greeter_test.d"],
+ deps = [":greeter"],
+)
+
+cc_library(
+ name = "native_greeter_lib",
+ srcs = ["native-greeter.c"],
+ hdrs = ["native-greeter.h"],
+)
+
+d_source_library(
+ name = "native_greeter",
+ srcs = ["native_greeter.d"],
+ deps = [":native_greeter_lib"],
+)
+
+d_docs(
+ name = "greeter_docs",
+ srcs = glob(
+ ["*.d"],
+ exclude = ["*_test.d"],
+ ),
+)
diff --git a/examples/d/hello_lib/greeter.d b/examples/d/hello_lib/greeter.d
new file mode 100644
index 0000000..ec916ff
--- /dev/null
+++ b/examples/d/hello_lib/greeter.d
@@ -0,0 +1,51 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+module greeter;
+
+import std.stdio;
+import std.string;
+
+/// Displays a greeting.
+class Greeter {
+ private string greeting;
+
+ public:
+ /// Creates a new greeter.
+ ///
+ /// Params:
+ /// greeting = The greeting to use.
+ this(in string greeting) {
+ this.greeting = greeting.dup;
+ }
+
+ /// Returns the greeting as a string.
+ ///
+ /// Params:
+ /// thing = The thing to greet
+ ///
+ /// Returns:
+ /// A greeting as a string.
+ string makeGreeting(in immutable string thing) {
+ return format("%s %s!", this.greeting, thing);
+ }
+
+ /// Prints a greeting.
+ ///
+ /// Params:
+ /// thing = The thing to greet.
+ void greet(in immutable string thing) {
+ writeln(makeGreeting(thing));
+ }
+}
diff --git a/examples/d/hello_lib/greeter_test.d b/examples/d/hello_lib/greeter_test.d
new file mode 100644
index 0000000..6ebd7f9
--- /dev/null
+++ b/examples/d/hello_lib/greeter_test.d
@@ -0,0 +1,22 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import examples.d.hello_lib.greeter;
+
+unittest {
+ auto greeter = new Greeter("Hello");
+ assert(greeter.makeGreeting("world") == "Hello world!");
+}
+
+void main() {}
diff --git a/examples/d/hello_lib/native-greeter.c b/examples/d/hello_lib/native-greeter.c
new file mode 100644
index 0000000..cdbb388
--- /dev/null
+++ b/examples/d/hello_lib/native-greeter.c
@@ -0,0 +1,49 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "examples/d/hello_lib/native-greeter.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+NativeGreeter* native_greeter_new(const char* greeting) {
+ if (greeting == NULL) {
+ return NULL;
+ }
+ NativeGreeter* greeter = NULL;
+ greeter = (NativeGreeter*)malloc(sizeof(*greeter));
+ if (greeter == NULL) {
+ return NULL;
+ }
+ greeter->greeting = strdup(greeting);
+ return greeter;
+}
+
+void native_greeter_greet(const NativeGreeter* greeter, const char* thing) {
+ if (greeter == NULL || thing == NULL) {
+ return;
+ }
+ printf("%s %s!\n", greeter->greeting, thing);
+}
+
+void native_greeter_free(NativeGreeter* greeter) {
+ if (greeter == NULL) {
+ return;
+ }
+ if (greeter->greeting != NULL) {
+ free(greeter->greeting);
+ }
+ free(greeter);
+}
diff --git a/examples/d/hello_lib/native-greeter.h b/examples/d/hello_lib/native-greeter.h
new file mode 100644
index 0000000..d01d8ca
--- /dev/null
+++ b/examples/d/hello_lib/native-greeter.h
@@ -0,0 +1,28 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef EXAMPLES_D_HELLO_LIB_NATIVE_GREETER_H_
+#define EXAMPLES_D_HELLO_LIB_NATIVE_GREETER_H_
+
+typedef struct NativeGreeter {
+ char* greeting;
+} NativeGreeter;
+
+NativeGreeter* native_greeter_new(const char* greeting);
+
+void native_greeter_greet(const NativeGreeter* greeter, const char* thing);
+
+void native_greeter_free(NativeGreeter* greeter);
+
+#endif // EXAMPLES_D_HELLO_LIB_NATIVE_GREETER_H_
diff --git a/examples/d/hello_lib/native_greeter.d b/examples/d/hello_lib/native_greeter.d
new file mode 100644
index 0000000..417492a
--- /dev/null
+++ b/examples/d/hello_lib/native_greeter.d
@@ -0,0 +1,43 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+module native_greeter;
+
+extern (C):
+
+struct NativeGreeter {
+ char* greeting;
+};
+
+/// Creates a new NativeGreeter.
+///
+/// Params:
+/// greeting = The greeting to use.
+///
+/// Returns:
+/// A pointer to a new NativeGreeting struct.
+NativeGreeter* native_greeter_new(const(char)* greeting);
+
+/// Prints a greeting to stdout.
+///
+/// Params:
+/// greeter = The pointer to the NativeGreeter object to use.
+/// thing = The thing to greet.
+void native_greeter_greet(const(NativeGreeter)* greeter, const(char)* thing);
+
+/// Frees the NativeGreeter.
+///
+/// Params:
+/// greeter = The pointer to the NativeGreeter object to use.
+void native_greeter_free(NativeGreeter* greeter);
diff --git a/examples/d/hello_world/BUILD b/examples/d/hello_world/BUILD
new file mode 100644
index 0000000..47c7342
--- /dev/null
+++ b/examples/d/hello_world/BUILD
@@ -0,0 +1,12 @@
+package(default_visibility = ["//visibility:public"])
+
+load("/tools/build_defs/d/d", "d_binary")
+
+d_binary(
+ name = "hello_world",
+ srcs = ["hello_world.d"],
+ deps = [
+ "//examples/d/hello_lib:greeter",
+ "//examples/d/hello_lib:native_greeter",
+ ],
+)
diff --git a/examples/d/hello_world/hello_world.d b/examples/d/hello_world/hello_world.d
new file mode 100644
index 0000000..3c60f4a
--- /dev/null
+++ b/examples/d/hello_world/hello_world.d
@@ -0,0 +1,26 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import std.stdio;
+import examples.d.hello_lib.greeter;
+import examples.d.hello_lib.native_greeter;
+
+void main() {
+ Greeter greeter = new Greeter("Hello");
+ greeter.greet("World");
+
+ NativeGreeter* nativeGreeter = native_greeter_new("Hello");
+ native_greeter_greet(nativeGreeter, "World");
+ native_greeter_free(nativeGreeter);
+}
diff --git a/site/docs/supported-rules.md b/site/docs/supported-rules.md
index 7010dcf..d763952 100644
--- a/site/docs/supported-rules.md
+++ b/site/docs/supported-rules.md
@@ -12,5 +12,6 @@
* [Docker images](https://github.com/bazelbuild/bazel/tree/master/tools/build_defs/docker)
* [Groovy projects](https://github.com/bazelbuild/bazel/tree/master/tools/build_defs/groovy)
* [Java App Engine applications](https://github.com/bazelbuild/bazel/tree/master/tools/build_rules/appengine)
+* [D projects](https://github.com/bazelbuild/bazel/tree/master/tools/build_defs/d)
* [Rust projects](https://github.com/bazelbuild/bazel/tree/master/tools/build_rules/rust)
* [Scala projects](https://github.com/bazelbuild/bazel/tree/master/tools/build_defs/scala) - experimental
diff --git a/tools/build_defs/d/BUILD b/tools/build_defs/d/BUILD
new file mode 100644
index 0000000..7d5b723
--- /dev/null
+++ b/tools/build_defs/d/BUILD
@@ -0,0 +1,43 @@
+package(default_visibility = ["//visibility:public"])
+
+config_setting(
+ name = "darwin",
+ values = {"host_cpu": "darwin"},
+)
+
+config_setting(
+ name = "k8",
+ values = {"host_cpu": "k8"},
+)
+
+filegroup(
+ name = "dmd",
+ srcs = select({
+ ":darwin": ["@dmd-darwin-x86_64//:dmd"],
+ ":k8": ["@dmd-linux-x86_64//:dmd"],
+ }),
+)
+
+filegroup(
+ name = "libphobos2",
+ srcs = select({
+ ":darwin": ["@dmd-darwin-x86_64//:libphobos2"],
+ ":k8": ["@dmd-linux-x86_64//:libphobos2"],
+ }),
+)
+
+filegroup(
+ name = "phobos-src",
+ srcs = select({
+ ":darwin": ["@dmd-darwin-x86_64//:phobos-src"],
+ ":k8": ["@dmd-linux-x86_64//:phobos-src"],
+ }),
+)
+
+filegroup(
+ name = "druntime-import-src",
+ srcs = select({
+ ":darwin": ["@dmd-darwin-x86_64//:druntime-import-src"],
+ ":k8": ["@dmd-linux-x86_64//:druntime-import-src"],
+ }),
+)
diff --git a/tools/build_defs/d/README.md b/tools/build_defs/d/README.md
new file mode 100644
index 0000000..89707a8
--- /dev/null
+++ b/tools/build_defs/d/README.md
@@ -0,0 +1,651 @@
+# D rules
+
+## Rules
+
+* [`d_library`](#d_library)
+* [`d_source_library`](#d_source_library)
+* [`d_binary`](#d_binary)
+* [`d_test`](#d_test)
+* [`d_docs`](#d_docs)
+
+## Setup
+
+To use the D rules, simply copy the contents of `d.WORKSPACE` into your
+`WORKSPACE` file.
+
+## Roadmap
+
+* Generate documentation using [`ddox`](https://github.com/rejectedsoftware/ddox)
+ for `d_docs` rule.
+* Support for other options as defined in the [Dub package
+ format](http://code.dlang.org/package-format?lang=json)
+* Support for specifying different configurations of a library, closer to
+ [Dub's model for configurations](http://code.dlang.org/package-format?lang=json#configurations)
+* Workspace rule for retrieving dependencies from [Dub](http://code.dlang.org/)
+
+<a name="d_library"></a>
+## d_library
+
+```python
+d_library(name, srcs, deps, includes, linkopts, versions)
+```
+
+<table>
+ <thead>
+ <tr>
+ <th>Attribute</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>name</code></td>
+ <td>
+ <code>Name, required</code>
+ <p>A unique name for this rule.</p>
+ <p>
+ This name will be used as the name of the library built by this rule.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>srcs</code></td>
+ <td>
+ <code>List of labels, required</code>
+ <p>List of D <code>.d</code> source files used to build the library.</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>deps</code></td>
+ <td>
+ <code>List of labels, optional</code>
+ <p>List of libraries to be linked to this library target.</p>
+ <p>
+ These can either be other <code>d_library</code> targets,
+ source-only <code>d_source_library</code> targets, or
+ <code>cc_library</code> targets if linking a native library.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>imports</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of import dirs to add to the compile line.</p>
+ <p>
+ These will be passed to the D compiler via <code>-I</code> flags.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>linkopts</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of flags that are added to the D linker command.</p>
+ <p>
+ These will be passed to the D compiler via <code>-L</code> flags.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>versions</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of versions to be defined during compilation.</p>
+ <p>
+ Versions are used for conditional compilation and are enabled in the
+ code using <code>version</code> condition blocks. These versions
+ listed here will be passed to the D compiler using
+ <code>-version</code> flags.
+ </p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+### Example
+
+Suppose you have the following directory structure for a D project:
+
+```
+[workspace]/
+ WORKSPACE
+ foo/
+ BUILD
+ foo.d
+ bar.d
+ baz.d
+```
+
+The library `foo` is built using a `d_library` target:
+
+`foo/BUILD`:
+
+```python
+load("/tools/build_defs/d/d", "d_library")
+
+d_binary(
+ name = "foo",
+ srcs = [
+ "foo.d",
+ "bar.d",
+ "baz.d",
+ ],
+)
+```
+
+<a name="d_source_library"></a>
+## d_source_library
+
+```python
+d_source_library(name, srcs, deps, includes, linkopts, versions)
+```
+
+<table>
+ <thead>
+ <tr>
+ <th>Attribute</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>name</code></td>
+ <td>
+ <code>Name, required</code>
+ <p>A unique name for this rule.</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>srcs</code></td>
+ <td>
+ <code>List of labels, required</code>
+ <p>
+ List of D <code>.d</code> source files that comprises this source
+ library target.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>deps</code></td>
+ <td>
+ <code>List of labels, optional</code>
+ <p>List of library targets depended on by this target.</p>
+ <p>
+ These can either be other <code>d_source_library</code> targets or
+ <code>cc_library</code> targets, such as when this source library
+ target implements the D interface for a native library. Any native
+ libraries will be linked by <code>d_library</code> targets that
+ depend on this target.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>imports</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of import dirs to add to the compile line.</p>
+ <p>
+ These will be passed to the D compiler via <code>-I</code> flags for
+ any <code>d_library</code> targets that depend on this target.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>linkopts</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of flags that are added to the D linker command.</p>
+ <p>
+ These will be passed to the D compiler via <code>-L</code> flags for
+ any <code>d_library</code> targets that depend on this target.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>versions</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of version flags to be defined during compilation.</p>
+ <p>
+ Versions are used for conditional compilation and are enabled in the
+ code using <code>version</code> condition blocks. These versions
+ listed here will be passed to the D compiler using
+ <code>-version</code> flags for any <code>d_library</code> targets
+ that depend on this target.
+ </p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+### Example
+
+Suppose you have the following directory structure for a project building a
+C library and a [D interface](http://dlang.org/interfaceToC.html) for the C
+library:
+
+```
+[workspace]/
+ WORKSPACE
+ greeter/
+ BUILD
+ native_greeter.c
+ native_greeter.h
+ native_greeter.d
+ hello_world
+ BUILD
+ hello_world.d
+```
+
+Build the C library using the `cc_library` rule and then use the
+`d_source_library` to define the target for the D interface for the C
+`native_greeter` library:
+
+`greeter/BUILD`:
+
+```python
+load("/tools/build_defs/d/d", "d_source_library")
+
+cc_library(
+ name = "native_greeter_lib",
+ srcs = ["native_greeter.c"],
+ hdrs = ["native_greeter.h"],
+)
+
+d_source_library(
+ name = "native_greeter",
+ srcs = ["native_greeter.d"],
+ deps = [":native_greeter_lib"],
+)
+```
+
+Other targets can directly depend on the `d_source_library` target to link
+the C library:
+
+`hello_world/BUILD`:
+
+```python
+load("/tools/build_defs/d/d", "d_source_library")
+
+d_binary(
+ name = "hello_world",
+ srcs = ["hello_world.d"],
+ deps = ["//greeter:native_greeter"],
+)
+```
+
+<a name="d_binary"></a>
+## d_binary
+
+```python
+d_binary(name, srcs, deps, includes, linkopts, versions)
+```
+
+<table>
+ <thead>
+ <tr>
+ <th>Attribute</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>name</code></td>
+ <td>
+ <code>Name, required</code>
+ <p>A unique name for this rule.</p>
+ <p>
+ This name will be used as the name of the binary built by this rule.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>srcs</code></td>
+ <td>
+ <code>List of labels, required</code>
+ <p>List of D <code>.d</code> source files used to build the binary.</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>deps</code></td>
+ <td>
+ <code>List of labels, optional</code>
+ <p>List of libraries to be linked to this binary target.</p>
+ <p>
+ These can either be other <code>d_library</code> targets,
+ source-only <code>d_source_library</code> targets, or
+ <code>cc_library</code> targets if linking a native library.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>imports</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of import dirs to add to the compile line.</p>
+ <p>
+ These will be passed to the D compiler via <code>-I</code> flags.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>linkopts</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of flags that are added to the D linker command.</p>
+ <p>
+ These will be passed to the D compiler via <code>-L</code> flags.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>versions</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of versions to be defined during compilation.</p>
+ <p>
+ Versions are used for conditional compilation and are enabled in the
+ code using <code>version</code> condition blocks. These versions
+ listed here will be passed to the D compiler using
+ <code>-version</code> flags.
+ </p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+Suppose you have the following directory structure for a D project:
+
+```
+[workspace]/
+ WORKSPACE
+ hello_lib/
+ BUILD
+ greeter.d
+ hello_world
+ BUILD
+ hello_world.d
+```
+
+The source file `hello_lib/greeter.d` defines a module `greeter`:
+
+```d
+module greeter;
+...
+```
+
+The `hello_lib` library is built using a `d_library` target:
+
+`hello_lib/BUILD`:
+
+```python
+load("/tools/build_defs/d/d", "d_library")
+
+d_library(
+ name = "hello_lib",
+ srcs = ["greeter.d"],
+)
+```
+
+By default, import paths are from the root of the workspace. Thus, the source
+for the `hello_world` binary, `hello_world.d`, would import the `greeter`
+module as follows:
+
+```d
+import hello_lib.greeter;
+```
+
+However, this can be changed via the `imports` attribute on the `d_library`
+rule.
+
+The `hello_world` binary is built using a `d_binary` target:
+
+`hello_world/BUILD`:
+
+```python
+load("/tools/build_defs/d/d", "d_library")
+
+d_binary(
+ name = "hello_world",
+ srcs = ["hello_world.d"],
+ deps = ["//hello_lib"],
+)
+```
+
+<a name="d_test"></a>
+## d_test
+
+```python
+d_test(name, srcs, deps, includes, linkopts, versions)
+```
+
+<table>
+ <thead>
+ <tr>
+ <th>Attribute</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>name</code></td>
+ <td>
+ <code>Name, required</code>
+ <p>A unique name for this rule.</p>
+ <p>
+ This name will be used as the name of the test built by this rule.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>srcs</code></td>
+ <td>
+ <code>List of labels, required</code>
+ <p>List of D <code>.d</code> source files used to build the test.</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>deps</code></td>
+ <td>
+ <code>List of labels, optional</code>
+ <p>List of libraries to be linked to this test target.</p>
+ <p>
+ These can either be other <code>d_library</code> targets,
+ source-only <code>d_source_library</code> targets, or
+ <code>cc_library</code> targets if linking a native library.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>imports</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of import dirs to add to the compile line.</p>
+ <p>
+ These will be passed to the D compiler via <code>-I</code> flags.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>linkopts</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of flags that are added to the D linker command.</p>
+ <p>
+ These will be passed to the D compiler via <code>-L</code> flags.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>versions</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of versions to be defined during compilation.</p>
+ <p>
+ Versions are used for conditional compilation and are enabled in the
+ code using <code>version</code> condition blocks. These versions
+ listed here will be passed to the D compiler using
+ <code>-version</code> flags.
+ </p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+### Example
+
+Suppose you have the following directory structure for a D project:
+
+```
+[workspace]/
+ WORKSPACE
+ hello_lib/
+ BUILD
+ greeter.d
+ greeter_test.d
+```
+
+`hello_lib/greeter.d`:
+
+```d
+module greeter;
+
+import std.stdio;
+import std.string;
+
+class Greeter {
+ private string greeting;
+
+ public:
+ this(in string greeting) {
+ this.greeting = greeting.dup;
+ }
+
+ string makeGreeting(in immutable string thing) {
+ return format("%s %s!", this.greeting, thing);
+ }
+
+ void greet(in immutable string thing) {
+ writeln(makeGreeting(thing));
+ }
+}
+```
+
+`hello_lib/greeter_test.d`:
+
+```d
+import hello_lib.greeter;
+
+unittest {
+ auto greeter = new Greeter("Hello");
+ assert(greeter.makeGreeting("world") == "Hello world!");
+}
+
+void main() {}
+```
+
+To build the library and unit test:
+
+`hello_lib/BUILD`:
+
+```python
+load("/tools/build_defs/d/d", "d_library", "d_test")
+
+d_library(
+ name = "greeter",
+ srcs = ["greeter.d"],
+)
+
+d_test(
+ name = "greeter_test",
+ srcs = ["greeter_test.d"],
+ deps = [":greeter"],
+)
+```
+
+The unit test can then be run using:
+
+```sh
+bazel test //hello_lib:greeter_test
+```
+
+<a name="d_docs"></a>
+## d_docs
+
+```python
+d_docs(name, srcs, imports)
+```
+
+<table>
+ <thead>
+ <tr>
+ <th>Attribute</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>name</code></td>
+ <td>
+ <code>Name, required</code>
+ <p>A unique name for this rule.</p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>srcs</code></td>
+ <td>
+ <code>List of labels, required</code>
+ <p>
+ List of D <code>.d</code> source files to generate documentation for.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td><code>imports</code></td>
+ <td>
+ <code>List of strings, optional</code>
+ <p>List of import dirs to add to the compile line.</p>
+ <p>
+ These will be passed to the D compiler via <code>-I</code> flags.
+ </p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+### Example
+
+Suppose you have the following directory structure for a D project:
+
+```
+[workspace]/
+ WORKSPACE
+ foo/
+ BUILD
+ foo.d
+ bar.d
+ baz.d
+```
+
+To generate HTML documentation for the `foo` package, define a `d_docs` target:
+
+`foo/BUILD`:
+
+```python
+load("/tools/build_defs/d/d", "d_docs")
+
+d_docs(
+ name = "foo_docs",
+ srcs = [
+ "foo.d",
+ "bar.d",
+ "baz.d",
+ ],
+)
+```
+
+Running `bazel build //foo:foo_docs` will generate a zip file containing the
+HTML documentation generated from the source files. See the official D language
+documentation on the [Documentation Generator](http://dlang.org/ddoc.html) for
+more information on the conventions for source documentation.
diff --git a/tools/build_defs/d/d.WORKSPACE b/tools/build_defs/d/d.WORKSPACE
new file mode 100644
index 0000000..0042764
--- /dev/null
+++ b/tools/build_defs/d/d.WORKSPACE
@@ -0,0 +1,13 @@
+new_http_archive(
+ name = "dmd-linux-x86_64",
+ url = "http://downloads.dlang.org/releases/2.x/2.067.1/dmd.2.067.1.linux.zip",
+ sha256 = "a5014886773853b4a42df19ee9591774cf281d33fbc511b265df30ba832926cd",
+ build_file = "tools/build_defs/d/dmd.BUILD",
+)
+
+new_http_archive(
+ name = "dmd-darwin-x86_64",
+ url = "http://downloads.dlang.org/releases/2.x/2.067.1/dmd.2.067.1.linux.zip",
+ sha256 = "aa76bb83c38b3f7495516eb08977fc9700c664d7a945ba3ac3c0004a6a8509f2",
+ build_file = "tools/build_defs/d/dmd.BUILD",
+)
diff --git a/tools/build_defs/d/d.bzl b/tools/build_defs/d/d.bzl
new file mode 100644
index 0000000..aaa9241
--- /dev/null
+++ b/tools/build_defs/d/d.bzl
@@ -0,0 +1,450 @@
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""D rules for Bazel."""
+
+A_FILETYPE = FileType([".a"])
+D_FILETYPE = FileType([".d", ".di"])
+
+ZIP_PATH = "/usr/bin/zip"
+
+def _relative(src_path, dest_path):
+ """Returns the relative path from src_path to dest_path."""
+ src_parts = src_path.split("/")
+ dest_parts = dest_path.split("/")
+ n = 0
+ for src_part, dest_part in zip(src_parts, dest_parts):
+ if src_part != dest_part:
+ break
+ n += 1
+
+ relative_path = ""
+ for _ in range(n, len(src_parts)):
+ relative_path += "../"
+ relative_path += "/".join(dest_parts[n:])
+
+ return relative_path
+
+def _create_setup_cmd(lib, deps_dir):
+ """Constructs a command for symlinking a library into the deps directory."""
+ return (
+ "ln -sf " + _relative(deps_dir, lib.path) + " " +
+ deps_dir + "/" + lib.basename + "\n"
+ )
+
+def _d_toolchain(ctx):
+ """Returns a struct containing info about the D toolchain.
+
+ Args:
+ ctx: The ctx object.
+
+ Return:
+ Struct containing the following fields:
+ d_compiler_path: The path to the D compiler.
+ link_flags: Linker (-L) flags for adding the standard library to the
+ library search paths.
+ import_flags: import (-L) flags for adding the standard library sources
+ to the import paths.
+ """
+
+ d_compiler_path = ctx.file._d_compiler.path
+ return struct(
+ d_compiler_path = d_compiler_path,
+ link_flags = ["-L-L" + ctx.files._d_stdlib[0].dirname],
+ import_flags = [
+ "-I" + ctx.files._d_stdlib_src[0].dirname,
+ "-I" + ctx.files._d_runtime_import_src[0].dirname])
+
+def _format_version(name):
+ """Formats the string name to be used in a --version flag."""
+ return name.replace("-", "_")
+
+def _build_compile_command(ctx, srcs, out, depinfo, extra_flags=[]):
+ """Returns a string containing the D compile command."""
+ toolchain = _d_toolchain(ctx)
+ cmd = (
+ ["set -e;"] +
+ depinfo.setup_cmd +
+ [toolchain.d_compiler_path] +
+ extra_flags + [
+ "-of" + out.path,
+ "-I.",
+ "-debug",
+ "-w",
+ "-g",
+ ] +
+ ["-I%s/%s" % (ctx.label.package, im) for im in ctx.attr.imports] +
+ ["-I%s" % im for im in depinfo.imports] +
+ toolchain.import_flags +
+ ["-version=Have_%s" % _format_version(ctx.label.name)] +
+ ["-version=%s" % v for v in ctx.attr.versions] +
+ ["-version=%s" % v for v in depinfo.versions] +
+ srcs)
+ return " ".join(cmd)
+
+def _build_link_command(ctx, objs, out, depinfo):
+ """Returns a string containing the D link command."""
+ toolchain = _d_toolchain(ctx)
+ cmd = (
+ ["set -e;"] +
+ depinfo.setup_cmd +
+ [toolchain.d_compiler_path] +
+ ["-of" + out.path] +
+ toolchain.link_flags +
+ depinfo.lib_flags +
+ depinfo.link_flags +
+ objs)
+ return " ".join(cmd)
+
+def _setup_deps(deps, name, working_dir):
+ """Sets up dependencies.
+
+ Walks through dependencies and constructs the commands and flags needed
+ for linking the necessary dependencies.
+
+ Args:
+ deps: List of deps labels from ctx.attr.deps.
+ name: Name of the current target.
+ working_dir: The output directory of the current target's output.
+
+ Returns:
+ Returns a struct containing the following fields:
+ libs: List of Files containing the target's direct library dependencies.
+ transitive_d_libs: List of Files containing all of the target's
+ transitive libraries.
+ d_srcs: List of Files representing D source files of dependencies that
+ will be used as inputs for this target.
+ versions: List of D versions to be used for compiling the target.
+ setup_cmd: String containing the symlink commands to be used to set
+ up the dependencies.
+ imports: List of Strings containing input paths that will be passed
+ to the D compiler via -I flags.
+ link_flags: List of linker flags.
+ lib_flags: List of library search flags.
+ """
+ deps_dir = working_dir + "/" + name + ".deps"
+ setup_cmd = ["rm -rf " + deps_dir + ";" + "mkdir -p " + deps_dir + ";"]
+
+ libs = set()
+ transitive_d_libs = set()
+ d_srcs = set()
+ symlinked_libs = set()
+ versions = set()
+ imports = set()
+ link_flags = set()
+ for dep in deps:
+ if hasattr(dep, "d_lib"):
+ # The dependency is a d_library.
+ libs += [dep.d_lib]
+ d_srcs += dep.d_srcs
+ transitive_d_libs += [dep.d_lib] + dep.transitive_d_libs
+ symlinked_libs += [dep.d_lib] + dep.transitive_d_libs
+ versions += dep.versions
+ versions += ["Have_%s" % _format_version(dep.label.name)]
+ link_flags += ["-L-l%s" % dep.label.name] + dep.link_flags
+ imports += ["%s/%s" % (dep.label.package, im) for im in dep.imports]
+
+ elif hasattr(dep, "d_srcs"):
+ # The dependency is a d_source_library.
+ d_srcs += dep.d_srcs
+ transitive_d_libs += dep.transitive_d_libs
+ symlinked_libs += dep.transitive_d_libs
+ link_flags += ["-L%s" % linkopt for linkopt in dep.linkopts]
+ imports += ["%s/%s" % (dep.label.package, im) for im in dep.imports]
+ versions += dep.versions
+
+ elif hasattr(dep, "cc"):
+ # The dependency is a cc_library
+ native_libs = A_FILETYPE.filter(dep.cc.libs)
+ libs += native_libs
+ transitive_d_libs += native_libs
+ symlinked_libs += native_libs
+ link_flags += ["-L-l%s" % dep.label.name]
+
+ else:
+ fail("D targets can only depend on d_library, d_source_library, or " +
+ "cc_library targets.", "deps")
+
+ for symlinked_libs in symlinked_libs:
+ setup_cmd += [_create_setup_cmd(symlinked_libs, deps_dir)]
+
+ return struct(
+ libs = list(libs),
+ transitive_d_libs = list(transitive_d_libs),
+ d_srcs = list(d_srcs),
+ versions = versions,
+ setup_cmd = setup_cmd,
+ imports = list(imports),
+ link_flags = list(link_flags),
+ lib_flags = ["-L-L%s" % deps_dir])
+
+def _d_library_impl(ctx):
+ """Implementation of the d_library rule."""
+ d_lib = ctx.outputs.d_lib
+
+ # Dependencies
+ depinfo = _setup_deps(ctx.attr.deps, ctx.label.name, d_lib.dirname)
+
+ # Build compile command.
+ cmd = _build_compile_command(
+ ctx = ctx,
+ srcs = [src.path for src in ctx.files.srcs],
+ out = d_lib,
+ depinfo = depinfo,
+ extra_flags = ["-lib"])
+
+ compile_inputs = (
+ ctx.files.srcs +
+ depinfo.d_srcs +
+ depinfo.libs +
+ depinfo.transitive_d_libs +
+ [ctx.file._d_compiler] +
+ ctx.files._d_stdlib +
+ ctx.files._d_stdlib_src +
+ ctx.files._d_runtime_import_src)
+
+ ctx.action(inputs = compile_inputs,
+ outputs = [d_lib],
+ mnemonic = "Dcompile",
+ command = cmd,
+ use_default_shell_env = True,
+ progress_message = "Compiling D library " + ctx.label.name)
+
+ return struct(files = set([d_lib]),
+ d_srcs = ctx.files.srcs + depinfo.d_srcs,
+ transitive_d_libs = depinfo.transitive_d_libs,
+ link_flags = depinfo.link_flags,
+ versions = ctx.attr.versions,
+ imports = ctx.attr.imports,
+ d_lib = d_lib)
+
+def _d_binary_impl_common(ctx, extra_flags=[]):
+ """Common implementation for rules that build a D binary."""
+ d_bin = ctx.outputs.executable
+ d_obj = ctx.new_file(ctx.configuration.bin_dir,
+ d_bin.basename + ".o")
+ depinfo = _setup_deps(ctx.attr.deps, ctx.label.name, d_bin.dirname)
+
+ # Build compile command
+ compile_cmd = _build_compile_command(
+ ctx = ctx,
+ srcs = [src.path for src in ctx.files.srcs],
+ depinfo = depinfo,
+ out = d_obj,
+ extra_flags = ["-c"] + extra_flags)
+
+ toolchain_files = (
+ [ctx.file._d_compiler] +
+ ctx.files._d_stdlib +
+ ctx.files._d_stdlib_src +
+ ctx.files._d_runtime_import_src)
+
+ compile_inputs = ctx.files.srcs + depinfo.d_srcs + toolchain_files
+ ctx.action(inputs = compile_inputs,
+ outputs = [d_obj],
+ mnemonic = "Dcompile",
+ command = compile_cmd,
+ use_default_shell_env = True,
+ progress_message = "Compiling D binary " + ctx.label.name)
+
+ # Build link command
+ link_cmd = _build_link_command(
+ ctx = ctx,
+ objs = [d_obj.path],
+ depinfo = depinfo,
+ out = d_bin)
+
+ link_inputs = (
+ [d_obj] +
+ depinfo.libs +
+ depinfo.transitive_d_libs +
+ toolchain_files)
+
+ ctx.action(inputs = link_inputs,
+ outputs = [d_bin],
+ mnemonic = "Dlink",
+ command = link_cmd,
+ use_default_shell_env = True,
+ progress_message = "Linking D binary " + ctx.label.name)
+
+def _d_binary_impl(ctx):
+ """Implementation of the d_binary rule."""
+ return _d_binary_impl_common(ctx)
+
+def _d_test_impl(ctx):
+ """Implementation of the d_test rule."""
+ return _d_binary_impl_common(ctx, extra_flags=["-unittest"])
+
+def _d_source_library_impl(ctx):
+ """Implementation of the d_source_library rule."""
+ transitive_d_srcs = set(order="compile")
+ transitive_d_libs = set()
+ transitive_imports = set()
+ transitive_linkopts = set()
+ transitive_versions = set()
+ for dep in ctx.attr.deps:
+ if hasattr(dep, "d_srcs"):
+ # Dependency is another d_source_library target.
+ transitive_d_srcs += dep.d_srcs
+ transitive_imports += dep.imports
+ transitive_linkopts += dep.linkopts
+ transitive_versions += dep.versions
+
+ elif hasattr(dep, "cc"):
+ # Dependency is a cc_library target.
+ native_libs = A_FILETYPE.filter(dep.cc.libs)
+ transitive_d_libs += native_libs
+ transitive_linkopts += ["-l%s" % dep.label.name]
+
+ else:
+ fail("d_source_library can only depend on other " +
+ "d_source_library or cc_library targets.", "deps")
+
+ return struct(
+ d_srcs = ctx.files.srcs + list(transitive_d_srcs),
+ transitive_d_libs = transitive_d_libs,
+ imports = ctx.attr.imports + list(transitive_imports),
+ linkopts = ctx.attr.linkopts + list(transitive_linkopts),
+ versions = ctx.attr.versions + list(transitive_versions))
+
+# TODO(dzc): Use ddox for generating HTML documentation.
+def _d_docs_impl(ctx):
+ """Implementation for the d_docs rule
+
+ This rule runs the following steps to generate an archive containing
+ HTML documentation generated from doc comments in D source code:
+ 1. Run the D compiler with the -D flags to generate HTML code
+ documentation.
+ 2. Create a ZIP archive containing the HTML documentation.
+ """
+ d_docs_zip = ctx.outputs.d_docs
+ docs_dir = d_docs_zip.dirname + "/_d_docs"
+ objs_dir = d_docs_zip.dirname + "/_d_objs"
+
+ # Build D docs command
+ toolchain = _d_toolchain(ctx)
+ doc_cmd = (
+ [
+ "set -e;",
+ "rm -rf %s; mkdir %s;" % (docs_dir, docs_dir),
+ "rm -rf %s; mkdir %s;" % (objs_dir, objs_dir),
+ toolchain.d_compiler_path,
+ "-c",
+ "-D",
+ "-Dd%s" % docs_dir,
+ "-od%s" % objs_dir,
+ "-I.",
+ ] +
+ ["-I%s/%s" % (ctx.label.package, im) for im in ctx.attr.imports] +
+ toolchain.import_flags +
+ [src.path for src in ctx.files.srcs])
+
+ # HTML documentation generated by the D compiler.
+ d_docs = [
+ ctx.new_file(ctx.configuration.bin_dir,
+ "_d_docs/%s" % src.basename.replace(".d", ".html"))
+ for src in ctx.files.srcs]
+
+ # Object files created by the D compiler during documentation generation.
+ d_objs = [
+ ctx.new_file(ctx.configuration.bin_dir,
+ "_d_objs/%s" % src.basename.replace(".d", ".o"))
+ for src in ctx.files.srcs]
+
+ toolchain_files = (
+ [ctx.file._d_compiler] +
+ ctx.files._d_stdlib +
+ ctx.files._d_stdlib_src +
+ ctx.files._d_runtime_import_src)
+ ddoc_inputs = ctx.files.srcs + toolchain_files
+ ctx.action(inputs = ddoc_inputs,
+ outputs = d_docs + d_objs,
+ mnemonic = "Ddoc",
+ command = " ".join(doc_cmd),
+ use_default_shell_env = True,
+ progress_message = "Generating D docs for " + ctx.label.name)
+
+ # Build zip command.
+ zip_cmd = [
+ ZIP_PATH,
+ "-qj",
+ d_docs_zip.path,
+ ] + [doc.path for doc in d_docs]
+
+ ctx.action(inputs = d_docs,
+ outputs = [d_docs_zip],
+ mnemonic = "Ddoczip",
+ command = " ".join(zip_cmd),
+ use_default_shell_env = True,
+ progress_message = "Creating D doc archive for " + ctx.label.name)
+
+_d_common_attrs = {
+ "srcs": attr.label_list(allow_files = D_FILETYPE),
+ "deps": attr.label_list(),
+ "imports": attr.string_list(),
+ "linkopts": attr.string_list(),
+ "versions": attr.string_list(),
+}
+
+_d_compile_attrs = {
+ "_d_compiler": attr.label(
+ default = Label("//tools/build_defs/d:dmd"),
+ executable = True,
+ single_file = True),
+ "_d_stdlib": attr.label(
+ default = Label("//tools/build_defs/d:libphobos2")),
+ "_d_stdlib_src": attr.label(
+ default = Label("//tools/build_defs/d:phobos-src")),
+ "_d_runtime_import_src": attr.label(
+ default = Label("//tools/build_defs/d:druntime-import-src")),
+}
+
+d_library = rule(
+ _d_library_impl,
+ attrs = _d_common_attrs + _d_compile_attrs,
+ outputs = {
+ "d_lib": "lib%{name}.a",
+ },
+)
+
+d_source_library = rule(
+ _d_source_library_impl,
+ attrs = _d_common_attrs,
+)
+
+d_binary = rule(
+ _d_binary_impl,
+ executable = True,
+ attrs = _d_common_attrs + _d_compile_attrs,
+)
+
+d_test = rule(
+ _d_test_impl,
+ executable = True,
+ attrs = _d_common_attrs + _d_compile_attrs,
+ test = True,
+)
+
+_d_docs_attrs = {
+ "srcs": attr.label_list(allow_files = D_FILETYPE),
+ "imports": attr.string_list(),
+}
+
+d_docs = rule(
+ _d_docs_impl,
+ attrs = _d_docs_attrs + _d_compile_attrs,
+ outputs = {
+ "d_docs": "%{name}-docs.zip",
+ },
+)
diff --git a/tools/build_defs/d/dmd.BUILD b/tools/build_defs/d/dmd.BUILD
new file mode 100644
index 0000000..fc5df60
--- /dev/null
+++ b/tools/build_defs/d/dmd.BUILD
@@ -0,0 +1,43 @@
+package(default_visibility = ["//visibility:public"])
+
+config_setting(
+ name = "darwin",
+ values = {"host_cpu": "darwin"},
+)
+
+config_setting(
+ name = "k8",
+ values = {"host_cpu": "k8"},
+)
+
+filegroup(
+ name = "dmd",
+ srcs = select({
+ ":darwin": ["dmd2/osx/bin/dmd"],
+ ":k8": ["dmd2/linux/bin64/dmd"],
+ }),
+)
+
+filegroup(
+ name = "libphobos2",
+ srcs = select({
+ ":darwin": ["dmd2/osx/lib/libphobos2.a"],
+ ":k8": [
+ "dmd2/linux/lib64/libphobos2.a",
+ "dmd2/linux/lib64/libphobos2.so",
+ ],
+ }),
+)
+
+filegroup(
+ name = "phobos-src",
+ srcs = glob(["dmd2/src/phobos/**/*.*"]),
+)
+
+filegroup(
+ name = "druntime-import-src",
+ srcs = glob([
+ "dmd2/src/druntime/import/*.*",
+ "dmd2/src/druntime/import/**/*.*",
+ ]),
+)