diff --git a/.whitesource b/.whitesource new file mode 100644 index 0000000..327ddac --- /dev/null +++ b/.whitesource @@ -0,0 +1,30 @@ +{ + "scanSettings": { + "configMode": "AUTO", + "configExternalURL": "", + "projectToken": "", + "baseBranches": [] + }, + "checkRunSettings": { + "vulnerableCheckRunConclusionLevel": "failure", + "displayMode": "diff", + "useMendCheckNames": true + }, + "issueSettings": { + "minSeverityLevel": "LOW", + "issueType": "DEPENDENCY" + }, + "remediateSettings": { + "workflowRules": { + "enabled": true + } + }, + "imageSettings":{ + "imageTracing":{ + "enableImageTracingPR": false, + "addRepositoryCoordinate": false, + "addDockerfilePath": false, + "addMendIdentifier": false + } + } +} \ No newline at end of file diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000..b63d86f --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,19 @@ +module( + name = "rules_d", +) + +bazel_dep( + name = "bazel_skylib", + version = "1.7.1", +) + +bazel_dep(name="platforms", version="0.0.11") + +non_module_dependencies = use_extension("//d:extensions.bzl", "non_module_dependencies") +use_repo(non_module_dependencies, "ldc_linux_x86_64", "dmd_linux_x86_64", "dmd_darwin_x86_64", "weka_ldc_linux_x86_64") +register_toolchains( + "//d:ldc_linux_x86_64_toolchain", + "//d:dmd_linux_x86_64_toolchain", + "//d:dmd_darwin_x86_64_toolchain", + "//d:weka_ldc_linux_x86_64_toolchain", + ) diff --git a/README.md b/README.md index 3c94072..3983106 100644 --- a/README.md +++ b/README.md @@ -1,694 +1,5 @@ -[![Build status](https://badge.buildkite.com/255dd622ff5647b60b08b6578e49df80f78c9b0d88f2758491.svg)](https://buildkite.com/bazel/rules-d) +# A very opinionated fork of https://github.com/bazel-contrib/rules_d -# D rules +## Differences with `bazel-contrib/rules_d` -## Status - -We make sure this repository works with the latest version of Bazel, but no -other development is planned. - -Volunteers are welcome. If you want to use the rules, consider contributing to -this repository and becoming a maintainer. - -## Rules - -
- -
- -## Setup - -To use the D rules, add the following to your `WORKSPACE` file to add the -external repositories for the D toolchain: - -```python -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -http_archive( - name = "io_bazel_rules_d", - urls = ["https://github.com/bazelbuild/rules_d/archive/bcf137e3c9381545ce54715632bc1d31c51ee4da.tar.gz"], - sha256 = "a32847bf2ae634563dece49c4dc8353956b64ba5c2d01ce811ea243e1a21b5b7", - strip_prefix = "rules_d-bcf137e3c9381545ce54715632bc1d31c51ee4da", -) - -load("@io_bazel_rules_d//d:d.bzl", "d_repositories") -d_repositories() -``` - -## 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/) - - -## d_library - -```python -d_library(name, srcs, deps, includes, linkopts, versions) -``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-

- This name will be used as the name of the library built by this rule. -

-
srcs - List of labels, required -

List of D .d source files used to build the library.

-
deps - List of labels, optional -

List of libraries to be linked to this library target.

-

- These can either be other d_library targets, - source-only d_source_library targets, or - cc_library targets if linking a native library. -

-
imports - List of strings, optional -

List of import dirs to add to the compile line.

-

- These will be passed to the D compiler via -I flags. -

-
linkopts - List of strings, optional -

List of flags that are added to the D linker command.

-

- These will be passed to the D compiler via -L flags. -

-
versions - List of strings, optional -

List of versions to be defined during compilation.

-

- Versions are used for conditional compilation and are enabled in the - code using version condition blocks. These versions - listed here will be passed to the D compiler using - -version flags. -

-
- -### 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("@io_bazel_rules_d//d:d.bzl", "d_library") - -d_library( - name = "foo", - srcs = [ - "foo.d", - "bar.d", - "baz.d", - ], -) -``` - - -## d_source_library - -```python -d_source_library(name, srcs, deps, includes, linkopts, versions) -``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-
srcs - List of labels, required -

- List of D .d source files that comprises this source - library target. -

-
deps - List of labels, optional -

List of library targets depended on by this target.

-

- These can either be other d_source_library targets or - cc_library targets, such as when this source library - target implements the D interface for a native library. Any native - libraries will be linked by d_library targets that - depend on this target. -

-
imports - List of strings, optional -

List of import dirs to add to the compile line.

-

- These will be passed to the D compiler via -I flags for - any d_library targets that depend on this target. -

-
linkopts - List of strings, optional -

List of flags that are added to the D linker command.

-

- These will be passed to the D compiler via -L flags for - any d_library targets that depend on this target. -

-
versions - List of strings, optional -

List of version flags to be defined during compilation.

-

- Versions are used for conditional compilation and are enabled in the - code using version condition blocks. These versions - listed here will be passed to the D compiler using - -version flags for any d_library targets - that depend on this target. -

-
- -### 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("@io_bazel_rules_d//d:d.bzl", "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("@io_bazel_rules_d//d:d.bzl", "d_source_library") - -d_binary( - name = "hello_world", - srcs = ["hello_world.d"], - deps = ["//greeter:native_greeter"], -) -``` - - -## d_binary - -```python -d_binary(name, srcs, deps, includes, linkopts, versions) -``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-

- This name will be used as the name of the binary built by this rule. -

-
srcs - List of labels, required -

List of D .d source files used to build the binary.

-
deps - List of labels, optional -

List of libraries to be linked to this binary target.

-

- These can either be other d_library targets, - source-only d_source_library targets, or - cc_library targets if linking a native library. -

-
imports - List of strings, optional -

List of import dirs to add to the compile line.

-

- These will be passed to the D compiler via -I flags. -

-
linkopts - List of strings, optional -

List of flags that are added to the D linker command.

-

- These will be passed to the D compiler via -L flags. -

-
versions - List of strings, optional -

List of versions to be defined during compilation.

-

- Versions are used for conditional compilation and are enabled in the - code using version condition blocks. These versions - listed here will be passed to the D compiler using - -version flags. -

-
- -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("@io_bazel_rules_d//d:d.bzl", "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("@io_bazel_rules_d//d:d.bzl", "d_library") - -d_binary( - name = "hello_world", - srcs = ["hello_world.d"], - deps = ["//hello_lib"], -) -``` - - -## d_test - -```python -d_test(name, srcs, deps, includes, linkopts, versions) -``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-

- This name will be used as the name of the test built by this rule. -

-
srcs - List of labels, required -

List of D .d source files used to build the test.

-
deps - List of labels, optional -

List of libraries to be linked to this test target.

-

- These can either be other d_library targets, - source-only d_source_library targets, or - cc_library targets if linking a native library. -

-
imports - List of strings, optional -

List of import dirs to add to the compile line.

-

- These will be passed to the D compiler via -I flags. -

-
linkopts - List of strings, optional -

List of flags that are added to the D linker command.

-

- These will be passed to the D compiler via -L flags. -

-
versions - List of strings, optional -

List of versions to be defined during compilation.

-

- Versions are used for conditional compilation and are enabled in the - code using version condition blocks. These versions - listed here will be passed to the D compiler using - -version flags. -

-
- -### 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("@io_bazel_rules_d//d:d.bzl", "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 -``` - - -## d_docs - -```python -d_docs(name, dep) -``` - - - - - - - - - - - - - - - - - - - - - -
Attributes
name - Name, required -

A unique name for this rule.

-
dep - Label, required -

The label of the target to generate code documentation for.

-

- d_docs can generate HTML code documentation for the - source files of d_library, d_source_library, - d_binary, or d_test targets. -

-
- -### Example - -Suppose you have the following directory structure for a D project: - -``` -[workspace]/ - WORKSPACE - foo/ - BUILD - foo.d - bar.d - baz.d -``` - -The `foo/` directory contains the sources for the `d_library` `foo`. To -generate HTML documentation for the `foo` library, define a `d_docs` target -that takes the `d_library` `foo` as its dependency: - -`foo/BUILD`: - -```python -load("@io_bazel_rules_d//d:d.bzl", "d_library", "d_docs") - -d_library( - name = "foo", - srcs = [ - "foo.d", - "bar.d", - "baz.d", - ], -) - -d_docs( - name = "foo_docs", - dep = ":foo", -) -``` - -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. +1. TBD diff --git a/WORKSPACE b/WORKSPACE index 733a0f4..9aceb46 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,4 +1,2 @@ -workspace(name = "io_bazel_rules_d") - -load("@io_bazel_rules_d//d:d.bzl", "d_repositories") -d_repositories() +## This is just a root of workspace marked +## Dependencies are moved to MODULE.bazel diff --git a/d/BUILD b/d/BUILD index 11b67c9..f0e4bc4 100644 --- a/d/BUILD +++ b/d/BUILD @@ -1,57 +1,126 @@ package(default_visibility = ["//visibility:public"]) +load("//d:toolchain.bzl", "D_TOOLCHAIN", "d_toolchain") + +toolchain_type(name = "toolchain_type") + filegroup( name = "srcs", srcs = glob(["**"]), ) -config_setting( - name = "darwin", - values = {"host_cpu": "darwin"}, -) +[d_toolchain( + name = "dmd_" + os + "_x86_64", + d_compiler = "@dmd_" + os + "_x86_64//:dmd", + druntime_src = "@dmd_" + os + "_x86_64//:druntime_src", + libphobos = "@dmd_" + os + "_x86_64//:libphobos2", + libphobos_src = "@dmd_" + os + "_x86_64//:phobos_src", + version_flag = "-version", +) for os in ["linux", "darwin"]] # , "windows"]] -config_setting( - name = "k8", - values = {"host_cpu": "k8"}, +toolchain( + name = "dmd_linux_x86_64_toolchain", + exec_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + "//d/constraints/compiler:dmd", + ], + target_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + toolchain = ":dmd_linux_x86_64", + toolchain_type = D_TOOLCHAIN, ) -config_setting( - name = "x64_windows", - values = {"host_cpu": "x64_windows"}, +toolchain( + name = "dmd_darwin_x86_64_toolchain", + exec_compatible_with = [ + "@platforms//os:macos", + "@platforms//cpu:x86_64", + "//d/constraints/compiler:dmd", + ], + target_compatible_with = [ + "@platforms//os:macos", + "@platforms//cpu:x86_64", + ], + toolchain = ":dmd_darwin_x86_64", + toolchain_type = D_TOOLCHAIN, ) -filegroup( - name = "dmd", - srcs = select({ - ":darwin": ["@dmd_darwin_x86_64//:dmd"], - ":k8": ["@dmd_linux_x86_64//:dmd"], - ":x64_windows": ["@dmd_windows_x86_64//:dmd"], - }), +# toolchain( +# name = "dmd_windows_x86_64_toolchain", +# exec_compatible_with = [ +# "@platforms//os:windows", +# "@platforms//cpu:x86_64", +# "//d/constraints/compiler:dmd", +# ], +# target_compatible_with = [ +# "@platforms//os:windows", +# "@platforms//cpu:x86_64", +# ], +# toolchain = ":dmd_windows_x86_64", +# toolchain_type = D_TOOLCHAIN, +# ) + +d_toolchain( + name = "ldc_linux_x86_64", + d_compiler = "@ldc_linux_x86_64//:ldc2", + druntime = "@ldc_linux_x86_64//:druntime", + druntime_src = "@ldc_linux_x86_64//:druntime_src", + libphobos = "@ldc_linux_x86_64//:libphobos2", + libphobos_src = "@ldc_linux_x86_64//:phobos_src", + version_flag = "--d-version", + lib_flags = [ + "-lib", "-oq", + ], + output_bc_flags = ["--output-bc"], ) -filegroup( - name = "libphobos2", - srcs = select({ - ":darwin": ["@dmd_darwin_x86_64//:libphobos2"], - ":k8": ["@dmd_linux_x86_64//:libphobos2"], - ":x64_windows": ["@dmd_windows_x86_64//:libphobos2"], - }), +toolchain( + name = "ldc_linux_x86_64_toolchain", + exec_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + "//d/constraints/compiler:ldc", + ], + target_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + toolchain = ":ldc_linux_x86_64", + toolchain_type = D_TOOLCHAIN, ) -filegroup( - name = "phobos-src", - srcs = select({ - ":darwin": ["@dmd_darwin_x86_64//:phobos-src"], - ":k8": ["@dmd_linux_x86_64//:phobos-src"], - ":x64_windows": ["@dmd_windows_x86_64//:phobos-src"], - }), +d_toolchain( + name = "weka_ldc_linux_x86_64", + d_compiler = "@weka_ldc_linux_x86_64//:ldc2", + druntime = "@weka_ldc_linux_x86_64//:druntime", + druntime_src = "@weka_ldc_linux_x86_64//:druntime_src", + libphobos = "@weka_ldc_linux_x86_64//:libphobos2", + libphobos_src = "@weka_ldc_linux_x86_64//:phobos_src", + version_flag = "--d-version", + lib_flags = [ + "-lib", "-oq", + ], + hdrgen_flags = [ + "-Honly", + ], + debug_repo_root_override = "/source", + output_bc_flags = ["--output-bc"], ) -filegroup( - name = "druntime-import-src", - srcs = select({ - ":darwin": ["@dmd_darwin_x86_64//:druntime-import-src"], - ":k8": ["@dmd_linux_x86_64//:druntime-import-src"], - ":x64_windows": ["@dmd_windows_x86_64//:druntime-import-src"], - }), +toolchain( + name = "weka_ldc_linux_x86_64_toolchain", + exec_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + "//d/constraints/compiler:weka-ldc", + ], + target_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + toolchain = ":weka_ldc_linux_x86_64", + toolchain_type = D_TOOLCHAIN, ) diff --git a/d/DMD.bzl b/d/DMD.bzl new file mode 100644 index 0000000..3645d34 --- /dev/null +++ b/d/DMD.bzl @@ -0,0 +1,50 @@ +load("@bazel_skylib//rules:native_binary.bzl", "native_binary") + +package(default_visibility = ["//visibility:public"]) + +native_binary( + name = "dmd", + out = "dmdcopy.exe", + src = select({ + "@bazel_tools//src/conditions:darwin": "osx/bin/dmd", + "@bazel_tools//src/conditions:linux_x86_64": "linux/bin64/dmd", + # "@bazel_tools//src/conditions:windows_x64": "windows/bin64/dmd.exe", + }), + data = select({ + "@bazel_tools//src/conditions:darwin": ["osx/bin/dmd.conf"], + "@bazel_tools//src/conditions:linux_x86_64": ["linux/bin64/dmd.conf"], + # "@bazel_tools//src/conditions:windows_x64": glob(["windows/lib64/mingw/**"]) + [ + # "windows/bin64/sc.ini", + # "windows/bin64/lld-link.exe", + # "windows/bin64/libcurl.dll", + # "windows/bin64/msvcr120.dll", + # "windows/lib64/curl.lib", + # ], + }), +) + +cc_import( + name = "libphobos2", + # shared_library = select({ + # "@bazel_tools//src/conditions:linux_x86_64": "linux/lib64/libphobos2.so", + # "//conditions:default": None, + # }), + static_library = select({ + "@bazel_tools//src/conditions:darwin": "osx/lib/libphobos2.a", + "@bazel_tools//src/conditions:linux_x86_64": "linux/lib64/libphobos2.a", + # "@bazel_tools//src/conditions:windows_x64": "windows/lib64/phobos64.lib", + }), +) + +filegroup( + name = "phobos_src", + srcs = glob(["src/phobos/**/*.*"]), +) + +filegroup( + name = "druntime_src", + srcs = glob([ + "src/druntime/import/*.*", + "src/druntime/import/**/*.*", + ]), +) diff --git a/d/LDC.bzl b/d/LDC.bzl new file mode 100644 index 0000000..b89e096 --- /dev/null +++ b/d/LDC.bzl @@ -0,0 +1,62 @@ +load("@bazel_skylib//rules:native_binary.bzl", "native_binary") + +package(default_visibility = ["//visibility:public"]) + +native_binary( + name = "ldc2", + out = "ldc2copy.exe", + src = select({ + "@bazel_tools//src/conditions:darwin": "bin/ldc2", + "@bazel_tools//src/conditions:linux_x86_64": "bin/ldc2", + # "@bazel_tools//src/conditions:windows_x64": "bin/ldc2.exe", + }), + # TODO: add the conf files to `data` field. +) + +cc_import( + name = "libphobos2", + shared_library = select({ + "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", + "@bazel_tools//src/conditions:linux_x86_64": "lib/libphobos2-ldc-shared.so", + # "@bazel_tools//src/conditions:windows_x64": "lib/phobos2-ldc-shared.lib", + }), + static_library = select({ + "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", + "@bazel_tools//src/conditions:linux_x86_64": "lib/libphobos2-ldc.a", + # "@bazel_tools//src/conditions:windows_x64": "lib/phobos2-ldc.lib", + }), +) + +cc_import( + name = "druntime", + shared_library = select({ + "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", + "@bazel_tools//src/conditions:linux_x86_64": "lib/libdruntime-ldc-shared.so", + # "@bazel_tools//src/conditions:windows_x64": "lib/druntime-ldc-shared.lib", + }), + static_library = select({ + "@bazel_tools//src/conditions:darwin": "osx/lib/dmd", + "@bazel_tools//src/conditions:linux_x86_64": "lib/libdruntime-ldc.a", + # "@bazel_tools//src/conditions:windows_x64": "lib/druntime-ldc.lib", + }), +) + +filegroup( + name = "phobos_src", + srcs = glob([ + "import/std/**/*.*", + "import/std/*.*", + "import/etc/**/*.*", + # "import/etc/*.*", + ]), +) + +filegroup( + name = "druntime_src", + srcs = glob([ + "import/core/**/*.*", + "import/core/*.*", + "import/ldc/**/*.*", + "import/ldc/*.*", + ]), +) diff --git a/d/config.bzl b/d/config.bzl new file mode 100644 index 0000000..dfdce8b --- /dev/null +++ b/d/config.bzl @@ -0,0 +1,34 @@ +""" +Configuration information for the D toolchain. +""" + +DToolchainConfigInfo = provider( + doc = "Configuration information for the D toolchain.", + fields = [ + # binaries + "d_compiler", + "c_compiler", + "llc_compiler", + # libraries + "libphobos", + "libphobos_src", + "druntime", + "druntime_src", + # flags that can differ for different toolchains + "lib_flags", + "import_flags", # unused + "version_flag", + "hdrgen_flags", + "output_bc_flags", + # compilation modes + "copts_per_mode", + "copts_common", + "linkopts_per_mode", + "linkopts_common", + "codegen_opts_common", + "codegen_opts_per_mode", + "global_versions_per_mode", + "global_versions_common", + "debug_repo_root_override", + ], +) diff --git a/d/constraints/compiler/BUILD b/d/constraints/compiler/BUILD new file mode 100644 index 0000000..53d2e18 --- /dev/null +++ b/d/constraints/compiler/BUILD @@ -0,0 +1,21 @@ +package(default_visibility = ["//visibility:public"]) + +constraint_setting( + name = "d_compiler", + default_constraint_value = ":dmd", +) + +constraint_value( + name = "dmd", + constraint_setting = ":d_compiler", +) + +constraint_value( + name = "ldc", + constraint_setting = ":d_compiler", +) + +constraint_value( + name = "weka-ldc", + constraint_setting = ":d_compiler", +) diff --git a/d/d.bzl b/d/d.bzl index 0d2696f..a1ef590 100644 --- a/d/d.bzl +++ b/d/d.bzl @@ -14,7 +14,7 @@ """D rules for Bazel.""" -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("//d:toolchain.bzl", "D_TOOLCHAIN") def _is_windows(ctx): return ctx.configuration.host_path_separator == ";" @@ -23,10 +23,20 @@ def a_filetype(ctx, files): lib_suffix = ".lib" if _is_windows(ctx) else ".a" return [f for f in files if f.basename.endswith(lib_suffix)] -D_FILETYPE = [".d", ".di"] +D_FILETYPE = [".d", ".di", ".h"] # TODO: restrict support of .di and .h files to source libraries ZIP_PATH = "/usr/bin/zip" +DInfo = provider() + +def _with_runfiles(tool): + """Returns a list of files _and_ runfiles for `tool`.""" + files = tool.files.to_list() + runfiles = tool[DefaultInfo].default_runfiles + if runfiles: + files += runfiles.files.to_list() + return files + def _files_directory(files): """Returns the shortest parent directory of a list of files.""" dir = files[0].dirname @@ -35,179 +45,371 @@ def _files_directory(files): dir = f.dirname return dir -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 (-I) 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/LIBPATH:" if _is_windows(ctx) else "-L-L") + ctx.files._d_stdlib[0].dirname], - import_flags = [ - "-I" + _files_directory(ctx.files._d_stdlib_src), - "-I" + _files_directory(ctx.files._d_runtime_import_src), - ], - ) - -COMPILATION_MODE_FLAGS_POSIX = { +DEFAULT_COMPILATION_MODE_FLAGS_POSIX = { "fastbuild": ["-g"], - "dbg": ["-debug", "-g"], + "dbg": ["-d-debug", "-d-version=debug_assert", "-g"], "opt": ["-checkaction=halt", "-boundscheck=safeonly", "-O"], } -COMPILATION_MODE_FLAGS_WINDOWS = { +DEFAULT_COMPILATION_MODE_FLAGS_WINDOWS = { "fastbuild": ["-g", "-m64", "-mscrtlib=msvcrt"], "dbg": ["-debug", "-g", "-m64", "-mscrtlib=msvcrtd"], - "opt": ["-checkaction=halt", "-boundscheck=safeonly", "-O", - "-m64", "-mscrtlib=msvcrt"], + "opt": [ + "-checkaction=halt", + "-boundscheck=safeonly", + "-O", + "-m64", + "-mscrtlib=msvcrt", + ], } -def _compilation_mode_flags(ctx): - """Returns a list of flags based on the compilation_mode.""" +def _default_compilation_mode_flags(ctx): + """Returns the default compilation mode flags.""" if _is_windows(ctx): - return COMPILATION_MODE_FLAGS_WINDOWS[ctx.var["COMPILATION_MODE"]] + return DEFAULT_COMPILATION_MODE_FLAGS_WINDOWS[ctx.var["COMPILATION_MODE"]] + else: + return DEFAULT_COMPILATION_MODE_FLAGS_POSIX[ctx.var["COMPILATION_MODE"]] + +def _compilation_mode_flags_helper(ctx): + """Helper function to return the flags for the compilation mode.""" + toolchain = ctx.toolchains[D_TOOLCHAIN] + compilation_mode = ctx.var["COMPILATION_MODE"] + default_flags = _default_compilation_mode_flags(ctx) + if compilation_mode == "dbg": + return toolchain.dbg_flags or default_flags + elif compilation_mode == "opt": + return toolchain.opt_flags or default_flags + elif compilation_mode == "fastbuild": + return toolchain.fastbuild_flags or default_flags else: - return COMPILATION_MODE_FLAGS_POSIX[ctx.var["COMPILATION_MODE"]] + fail("Invalid compilation mode: %s" % compilation_mode) + +def _compilation_mode_flags(ctx): + """Returns a list of flags based on the compilation mode.""" + toolchain = ctx.toolchains[D_TOOLCHAIN] + return (toolchain.common_flags or []) + _compilation_mode_flags_helper(ctx) def _format_version(name): """Formats the string name to be used in a --version flag.""" return name.replace("-", "_") -def _build_import(label, im): +def _build_import(label, im, gen_dir = None): """Builds the import path under a specific label""" import_path = "" if label.workspace_root: import_path += label.workspace_root + "/" if label.package: import_path += label.package + "/" - import_path += im + if im == ".": + import_path = import_path[0:len(import_path) - 1] + else: + import_path += im + if gen_dir: + import_path = gen_dir + "/" + import_path return import_path def _build_compile_arglist(ctx, out, depinfo, extra_flags = []): """Returns a list of strings constituting the D compile command arguments.""" - toolchain = _d_toolchain(ctx) + toolchain = ctx.toolchains[D_TOOLCHAIN] + version_flag = toolchain.version_flag + gen_dir = ctx.genfiles_dir.path if ctx.attr.is_generated else None + + ws_root = gen_dir if ctx.attr.is_generated else "." + + versions = depset( + toolchain.global_versions_common + toolchain.global_versions_per_mode[ctx.var["COMPILATION_MODE"]], + transitive = [depinfo.versions]) return ( _compilation_mode_flags(ctx) + extra_flags + [ "-of" + out.path, - "-I.", "-w", ] + - ["-I%s" % _build_import(ctx.label, im) for im in ctx.attr.imports] + + (toolchain.output_bc_flags if ctx.attr.compile_via_bc else []) + + (["-I%s" % ws_root] if ctx.attr.include_workspace_root else []) + ["-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] + ["-J%s" % im for im in depinfo.string_imports] + + # toolchain.import_flags + + [version_flag + "=%s" % v for v in versions.to_list()] ) -def _build_link_arglist(ctx, objs, out, depinfo): +def _sort_objects(objs, link_order): + """Sorts the objects in the order they need to be linked.""" + if not link_order: + return [o.path for o in objs] + return [ + obj.path for i, obj in sorted(enumerate(objs), key=lambda x: link_order.get(x[1].path, x[0])) + ] + +def _link_order_dict(objs, link_order): + """Builds a dictionary mapping object file paths to their link order index.""" + if not link_order: + return {} + size = len(objs) + link_order_dict = dict() + for k, v in link_order.items(): + idx = int(v) + if idx < 0: + idx = size - 1 - idx + for p in k.files.to_list(): + link_order_dict[p.path] = idx + return link_order_dict + +def _build_link_arglist(ctx, objs, out, depinfo, c_compiler, link_flags, link_order): """Returns a list of strings constituting the D link command arguments.""" - toolchain = _d_toolchain(ctx) + if not ctx.attr.use_lto: + transitive_libs = [depinfo.libs, depinfo.transitive_libs] + else: + transitive_libs = [depinfo.libs_bc, depinfo.libs_non_bc, depinfo.transitive_libs_bc, depinfo.transitive_libs_non_bc] + all_objs = objs + depset(transitive = transitive_libs).to_list() + sorted_objs = _sort_objects(all_objs, _link_order_dict(all_objs, link_order)) return ( _compilation_mode_flags(ctx) + + (["-gcc=%s" % c_compiler.files.to_list()[0].path] if c_compiler else []) + + (link_flags or []) + + (["-L--dynamic-list=%s" % ctx.files.dynamic_symbols[0].path] if ctx.files.dynamic_symbols else []) + ["-of" + out.path] + - toolchain.link_flags + - [f.path for f in depset(transitive = [depinfo.libs, depinfo.transitive_libs]).to_list()] + depinfo.link_flags + - objs + sorted_objs ) -def _setup_deps(ctx, deps, name, working_dir): +def _find_gensrc_location(loc, src): + if loc.startswith("@"): + fail("Cannot place the generated source %s into location %s" % ( + src, loc)) + if loc.startswith("//"): + label = Label(loc) + return label.package + "/" + label.name + return src.label.package + "/" + loc + +def _setup_deps(ctx, deps, impl_deps, name): """Sets up dependencies. Walks through dependencies and constructs the commands and flags needed for linking the necessary dependencies. Args: + ctx: The context of the current target. deps: List of deps labels from ctx.attr.deps. + impl_deps: List of deps labels from ctx.attr.implementation_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_libs: List of Files containing all of the target's transitive libraries. + transitive_bc_libs: List of transitive deps as bc files (where they exist) + transitive_non_bc_libs: List of transitive deps that don't exists as bc 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. imports: List of Strings containing input paths that will be passed to the D compiler via -I flags. + string_imports: List of strings containing input paths that will be + passed to the D compiler via -J flags. link_flags: List of linker flags. + generated_srcs: A dictionary mapping generated files to their + desired locations. + data: List of Files containing extra (non-source) files that will + be used as inputs for this target. """ + gen_dir = ctx.genfiles_dir.path libs = [] + libs_bc = [] + libs_non_bc = [] transitive_libs = [] + transitive_libs_bc = [] + transitive_libs_non_bc = [] d_srcs = [] + data = [] transitive_d_srcs = [] - versions = [] - imports = [] + transitive_data = [] + versions = ctx.attr.versions + ["Have_%s" % _format_version(name)] + transitive_versions = [] + gen_dir_for_imports = gen_dir if ctx.attr.is_generated else None + imports = [_build_import(ctx.label, im, gen_dir_for_imports) for im in ctx.attr.imports] + string_imports = [_build_import(ctx.label, im, gen_dir_for_imports) for im in ctx.attr.string_imports] link_flags = [] + generated_srcs = { + src.files.to_list()[0]: _find_gensrc_location(loc, src) for src, loc in ctx.attr.generated_srcs.items()} for dep in deps: - if hasattr(dep, "d_lib"): + if DInfo in dep and hasattr(dep[DInfo], "d_lib"): # The dependency is a d_library. - libs.append(dep.d_lib) - transitive_libs.append(dep.transitive_libs) - d_srcs += dep.d_srcs - transitive_d_srcs.append(dep.transitive_d_srcs) - versions += dep.versions + ["Have_%s" % _format_version(dep.label.name)] - link_flags.extend(dep.link_flags) - imports += [_build_import(dep.label, im) for im in dep.imports] - - elif hasattr(dep, "d_srcs"): + ddep = dep[DInfo] + if ddep.d_lib: + libs.append(ddep.d_lib) + if ddep.d_lib_bc: + libs_bc.append(ddep.d_lib_bc) + else: + libs_non_bc.append(ddep.d_lib) + transitive_libs.append(ddep.transitive_libs) + transitive_libs_bc.append(ddep.transitive_libs_bc) + transitive_libs_non_bc.append(ddep.transitive_libs_non_bc) + + d_srcs += ddep.d_exports + transitive_d_srcs.append(ddep.transitive_d_srcs) + data += ddep.data + transitive_data.append(ddep.transitive_data) + transitive_versions.append(ddep.versions) + link_flags.extend(ddep.link_flags) + link_flags += ["-L%s" % linkopt for linkopt in ddep.linkopts] + imports += ddep.imports + if ddep.is_generated: + imports.append(gen_dir) + string_imports += ddep.string_imports + generated_srcs = generated_srcs | ddep.generated_srcs + + elif DInfo in dep and hasattr(dep[DInfo], "d_srcs"): # The dependency is a d_source_library. - d_srcs += dep.d_srcs - transitive_d_srcs.append(dep.transitive_d_srcs) - transitive_libs.append(dep.transitive_libs) - link_flags += ["-L%s" % linkopt for linkopt in dep.linkopts] - imports += [_build_import(dep.label, im) for im in dep.imports] - versions += dep.versions + ddep = dep[DInfo] + d_srcs += ddep.d_srcs + transitive_d_srcs.append(ddep.transitive_d_srcs) + data += ddep.data + transitive_data.append(ddep.transitive_data) + transitive_libs.append(ddep.transitive_libs) + transitive_libs_bc.append(ddep.transitive_libs_bc) + transitive_libs_non_bc.append(ddep.transitive_libs_non_bc) + link_flags += ["-L%s" % linkopt for linkopt in ddep.linkopts] + imports += ddep.imports + if ddep.is_generated: + imports.append(gen_dir) + string_imports += ddep.string_imports + transitive_versions.append(ddep.versions) + generated_srcs = generated_srcs | ddep.generated_srcs elif CcInfo in dep: # The dependency is a cc_library native_libs = a_filetype(ctx, _get_libs_for_static_executable(dep)) libs.extend(native_libs) + libs_non_bc.extend(native_libs) transitive_libs.append(depset(native_libs)) + transitive_libs_non_bc.append(depset(native_libs)) else: fail("D targets can only depend on d_library, d_source_library, or " + - "cc_library targets.", "deps") + "cc_library targets.", dep) + + impl_srcs = [] + for dep in impl_deps: + if DInfo in dep and hasattr(dep[DInfo], "d_lib"): + ddep = dep[DInfo] + libs.append(ddep.d_lib) + if ddep.d_lib_bc: + libs_bc.append(ddep.d_lib_bc) + else: + libs_non_bc.append(ddep.d_lib) + transitive_libs.append(ddep.transitive_libs) + transitive_libs_bc.append(ddep.transitive_libs_bc) + transitive_libs_non_bc.append(ddep.transitive_libs_non_bc) + impl_srcs.extend(ddep.d_exports) + elif CcInfo in dep: + native_libs = a_filetype(ctx, _get_libs_for_static_executable(dep)) + libs.extend(native_libs) + libs_non_bc.extend(native_libs) + transitive_libs.append(depset(native_libs)) + transitive_libs_non_bc.append(depset(native_libs)) + else: + fail("Implementation dependencies can only depend on d_library or cc_library targets.", dep) return struct( libs = depset(libs), + libs_bc = depset(libs_bc), + libs_non_bc = depset(libs_non_bc), transitive_libs = depset(transitive = transitive_libs), - d_srcs = depset(d_srcs).to_list(), - transitive_d_srcs = depset(transitive = transitive_d_srcs), - versions = versions, + transitive_libs_bc = depset(transitive = transitive_libs_bc), + transitive_libs_non_bc = depset(transitive = transitive_libs_non_bc), + transitive_d_srcs = depset(d_srcs, transitive = transitive_d_srcs), + data = depset(data).to_list(), + transitive_data = depset(transitive = transitive_data), + versions = depset(versions, transitive = transitive_versions), imports = depset(imports).to_list(), + string_imports = depset(string_imports).to_list(), link_flags = depset(link_flags).to_list(), + generated_srcs = generated_srcs, + impl_srcs = impl_srcs, ) -def _d_library_impl(ctx): +def _handle_generated_srcs(ctx, generated_srcs, d_compiler, debug_repo_root_override): + """Handles the generated source files.""" + if not generated_srcs and not debug_repo_root_override: + return (ctx.files.srcs, None) + mapped_srcs = [src if src not in generated_srcs else generated_srcs[src] for src in ctx.files.srcs] + + wrapper = ctx.actions.declare_file(ctx.label.name + "_d_compile_wrapper.sh") + debug_prefix_map = "-fdebug-prefix-map=$PWD=%s " % debug_repo_root_override if debug_repo_root_override else "" + ctx.actions.write( + output = wrapper, + content = "\n".join( + [ + "#!/bin/bash", + "set -e", + ] + + [ + "mkdir -p $(dirname %s)\n" % loc + + "[ -f $PWD/%s ] && ln -s $PWD/%s %s" % (src.path, src.path, loc) for src, loc in generated_srcs.items() + ] + [ + "%s %s$*" % (d_compiler.path, debug_prefix_map), + ]), + is_executable = True, + ) + + return (mapped_srcs, wrapper) + +def _d_library_impl_common(ctx, extra_flags = []): """Implementation of the d_library rule.""" - d_lib = ctx.actions.declare_file((ctx.label.name + ".lib") if _is_windows(ctx) else ("lib" + ctx.label.name + ".a")) + toolchain = ctx.toolchains[D_TOOLCHAIN] + d_compiler = toolchain.d_compiler.files.to_list()[0] + + if ctx.attr.compile_via_bc and not toolchain.output_bc_flags: + fail("'compile_via_bc' requires a toolchain with 'output_bc_flags' set") # Dependencies - depinfo = _setup_deps(ctx, ctx.attr.deps, ctx.label.name, d_lib.dirname) + deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) + depinfo = _setup_deps(ctx, ctx.attr.deps, ctx.attr.implementation_deps, ctx.label.name) + + public_srcs = ctx.files.hdrs + ctx.files.exports + if not public_srcs: + public_srcs = ctx.files.srcs + + if not ctx.files.srcs: + return [ + DefaultInfo( + files = depset(), + ), + DInfo( + d_srcs = ctx.files.srcs, + d_exports = public_srcs, + transitive_d_srcs = depinfo.transitive_d_srcs, + data = ctx.files.data, + transitive_data = depset(depinfo.data, transitive = [depinfo.transitive_data]), + transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), + transitive_libs_bc = depset(transitive = [depinfo.libs_bc, depinfo.transitive_libs_bc]), + transitive_libs_non_bc = depset(transitive = [depinfo.libs_non_bc, depinfo.transitive_libs_non_bc]), + link_flags = depinfo.link_flags, + linkopts = ctx.attr.linkopts, + versions = depinfo.versions, + imports = depinfo.imports, + string_imports = depinfo.string_imports, + d_lib = "", # TODO: we only need it to distinguish from d_source_library. Either drop d_source_library or make another provider for it. + is_generated = ctx.attr.is_generated, + generated_srcs = depinfo.generated_srcs, + ), + ] + + #d_lib = ctx.actions.declare_file((ctx.label.name + ".lib") if _is_windows(ctx) else ("lib" + ctx.label.name + ".a")) + d_lib = ctx.actions.declare_file(ctx.label.name + ".o") + d_lib_bc = None + if ctx.attr.compile_via_bc: + d_lib_bc = ctx.actions.declare_file(ctx.label.name + ".bc.o") # Build compile command. compile_args = _build_compile_arglist( ctx = ctx, - out = d_lib, + out = d_lib if not d_lib_bc else d_lib_bc, depinfo = depinfo, - extra_flags = ["-lib"], + extra_flags = ["-c"] + extra_flags, ) # Convert sources to args @@ -215,115 +417,218 @@ def _d_library_impl(ctx): # args will auto-expand this to the contained files args = ctx.actions.args() args.add_all(compile_args) - args.add_all(ctx.files.srcs) + mapped_srcs, generated_srcs_wrapper = _handle_generated_srcs(ctx, depinfo.generated_srcs, d_compiler, toolchain.debug_repo_root_override) + + args.add_all(mapped_srcs) + + phobos_files = toolchain.libphobos.files if toolchain.libphobos != None else depset() + phobos_src_files = toolchain.libphobos_src.files if toolchain.libphobos_src != None else depset() + druntime_src_files = toolchain.druntime_src.files if toolchain.druntime_src != None else depset() + # TODO: Should they be in transitive? compile_inputs = depset( ctx.files.srcs + - depinfo.d_srcs + - ctx.files._d_stdlib + - ctx.files._d_stdlib_src + - ctx.files._d_runtime_import_src, + ctx.files.hdrs + + ctx.files.exports + + ctx.files.data + + depinfo.data + + depinfo.impl_srcs, transitive = [ depinfo.transitive_d_srcs, - depinfo.libs, - depinfo.transitive_libs, + depinfo.transitive_data, + phobos_files, + phobos_src_files, + druntime_src_files, ], ) + executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler ctx.actions.run( inputs = compile_inputs, - tools = [ctx.file._d_compiler], - outputs = [d_lib], + tools = _with_runfiles(toolchain.d_compiler) + ([generated_srcs_wrapper] if generated_srcs_wrapper else []), + outputs = [d_lib] if not d_lib_bc else [d_lib_bc], mnemonic = "Dcompile", - executable = ctx.file._d_compiler.path, + executable = executable, arguments = [args], use_default_shell_env = True, progress_message = "Compiling D library " + ctx.label.name, ) - return struct( - files = depset([d_lib]), - d_srcs = ctx.files.srcs, - transitive_d_srcs = depset(depinfo.d_srcs), - transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), - link_flags = depinfo.link_flags, - versions = ctx.attr.versions, - imports = ctx.attr.imports, - d_lib = d_lib, - ) + if d_lib_bc: + # need to compile .bc.o -> .o in an extra step + codegen_flags = toolchain.codegen_common_flags + toolchain.codegen_per_mode_flags[ctx.var["COMPILATION_MODE"]] + # this is a hack, just hoping there is some llc is not good + # TODO: enforce this is only used with toolchain.llc_compiler + # This also _could_ be clang, but aligning LDC backend options with + # clang ones is non-trivial, whereas llc has exactly the same options + # as ldc does. + llc = toolchain.llc_compiler.files.to_list()[0] if toolchain.llc_compiler else "llc" + ctx.actions.run( + inputs = [d_lib_bc], + tools = _with_runfiles(toolchain.llc_compiler) if toolchain.llc_compiler else [], + outputs = [d_lib], + executable = llc, + arguments = codegen_flags + ["--filetype=obj", "-o", d_lib.path, d_lib_bc.path], + use_default_shell_env = True, + progress_message = "Compiling bitcode for D library " + ctx.label.name, + ) + return [ + DefaultInfo( + files = depset([d_lib]), + ), + DInfo( + d_srcs = ctx.files.srcs, + d_exports = public_srcs, + transitive_d_srcs = depinfo.transitive_d_srcs, + data = ctx.files.data, + transitive_data = depset(depinfo.data, transitive = [depinfo.transitive_data]), + transitive_libs = depset(transitive = [depinfo.libs, depinfo.transitive_libs]), + transitive_libs_bc = depset(transitive = [depinfo.libs_bc, depinfo.transitive_libs_bc]), + transitive_libs_non_bc = depset(transitive = [depinfo.libs_non_bc, depinfo.transitive_libs_non_bc]), + link_flags = depinfo.link_flags, + linkopts = ctx.attr.linkopts, + versions = depinfo.versions, + imports = depinfo.imports, + string_imports = depinfo.string_imports, + d_lib = d_lib, + d_lib_bc = d_lib_bc, + is_generated = ctx.attr.is_generated, + generated_srcs = depinfo.generated_srcs, + ), + ] def _d_binary_impl_common(ctx, extra_flags = []): """Common implementation for rules that build a D binary.""" + toolchain = ctx.toolchains[D_TOOLCHAIN] d_bin = ctx.actions.declare_file(ctx.label.name + ".exe" if _is_windows(ctx) else ctx.label.name) - d_obj = ctx.actions.declare_file(ctx.label.name + (".obj" if _is_windows(ctx) else ".o")) - depinfo = _setup_deps(ctx, ctx.attr.deps, ctx.label.name, d_bin.dirname) - - # Build compile command - compile_args = _build_compile_arglist( - ctx = ctx, - depinfo = depinfo, - out = d_obj, - extra_flags = ["-c"] + extra_flags, - ) - - # Convert sources to args - # This is done to support receiving a File that is a directory, as - # args will auto-expand this to the contained files - args = ctx.actions.args() - args.add_all(compile_args) - args.add_all(ctx.files.srcs) - - toolchain_files = ( - ctx.files._d_stdlib + - ctx.files._d_stdlib_src + - ctx.files._d_runtime_import_src - ) - - compile_inputs = depset( - ctx.files.srcs + depinfo.d_srcs + toolchain_files, - transitive = [depinfo.transitive_d_srcs], - ) - ctx.actions.run( - inputs = compile_inputs, - tools = [ctx.file._d_compiler], - outputs = [d_obj], - mnemonic = "Dcompile", - executable = ctx.file._d_compiler.path, - arguments = [args], - use_default_shell_env = True, - progress_message = "Compiling D binary " + ctx.label.name, - ) + d_compiler = toolchain.d_compiler.files.to_list()[0] + # Dependencies + deps = ctx.attr.deps + ([toolchain.libphobos] if toolchain.libphobos != None else []) + ([toolchain.druntime] if toolchain.druntime != None else []) + depinfo = _setup_deps(ctx, deps, [], ctx.label.name) + + d_obj = None + toolchain_files = [ + toolchain.libphobos.files if toolchain.libphobos != None else depset(), + toolchain.libphobos_src.files if toolchain.libphobos_src != None else depset(), + toolchain.druntime_src.files if toolchain.druntime_src != None else depset(), + ] + + d_obj_bc = None + if ctx.files.srcs: + if ctx.attr.compile_via_bc or ctx.attr.use_lto: + if not toolchain.output_bc_flags: + fail("'compile_via_bc' and 'use_lto' require a toolchain with 'output_bc_flags' set") + d_obj_bc = ctx.actions.declare_file(ctx.label.name + ".bc.o") + + d_obj = ctx.actions.declare_file(ctx.label.name + (".obj" if _is_windows(ctx) else ".o")) + # Build compile command + compile_args = _build_compile_arglist( + ctx = ctx, + depinfo = depinfo, + out = d_obj if not d_obj_bc else d_obj_bc, + extra_flags = ["-c"] + extra_flags, + ) + + # Convert sources to args + # This is done to support receiving a File that is a directory, as + # args will auto-expand this to the contained files + args = ctx.actions.args() + args.add_all(compile_args) + + mapped_srcs, generated_srcs_wrapper = _handle_generated_srcs(ctx, depinfo.generated_srcs, d_compiler, toolchain.debug_repo_root_override) + + args.add_all(mapped_srcs) + + compile_inputs = depset( + ctx.files.srcs + ctx.files.data + depinfo.data, + transitive = [depinfo.transitive_d_srcs, depinfo.transitive_data] + toolchain_files, + ) + ctx.actions.run( + inputs = compile_inputs, + tools = _with_runfiles(toolchain.d_compiler) + ([generated_srcs_wrapper] if generated_srcs_wrapper else []), + outputs = [d_obj] if not d_obj_bc else [d_obj_bc], + mnemonic = "Dcompile", + executable = generated_srcs_wrapper if generated_srcs_wrapper else d_compiler, + arguments = [args], + use_default_shell_env = True, + progress_message = "Compiling D binary " + ctx.label.name, + ) + + if d_obj_bc: + # TODO: this code is almost exactly the same as in d_library + # need to compile .bc.o -> .o in an extra step + codegen_flags = toolchain.codegen_common_flags + toolchain.codegen_per_mode_flags[ctx.var["COMPILATION_MODE"]] + # this is a hack, just hoping there is some llc is not good + # TODO: enforce this is only used with toolchain.llc_compiler + # This also _could_ be clang, but aligning LDC backend options with + # clang ones is non-trivial, whereas llc has exactly the same options + # as ldc does. + llc = toolchain.llc_compiler.files.to_list()[0] if toolchain.llc_compiler else "llc" + ctx.actions.run( + inputs = [d_obj_bc], + tools = _with_runfiles(toolchain.llc_compiler) if toolchain.llc_compiler else [], + outputs = [d_obj], + executable = llc, + arguments = codegen_flags + ["--filetype=obj", "-o", d_obj.path, d_obj_bc.path], + use_default_shell_env = True, + progress_message = "Compiling bitcode for D binary " + ctx.label.name, + ) + + obj = d_obj_bc if ctx.attr.use_lto else d_obj # Build link command link_args = _build_link_arglist( ctx = ctx, - objs = [d_obj.path], + objs = [obj] if obj else [], depinfo = depinfo, out = d_bin, + c_compiler = toolchain.c_compiler, + link_flags = toolchain.link_flags + ["-L%s" % linkopt for linkopt in ctx.attr.linkopts], + link_order = ctx.attr.link_order, ) + if ctx.attr.use_lto: + libs = [depinfo.libs_bc, depinfo.libs_non_bc, depinfo.transitive_libs_bc, depinfo.transitive_libs_non_bc] + else: + libs = [depinfo.libs, depinfo.transitive_libs] link_inputs = depset( - [d_obj] + toolchain_files, - transitive = [depinfo.libs, depinfo.transitive_libs], + ([obj] if obj else []) + ([ctx.files.dynamic_symbols[0]] if ctx.files.dynamic_symbols else []), + transitive = libs + toolchain_files, ) ctx.actions.run( inputs = link_inputs, - tools = [ctx.file._d_compiler], + tools = _with_runfiles(toolchain.d_compiler) + (_with_runfiles(toolchain.c_compiler) if toolchain.c_compiler else []), outputs = [d_bin], mnemonic = "Dlink", - executable = ctx.file._d_compiler.path, + executable = d_compiler, arguments = link_args, use_default_shell_env = True, - progress_message = "Linking D binary " + ctx.label.name, + progress_message = "Linking " + ("(with LTO) " if ctx.attr.use_lto else "") + "D binary " + ctx.label.name, ) - return struct( - d_srcs = ctx.files.srcs, - transitive_d_srcs = depset(depinfo.d_srcs), - imports = ctx.attr.imports, - executable = d_bin, - ) + return [ + DInfo( + d_srcs = ctx.files.srcs, + transitive_d_srcs = depinfo.transitive_d_srcs, + data = ctx.files.data, + transitive_data = depset(depinfo.data), + imports = ctx.attr.imports, + string_imports = ctx.attr.string_imports, + ), + DefaultInfo( + executable = d_bin, + ), + ] + +def _d_library_impl(ctx): + """Implementation of the d_library rule.""" + return _d_library_impl_common(ctx) + +def _d_test_library_impl(ctx): + """Implementation of the d_test_library rule.""" + # A test library is just a d_library with testonly=True + return _d_library_impl_common(ctx, extra_flags=["-unittest"]) def _d_binary_impl(ctx): """Implementation of the d_binary rule.""" @@ -358,19 +663,32 @@ def _get_libs_for_static_executable(dep): def _d_source_library_impl(ctx): """Implementation of the d_source_library rule.""" transitive_d_srcs = [] + transitive_data = [] transitive_libs = [] transitive_transitive_libs = [] + transitive_transitive_libs_bc = [] + transitive_transitive_libs_non_bc = [] transitive_imports = depset() + transitive_string_imports = depset() transitive_linkopts = depset() transitive_versions = depset() + generated_srcs = { + src.files.to_list()[0]: src.label.package + "/" + loc for src, loc in ctx.attr.generated_srcs.items()} for dep in ctx.attr.deps: - if hasattr(dep, "d_srcs"): + if DInfo in dep and hasattr(dep[DInfo], "d_srcs") and not hasattr(dep[DInfo], "d_lib"): # Dependency is another d_source_library target. - transitive_d_srcs.append(dep.d_srcs) - transitive_imports = depset(dep.imports, transitive = [transitive_imports]) - transitive_linkopts = depset(dep.linkopts, transitive = [transitive_linkopts]) - transitive_versions = depset(dep.versions, transitive = [transitive_versions]) - transitive_transitive_libs.append(dep.transitive_libs) + # TODO: Could we also support d_library here? + ddep = dep[DInfo] + transitive_d_srcs.append(depset(ddep.d_srcs, transitive = [ddep.transitive_d_srcs])) + transitive_data.append(depset(ddep.data)) + transitive_imports = depset(ddep.imports, transitive = [transitive_imports]) + transitive_string_imports = depset(ddep.string_imports, transitive = [transitive_string_imports]) + transitive_linkopts = depset(ddep.linkopts, transitive = [transitive_linkopts]) + transitive_versions = depset(transitive = [ddep.versions, transitive_versions]) + transitive_transitive_libs.append(ddep.transitive_libs) + transitive_transitive_libs_bc.append(ddep.transitive_libs_bc) + transitive_transitive_libs_non_bc.append(ddep.transitive_libs_non_bc) + generated_srcs = generated_srcs | ddep.generated_srcs elif CcInfo in dep: # Dependency is a cc_library target. @@ -381,14 +699,25 @@ def _d_source_library_impl(ctx): fail("d_source_library can only depend on other " + "d_source_library or cc_library targets.", "deps") - return struct( - d_srcs = ctx.files.srcs, - transitive_d_srcs = depset(transitive = transitive_d_srcs, order = "postorder"), - transitive_libs = depset(transitive_libs, transitive = transitive_transitive_libs), - imports = ctx.attr.imports + transitive_imports.to_list(), - linkopts = ctx.attr.linkopts + transitive_linkopts.to_list(), - versions = ctx.attr.versions + transitive_versions.to_list(), - ) + gen_dir = ctx.genfiles_dir.path if ctx.attr.is_generated else None + + return [ + DInfo( + d_srcs = ctx.files.srcs, + data = ctx.files.data, + transitive_d_srcs = depset(transitive = transitive_d_srcs, order = "postorder"), + transitive_data = depset(transitive = transitive_data, order = "postorder"), + transitive_libs = depset(transitive_libs, transitive = transitive_transitive_libs), + transitive_libs_bc = depset(transitive_libs, transitive = transitive_transitive_libs_bc), + transitive_libs_non_bc = depset(transitive_libs, transitive = transitive_transitive_libs_non_bc), + imports = [_build_import(ctx.label, im, gen_dir) for im in ctx.attr.imports] + transitive_imports.to_list(), + string_imports = [_build_import(ctx.label, im, gen_dir) for im in ctx.attr.string_imports] + transitive_string_imports.to_list(), + linkopts = ctx.attr.linkopts + transitive_linkopts.to_list(), + versions = depset(ctx.attr.versions, transitive = [transitive_versions]), + is_generated = ctx.attr.is_generated, + generated_srcs = generated_srcs, + ), + ] # TODO(dzc): Use ddox for generating HTML documentation. def _d_docs_impl(ctx): @@ -406,19 +735,21 @@ def _d_docs_impl(ctx): target = struct( name = ctx.attr.dep.label.name, - srcs = ctx.attr.dep.d_srcs, - transitive_srcs = ctx.attr.dep.transitive_d_srcs, - imports = ctx.attr.dep.imports, + srcs = ctx.attr.dep[DInfo].d_srcs, + transitive_srcs = ctx.attr.dep[DInfo].transitive_d_srcs, + imports = ctx.attr.dep[DInfo].imports, ) + toolchain = ctx.toolchains[D_TOOLCHAIN] + d_compiler = toolchain.d_compiler.files.to_list()[0] + # Build D docs command - toolchain = _d_toolchain(ctx) doc_cmd = ( [ "set -e;", "rm -rf %s; mkdir -p %s;" % (docs_dir, docs_dir), "rm -rf %s; mkdir -p %s;" % (objs_dir, objs_dir), - toolchain.d_compiler_path, + d_compiler.path, "-c", "-D", "-Dd%s" % docs_dir, @@ -426,7 +757,7 @@ def _d_docs_impl(ctx): "-I.", ] + ["-I%s" % _build_import(ctx.label, im) for im in target.imports] + - toolchain.import_flags + + # toolchain.import_flags + [src.path for src in target.srcs] + [ "&&", @@ -439,15 +770,16 @@ def _d_docs_impl(ctx): ] ) - toolchain_files = ( - ctx.files._d_stdlib + - ctx.files._d_stdlib_src + - ctx.files._d_runtime_import_src - ) - ddoc_inputs = depset(target.srcs + toolchain_files, transitive = [target.transitive_srcs]) + toolchain_files = [ + toolchain.libphobos.files if toolchain.libphobos != None else depset(), + toolchain.libphobos_src.files if toolchain.libphobos_src != None else depset(), + toolchain.druntime_src.files if toolchain.druntime_src != None else depset(), + ] + + ddoc_inputs = depset(target.srcs, transitive = [target.transitive_srcs] + toolchain_files) ctx.actions.run_shell( inputs = ddoc_inputs, - tools = [ctx.file._d_compiler], + tools = _with_runfiles(toolchain.d_compiler), outputs = [d_docs_zip], mnemonic = "Ddoc", command = " ".join(doc_cmd), @@ -455,53 +787,128 @@ def _d_docs_impl(ctx): progress_message = "Generating D docs for " + ctx.label.name, ) +def _d_header_generator_impl(ctx): + """Implementation of the d_header_generator rule.""" + toolchain = ctx.toolchains[D_TOOLCHAIN] + if not toolchain.hdrgen_flags: + fail("d_header_generator requires a toolchain with hdrgen_flags set.") + + d_compiler = toolchain.d_compiler.files.to_list()[0] + + infile = ctx.file.src + if not infile: + fail("d_header_generator requires a single source file.") + + if not infile.path.endswith(".d"): + fail("d_header_generator only supports .d files, got: %s" % infile.path) + + header = ctx.actions.declare_file(ctx.label.name + ".di") + + ctx.actions.run( + inputs = [ctx.file.src], + tools = _with_runfiles(toolchain.d_compiler), + outputs = [header], + mnemonic = "Dhdrgen", + executable = d_compiler, + arguments = toolchain.hdrgen_flags + [infile.path, "--Hf", header.path], + use_default_shell_env = True, + progress_message = "Generating D header for " + ctx.label.name, + ) + return [ + DefaultInfo( + files = depset([header]), + ), + DInfo( + d_exports = [header] + ), + ] + _d_common_attrs = { "srcs": attr.label_list(allow_files = D_FILETYPE), "imports": attr.string_list(), + "string_imports": attr.string_list(), + "data": attr.label_list(allow_files = True), "linkopts": attr.string_list(), "versions": attr.string_list(), + "include_workspace_root": attr.bool(default = True), + "is_generated": attr.bool(default = False), + "generated_srcs": attr.label_keyed_string_dict(allow_files = True), + "compile_via_bc": attr.bool(default = False), "deps": attr.label_list(), } -_d_compile_attrs = { - "_d_compiler": attr.label( - default = Label("//d:dmd"), - executable = True, - allow_single_file = True, - cfg = "exec", - ), - "_d_runtime_import_src": attr.label( - default = Label("//d:druntime-import-src"), - ), - "_d_stdlib": attr.label( - default = Label("//d:libphobos2"), - ), - "_d_stdlib_src": attr.label( - default = Label("//d:phobos-src"), - ), +_d_library_attrs = { + "hdrs": attr.label_list(allow_files = D_FILETYPE, allow_empty = True), + "exports": attr.label_list(allow_files = D_FILETYPE), + "implementation_deps": attr.label_list(), } +_d_binary_attrs = { + "dynamic_symbols" : attr.label(allow_files = True), + "link_order": attr.label_keyed_string_dict(), + "use_lto": attr.bool(default = False), +} + +# _d_compile_attrs = { +# "_d_compiler": attr.label( +# default = Label("//d:dmd"), +# executable = True, +# allow_single_file = True, +# cfg = "host", +# ), +# "_d_runtime_import_src": attr.label( +# default = Label("//d:druntime-import-src"), +# ), +# "_d_stdlib": attr.label( +# default = Label("//d:libphobos2"), +# ), +# "_d_stdlib_src": attr.label( +# default = Label("//d:phobos-src"), +# ), +# } + d_library = rule( _d_library_impl, - attrs = dict(_d_common_attrs.items() + _d_compile_attrs.items()), + attrs = dict(_d_common_attrs.items() + _d_library_attrs.items()), + toolchains = [D_TOOLCHAIN], +) + +d_test_library = rule( + _d_test_library_impl, + attrs = dict(_d_common_attrs.items() + _d_library_attrs.items()), + toolchains = [D_TOOLCHAIN], +) + +d_header_generator = rule( + _d_header_generator_impl, + attrs = { + "src": attr.label( + mandatory = True, + allow_single_file = [".d"], + ), + }, + toolchains = [D_TOOLCHAIN], ) d_source_library = rule( _d_source_library_impl, attrs = _d_common_attrs, + toolchains = [D_TOOLCHAIN], ) d_binary = rule( _d_binary_impl, - attrs = dict(_d_common_attrs.items() + _d_compile_attrs.items()), + attrs = dict(_d_common_attrs.items() + _d_binary_attrs.items()), executable = True, + toolchains = [D_TOOLCHAIN], ) d_test = rule( _d_test_impl, - attrs = dict(_d_common_attrs.items() + _d_compile_attrs.items()), + attrs = dict(_d_common_attrs.items() + _d_binary_attrs.items()), executable = True, test = True, + toolchains = [D_TOOLCHAIN], ) _d_docs_attrs = { @@ -510,89 +917,132 @@ _d_docs_attrs = { d_docs = rule( _d_docs_impl, - attrs = dict(_d_docs_attrs.items() + _d_compile_attrs.items()), + attrs = dict(_d_docs_attrs.items()), outputs = { "d_docs": "%{name}-docs.zip", }, + toolchains = [D_TOOLCHAIN], ) -DMD_BUILD_FILE = """ -package(default_visibility = ["//visibility:public"]) - -config_setting( - name = "darwin", - values = {"host_cpu": "darwin"}, -) - -config_setting( - name = "k8", - values = {"host_cpu": "k8"}, -) - -config_setting( - name = "x64_windows", - values = {"host_cpu": "x64_windows"}, -) - -filegroup( - name = "dmd", - srcs = select({ - ":darwin": ["dmd2/osx/bin/dmd"], - ":k8": ["dmd2/linux/bin64/dmd"], - ":x64_windows": ["dmd2/windows/bin64/dmd.exe"], - }), -) - -filegroup( - name = "libphobos2", - srcs = select({ - ":darwin": ["dmd2/osx/lib/libphobos2.a"], - ":k8": [ - "dmd2/linux/lib64/libphobos2.a", - "dmd2/linux/lib64/libphobos2.so", - ], - ":x64_windows": ["dmd2/windows/lib64/phobos64.lib"], - }), -) - -filegroup( - name = "phobos-src", - srcs = glob(["dmd2/src/phobos/**/*.*"]), -) - -filegroup( - name = "druntime-import-src", - srcs = glob([ - "dmd2/src/druntime/import/*.*", - "dmd2/src/druntime/import/**/*.*", - ]), -) -""" - -def d_repositories(): - http_archive( - name = "dmd_linux_x86_64", - urls = [ - "https://downloads.dlang.org/releases/2.x/2.101.2/dmd.2.101.2.linux.tar.xz", - ], - sha256 = "95d96731853805a8a026324240f8ea7bd871927f6a405d14268408685bbbdc5c", - build_file_content = DMD_BUILD_FILE, - ) - - http_archive( - name = "dmd_darwin_x86_64", - urls = [ - "https://downloads.dlang.org/releases/2.x/2.101.2/dmd.2.101.2.osx.tar.xz", - ], - sha256 = "45bbe0d0e500faee5c84aaa5b124553671f1cec06a711860647cfaa7016aeb56", - build_file_content = DMD_BUILD_FILE, - ) - - http_archive( - name = "dmd_windows_x86_64", - urls = [ - "https://downloads.dlang.org/releases/2.x/2.101.2/dmd.2.101.2.windows.zip", - ], - sha256 = "8065df7316e4d2d9e1f322998ec16b4b52c5c966dc3e7220159ba4029d5b97ba", - build_file_content = DMD_BUILD_FILE, - ) +def d_lib( + name, + srcs = [], + imports = [], + string_imports = [], + data = [], + linkopts = [], + versions = [], + hdrs = [], + exports = [], + exports_no_hdrs = [], + deps = [], + implementation_deps = [], + include_workspace_root = True, + is_generated = False, + generated_srcs = {}, + test = False, + exports_lib = None, + **kwargs, +): + """d_lib is a macro that can generate header files for a D library. + + It wraps the d_library rule and automatically generates header files + for the exported D source files. It takes mostly the same arguments + as d_library, plus an additional `exports_no_hdrs` argument that + specifies the exported D source files that should be exported without + generating headers for them (this might be useful if they contain + non-templated functions that need to be called during CTFE). + Args: + name: The name of the target. + srcs: List of D source files to compile. + imports: List of import paths to include in the compilation. + string_imports: List of string import paths to include in the compilation. + data: List of extra files to include in the compilation. + linkopts: List of linker options to pass to the linker. + versions: List of D versions to define during compilation. + hdrs: List of header files to include in the library. + exports: List of D source files to export, which will have headers generated for them. + exports_no_hdrs: List of D source files to export without generating headers. + deps: List of dependencies for this library. + implementation_deps: List of implementation dependencies for this library. + include_workspace_root: Whether to include the workspace root in import paths. + is_generated: Whether this library is generated (used for generated sources). + generated_srcs: A dictionary mapping generated source files to their desired locations. + test: Whether this library is a test library (compiled with -unittest flag). + exports_lib: Optional label of a d_library target that contains the exported files. + If provided, will create an extra `d_source_library` with headers+exports. + This could be used to break a circular dependency. + **kwargs: Additional attributes for the d_library rule. + """ + exports_hdrs = [] + new_generated_srcs = {} + new_generated_srcs |= generated_srcs + for exp in exports: + if not exp.endswith(".d"): + fail("Exported files must be D source files, got: %s" % exp) + hdr = name + ".hdrgen/" + exp + "_hdrgen" + d_header_generator( + name = hdr, + src = exp, + ) + if exp in generated_srcs: + # If the file is already in generated_srcs, let's put di file next to the target d file. + target = generated_srcs[exp] + else: + target = exp + exports_hdrs.append(hdr) + di_name = target[:-2] + ".di" # Replace .d with .di + new_generated_srcs[hdr] = di_name + + if not test: + d_library( + name = name, + srcs = srcs, + imports = imports, + string_imports = string_imports, + data = data, + linkopts = linkopts, + versions = versions, + hdrs = hdrs + exports_hdrs, + exports = exports_no_hdrs, + deps = deps, + implementation_deps = implementation_deps, + include_workspace_root = include_workspace_root, + is_generated = is_generated, + generated_srcs = new_generated_srcs, + **kwargs, + ) + else: + d_test_library( + name = name, + srcs = srcs, + imports = imports, + string_imports = string_imports, + data = data, + linkopts = linkopts, + versions = versions, + hdrs = hdrs + exports_hdrs, + exports = exports_no_hdrs, + deps = deps, + implementation_deps = implementation_deps, + include_workspace_root = include_workspace_root, + is_generated = is_generated, + generated_srcs = new_generated_srcs, + **kwargs, + ) + + if exports_lib: + # Create a d_source_library with the exported files. + d_library( + name = exports_lib, + hdrs = hdrs + exports_hdrs + exports_no_hdrs, + imports = imports, + string_imports = string_imports, + data = data, + linkopts = linkopts, + versions = versions, + include_workspace_root = include_workspace_root, + is_generated = is_generated, + generated_srcs = new_generated_srcs, + **kwargs, + ) diff --git a/d/extensions.bzl b/d/extensions.bzl new file mode 100644 index 0000000..fdde34e --- /dev/null +++ b/d/extensions.bzl @@ -0,0 +1,6 @@ +load("//d:repositories.bzl", "rules_d_toolchains") + +def _non_module_dependencies_impl(_ctx): + rules_d_toolchains() + +non_module_dependencies = module_extension(implementation = _non_module_dependencies_impl) diff --git a/d/platforms/BUILD b/d/platforms/BUILD new file mode 100644 index 0000000..51ee5d6 --- /dev/null +++ b/d/platforms/BUILD @@ -0,0 +1,25 @@ +package(default_visibility = ["//visibility:public"]) + +platform( + name = "dmd", + parents = ["@local_config_platform//:host"], + constraint_values = [ + "//d/constraints/compiler:dmd", + ], +) + +platform( + name = "ldc", + parents = ["@local_config_platform//:host"], + constraint_values = [ + "//d/constraints/compiler:ldc", + ], +) + +platform( + name = "weka-ldc", + parents = ["@local_config_platform//:host"], + constraint_values = [ + "//d/constraints/compiler:weka-ldc", + ], +) \ No newline at end of file diff --git a/d/repositories.bzl b/d/repositories.bzl new file mode 100644 index 0000000..c123a35 --- /dev/null +++ b/d/repositories.bzl @@ -0,0 +1,111 @@ +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_skylib//lib:versions.bzl", "versions") + +DMD_BUILD_FILE = "//d:DMD.bzl" +LDC_BUILD_FILE = "//d:LDC.bzl" +DMD_STRIP_PREFIX = "dmd2" + +def fetch_dmd(version = None): + if version == None: + http_archive( + name = "dmd_linux_x86_64", + urls = [ + "https://downloads.dlang.org/releases/2.x/2.102.1/dmd.2.102.1.linux.tar.xz", + ], + sha256 = "f3f62fd7357d9c0c0349c7b96721d6734fe8285c0f32a37649d378c8abb0e9eb", + strip_prefix = DMD_STRIP_PREFIX, + build_file = DMD_BUILD_FILE, + ) + + http_archive( + name = "dmd_darwin_x86_64", + urls = [ + "https://downloads.dlang.org/releases/2.x/2.102.1/dmd.2.102.1.osx.tar.xz", + ], + sha256 = "300d309a2b71e95404f58e14a23daf342f47cc8608476a0b6414d356485df2bc", + strip_prefix = DMD_STRIP_PREFIX, + build_file = DMD_BUILD_FILE, + ) + + # http_archive( + # name = "dmd_windows_x86_64", + # urls = [ + # "https://downloads.dlang.org/releases/2.x/2.102.1/dmd.2.102.1.windows.zip", + # ], + # sha256 = "a263ffbf6232288fa093c71a43a5cc1cd09ef5a75e7eca385ece16606c245090", + # strip_prefix = DMD_STRIP_PREFIX, + # build_file = DMD_BUILD_FILE, + # ) + + elif versions.is_at_least("2.0.0", version): + http_archive( + name = "dmd_linux_x86_64", + urls = [ + "https://downloads.dlang.org/releases/2.x/{version}/dmd.{version}.linux.tar.xz".format(version = version), + ], + strip_prefix = DMD_STRIP_PREFIX, + build_file = DMD_BUILD_FILE, + ) + + http_archive( + name = "dmd_darwin_x86_64", + urls = [ + "https://downloads.dlang.org/releases/2.x/{version}/dmd.{version}.osx.tar.xz".format(version = version), + ], + strip_prefix = DMD_STRIP_PREFIX, + build_file = DMD_BUILD_FILE, + ) + + http_archive( + name = "dmd_windows_x86_64", + urls = [ + "https://downloads.dlang.org/releases/2.x/{version}/dmd.{version}.windows.zip".format(version = version), + ], + strip_prefix = DMD_STRIP_PREFIX, + build_file = DMD_BUILD_FILE, + ) + + else: + fail("Sorry, only DMD 2 is supported, but got %s. Maybe consider switching to D2?" % version) + +def fetch_ldc(version = None): + http_archive( + name = "ldc_linux_x86_64", + urls = [ + "https://github.com/ldc-developers/ldc/releases/download/v1.31.0/ldc2-1.31.0-linux-x86_64.tar.xz", + ], + sha256 = "7dbd44786c0772ec41890a8c03e22b0985d6ef547c40943dd56bc6be21cf4d98", + strip_prefix = "ldc2-1.31.0-linux-x86_64", + build_file = LDC_BUILD_FILE, + ) + +def fetch_weka_ldc(version = "1.30.0-weka20"): + http_archive( + name = "weka_ldc_linux_x86_64", + urls = [ + "https://github.com/weka/ldc/releases/download/v{version}/ldc2-{version}-linux-x86_64.tar.xz".format(version = version), + ], + sha256 = "0a6001fb4975361724b1975eb49cde70ef53546f78b281a69446121072342f7a", + strip_prefix = "ldc2-{version}-linux-x86_64".format(version = version), + build_file = LDC_BUILD_FILE, + ) + +def rules_d_toolchains(ctype = "dmd", version = None): + if ctype == "dmd": + fetch_dmd(version = version) + fetch_ldc() + fetch_weka_ldc() + + elif ctype == "ldc": + fetch_dmd() + fetch_ldc(version = version) + fetch_weka_ldc() + + elif ctype == "weka-ldc": + # Special case for Weka LDC, which is a fork of LDC + fetch_weka_ldc(version = version) + fetch_dmd() + fetch_ldc() + + else: + fail("Only \"dmd\", \"ldc\" and \"weka-ldc\" compilers are supported at this moment.") diff --git a/d/toolchain.bzl b/d/toolchain.bzl new file mode 100644 index 0000000..67143cf --- /dev/null +++ b/d/toolchain.bzl @@ -0,0 +1,139 @@ +load("@bazel_skylib//rules:common_settings.bzl", "string_setting") +load("//d:config.bzl", "DToolchainConfigInfo") + +D_TOOLCHAIN = "//d:toolchain_type" + +# string_setting( +# name = "compiler_type", +# values = [ +# "dmd", +# "ldc", +# ], +# ) +# +# config_setting( +# name = "dmd", +# flag_values = { +# ":compiler_type": "dmd", +# }, +# ) +# +# config_setting( +# name = "ldc", +# flag_values = { +# ":compiler_type": "ldc", +# }, +# ) + +def _d_toolchain_impl(ctx): + config = ctx.attr.config[DToolchainConfigInfo] if ctx.attr.config else None + codegen_opts_per_mode = { + "fastbuild": ctx.attr.codegen_fastbuild_flags, + "dbg": ctx.attr.codegen_dbg_flags, + "opt": ctx.attr.codegen_opt_flags, + } + if config == None: + # TODO: deprecate this + toolchain_info = platform_common.ToolchainInfo( + name = ctx.label.name, + d_compiler = ctx.attr.d_compiler, + c_compiler = ctx.attr.c_compiler, + llc_compiler = ctx.attr.llc_compiler, + lib_flags = ctx.attr.lib_flags, + link_flags = ctx.attr.link_flags, + import_flags = ctx.attr.import_flags, + libphobos = ctx.attr.libphobos, + libphobos_src = ctx.attr.libphobos_src, + druntime = ctx.attr.druntime, + druntime_src = ctx.attr.druntime_src, + version_flag = ctx.attr.version_flag, + common_flags = ctx.attr.common_flags, + fastbuild_flags = ctx.attr.fastbuild_flags, + dbg_flags = ctx.attr.dbg_flags, + opt_flags = ctx.attr.opt_flags, + codegen_common_flags = ctx.attr.codegen_common_flags, + codegen_per_mode_flags = codegen_opts_per_mode, + hdrgen_flags = ctx.attr.hdrgen_flags, + output_bc_flags = ctx.attr.output_bc_flags, + global_versions_common = [], + global_versions_per_mode = { + "fastbuild": [], + "dbg": [], + "opt": [], + }, + debug_repo_root_override = ctx.attr.debug_repo_root_override, + ) + else: + toolchain_info = platform_common.ToolchainInfo( + name = ctx.attr.name, + d_compiler = config.d_compiler or ctx.attr.d_compiler, + c_compiler = config.c_compiler or ctx.attr.c_compiler, + llc_compiler = config.llc_compiler or ctx.attr.llc_compiler, + lib_flags = config.lib_flags or ctx.attr.lib_flags, + link_flags = (config.linkopts_common + config.linkopts_per_mode[ctx.var["COMPILATION_MODE"]]) or ctx.attr.link_flags, + import_flags = config.import_flags or ctx.attr.import_flags, + libphobos = config.libphobos or ctx.attr.libphobos, + libphobos_src = config.libphobos_src or ctx.attr.libphobos_src, + druntime = config.druntime or ctx.attr.druntime, + druntime_src = config.druntime_src or ctx.attr.druntime_src, + version_flag = config.version_flag or ctx.attr.version_flag, + common_flags = config.copts_common or ctx.attr.common_flags, + fastbuild_flags = config.copts_per_mode["fastbuild"] or ctx.attr.fastbuild_flags, + dbg_flags = config.copts_per_mode["dbg"] or ctx.attr.dbg_flags, + opt_flags = config.copts_per_mode["opt"] or ctx.attr.opt_flags, + codegen_common_flags = config.codegen_opts_common or ctx.attr.codegen_common_flags, + codegen_per_mode_flags = config.codegen_opts_per_mode or codegen_opts_per_mode, + hdrgen_flags = config.hdrgen_flags, + output_bc_flags = config.output_bc_flags, + global_versions_common = config.global_versions_common, + global_versions_per_mode = config.global_versions_per_mode, + debug_repo_root_override = config.debug_repo_root_override, + ) + return [toolchain_info] + +d_toolchain = rule( + _d_toolchain_impl, + attrs = { + "d_compiler": attr.label( + executable = True, + # allow_files = True, + cfg = "exec", + ), + "c_compiler": attr.label( + executable = True, + allow_files = True, + cfg = "exec", + ), + "llc_compiler": attr.label( + executable = True, + allow_files = True, + cfg = "exec", + ), + "lib_flags": attr.string_list( + default = ["-lib"], + ), + "link_flags": attr.string_list( + default = [], + ), + "import_flags": attr.string_list(), + "libphobos": attr.label(), + "libphobos_src": attr.label(), + "druntime": attr.label(), + "druntime_src": attr.label(), + "version_flag": attr.string(), + "common_flags": attr.string_list(), + "fastbuild_flags": attr.string_list(), + "dbg_flags": attr.string_list(), + "opt_flags": attr.string_list(), + "codegen_common_flags": attr.string_list(default = []), + "codegen_fastbuild_flags": attr.string_list(), + "codegen_dbg_flags": attr.string_list(), + "codegen_opt_flags": attr.string_list(), + "hdrgen_flags": attr.string_list(), + "output_bc_flags": attr.string_list(), + "debug_repo_root_override": attr.string(), + "config": attr.label( + providers = [DToolchainConfigInfo], + ), + }, +) diff --git a/examples/dynamic_symbols/BUILD b/examples/dynamic_symbols/BUILD new file mode 100644 index 0000000..659241e --- /dev/null +++ b/examples/dynamic_symbols/BUILD @@ -0,0 +1,13 @@ +package(default_visibility = ["//visibility:public"]) + +load("//d:d.bzl", "d_binary") + +d_binary( + name = "dynamic_symbols", + srcs = ["dynamic_symbols.d"], + dynamic_symbols = ":dynamic_symbols.txt", + deps = [ + "//examples/hello_lib:greeter", + "//examples/hello_lib:native_greeter", + ], +) diff --git a/examples/dynamic_symbols/dynamic_symbols.d b/examples/dynamic_symbols/dynamic_symbols.d new file mode 100644 index 0000000..1bd0235 --- /dev/null +++ b/examples/dynamic_symbols/dynamic_symbols.d @@ -0,0 +1,26 @@ +// Copyright 2015 The Bazel Authors. 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.hello_lib.greeter; +import examples.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/examples/dynamic_symbols/dynamic_symbols.txt b/examples/dynamic_symbols/dynamic_symbols.txt new file mode 100644 index 0000000..53f38aa --- /dev/null +++ b/examples/dynamic_symbols/dynamic_symbols.txt @@ -0,0 +1,4 @@ +{ +a; +b; +}; diff --git a/examples/string_imports/BUILD b/examples/string_imports/BUILD new file mode 100644 index 0000000..f876803 --- /dev/null +++ b/examples/string_imports/BUILD @@ -0,0 +1,16 @@ +load("//d:d.bzl", "d_binary", "d_library") + +d_library( + name = "lib", + srcs = ["lib.d"], + data = ["imports/test.txt"], + string_imports = ["imports"], +) + +d_binary( + name = "main", + srcs = ["main.d"], + deps = [ + ":lib", + ] +) \ No newline at end of file diff --git a/examples/string_imports/imports/test.txt b/examples/string_imports/imports/test.txt new file mode 100644 index 0000000..f2ba8f8 --- /dev/null +++ b/examples/string_imports/imports/test.txt @@ -0,0 +1 @@ +abc \ No newline at end of file diff --git a/examples/string_imports/lib.d b/examples/string_imports/lib.d new file mode 100644 index 0000000..4bd7df0 --- /dev/null +++ b/examples/string_imports/lib.d @@ -0,0 +1,8 @@ + +string testTemplate()() { + return import("test.txt"); +} + +string test() { + return import("test.txt"); +} \ No newline at end of file diff --git a/examples/string_imports/main.d b/examples/string_imports/main.d new file mode 100644 index 0000000..544abaf --- /dev/null +++ b/examples/string_imports/main.d @@ -0,0 +1,8 @@ +import examples.string_imports.lib; + +import std.stdio; + +void main() { + writeln(test); + writeln(testTemplate); +} \ No newline at end of file diff --git a/tests/c_library_usage/BUILD b/tests/c_library_usage/BUILD index caf85f0..06c0cc7 100644 --- a/tests/c_library_usage/BUILD +++ b/tests/c_library_usage/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") +load("@rules_d//d:d.bzl", "d_test") d_test( name = "c_library_usage", diff --git a/tests/c_library_usage_no_wrapper/BUILD b/tests/c_library_usage_no_wrapper/BUILD index 8e152f9..8552a7a 100644 --- a/tests/c_library_usage_no_wrapper/BUILD +++ b/tests/c_library_usage_no_wrapper/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") +load("@rules_d//d:d.bzl", "d_test") d_test( name = "c_library_usage_no_wrapper", diff --git a/tests/circular_deps/BUILD b/tests/circular_deps/BUILD new file mode 100644 index 0000000..06699e7 --- /dev/null +++ b/tests/circular_deps/BUILD @@ -0,0 +1,51 @@ + +load("//d:d.bzl", "d_lib", "d_test") + +d_lib( + name = "lib_a", + srcs = ["lib_a.d"], + exports = ["lib_a.d"], + exports_lib = "lib_a_exports", + deps = [ + ":lib_b", + ], +) + +d_lib( + name = "lib_b", + srcs = ["lib_b.d"], + exports = ["lib_b.d"], + deps = [ + ":lib_a_exports", + ], +) + +d_test( + name = "circular_deps_test", + srcs = ["circular_deps_test.d"], + link_order = { + ":lib_a": "-1", # lib_a must be linked last + }, + args = [ + "--DRT-oncycle=ignore", + ], + deps = [ + ":lib_a", + ":lib_b", + ], +) + +d_test( + name = "circular_deps_test2", + srcs = ["circular_deps_test.d"], + link_order = { + ":lib_a": "-1", # lib_a must be linked last + }, + args = [ + "--DRT-oncycle=ignore", + ], + deps = [ + ":lib_b", + ":lib_a", + ], +) \ No newline at end of file diff --git a/tests/circular_deps/circular_deps_test.d b/tests/circular_deps/circular_deps_test.d new file mode 100644 index 0000000..d65b9b5 --- /dev/null +++ b/tests/circular_deps/circular_deps_test.d @@ -0,0 +1,14 @@ +module tests.circular_deps.circular_deps_test; + +void main() {} + +unittest +{ + import tests.circular_deps.lib_a; + import tests.circular_deps.lib_b; + + assert(f(1) == 4); + assert(g(1) == 3); + assert(h(1) == 2); + assert(globalVar == 10); +} diff --git a/tests/circular_deps/lib_a.d b/tests/circular_deps/lib_a.d new file mode 100644 index 0000000..fe8b554 --- /dev/null +++ b/tests/circular_deps/lib_a.d @@ -0,0 +1,19 @@ +module tests.circular_deps.lib_a; + +import tests.circular_deps.lib_b; + +__gshared int globalVar = 2; + +int f(int x) { + return x + g(x); +} + +int h(int x) { + return x + 1; +} + +shared static this() { + import std.stdio; + globalVar += 3; + writeln("lib_a initialized"); +} diff --git a/tests/circular_deps/lib_b.d b/tests/circular_deps/lib_b.d new file mode 100644 index 0000000..f51df99 --- /dev/null +++ b/tests/circular_deps/lib_b.d @@ -0,0 +1,13 @@ +module tests.circular_deps.lib_b; + +import tests.circular_deps.lib_a; + +int g(int x) { + return x + h(x); +} + +shared static this() { + import std.stdio; + globalVar *= 2; + writeln("lib_b initialized"); +} diff --git a/tests/circular_deps_with_gensrcs/BUILD b/tests/circular_deps_with_gensrcs/BUILD new file mode 100644 index 0000000..0d17abe --- /dev/null +++ b/tests/circular_deps_with_gensrcs/BUILD @@ -0,0 +1,61 @@ + +load("//d:d.bzl", "d_lib", "d_test") + +genrule( + name = "lib_a_preprocess", + srcs = ["lib_a.d"], + outs = ["lib_a_preprocessed.d"], + cmd = "cp $< $@", +) + +d_lib( + name = "lib_a", + srcs = ["lib_a_preprocessed.d"], + exports = ["lib_a_preprocessed.d"], + exports_lib = "lib_a_exports", + generated_srcs = { + "lib_a_preprocessed.d": "lib_a.d", + }, + deps = [ + ":lib_b", + ], +) + +d_lib( + name = "lib_b", + srcs = ["lib_b.d"], + exports = ["lib_b.d"], + deps = [ + ":lib_a_exports", + ], +) + +d_test( + name = "circular_deps_test", + srcs = ["circular_deps_test.d"], + link_order = { + ":lib_a": "-1", # lib_a must be linked last + }, + args = [ + "--DRT-oncycle=ignore", + ], + deps = [ + ":lib_a", + ":lib_b", + ], +) + +d_test( + name = "circular_deps_test2", + srcs = ["circular_deps_test.d"], + link_order = { + ":lib_a": "-1", # lib_a must be linked last + }, + args = [ + "--DRT-oncycle=ignore", + ], + deps = [ + ":lib_b", + ":lib_a", + ], +) \ No newline at end of file diff --git a/tests/circular_deps_with_gensrcs/circular_deps_test.d b/tests/circular_deps_with_gensrcs/circular_deps_test.d new file mode 100644 index 0000000..f05e47a --- /dev/null +++ b/tests/circular_deps_with_gensrcs/circular_deps_test.d @@ -0,0 +1,14 @@ +module tests.circular_deps_with_gensrcs.circular_deps_test; + +void main() {} + +unittest +{ + import tests.circular_deps_with_gensrcs.lib_a; + import tests.circular_deps_with_gensrcs.lib_b; + + assert(f(1) == 4); + assert(g(1) == 3); + assert(h(1) == 2); + assert(globalVar == 10); +} diff --git a/tests/circular_deps_with_gensrcs/lib_a.d b/tests/circular_deps_with_gensrcs/lib_a.d new file mode 100644 index 0000000..c5b8a38 --- /dev/null +++ b/tests/circular_deps_with_gensrcs/lib_a.d @@ -0,0 +1,19 @@ +module tests.circular_deps_with_gensrcs.lib_a; + +import tests.circular_deps_with_gensrcs.lib_b; + +__gshared int globalVar = 2; + +int f(int x) { + return x + g(x); +} + +int h(int x) { + return x + 1; +} + +shared static this() { + import std.stdio; + globalVar += 3; + writeln("lib_a initialized"); +} diff --git a/tests/circular_deps_with_gensrcs/lib_b.d b/tests/circular_deps_with_gensrcs/lib_b.d new file mode 100644 index 0000000..8074e69 --- /dev/null +++ b/tests/circular_deps_with_gensrcs/lib_b.d @@ -0,0 +1,13 @@ +module tests.circular_deps_with_gensrcs.lib_b; + +import tests.circular_deps_with_gensrcs.lib_a; + +int g(int x) { + return x + h(x); +} + +shared static this() { + import std.stdio; + globalVar *= 2; + writeln("lib_b initialized"); +} diff --git a/tests/d_binary_no_source/BUILD b/tests/d_binary_no_source/BUILD new file mode 100644 index 0000000..27ac54c --- /dev/null +++ b/tests/d_binary_no_source/BUILD @@ -0,0 +1,20 @@ +load("//d:d.bzl", "d_library", "d_test_library", "d_test") + +d_test_library( + name = "testlib", + srcs = ["testlib.d"], +) + +d_library( + name = "main", + srcs = ["main.d"], +) + +d_test( + name = "test", + srcs = [], + deps = [ + ":main", + ":testlib", + ], +) \ No newline at end of file diff --git a/tests/d_binary_no_source/main.d b/tests/d_binary_no_source/main.d new file mode 100644 index 0000000..34f46e2 --- /dev/null +++ b/tests/d_binary_no_source/main.d @@ -0,0 +1,2 @@ +void main() { +} diff --git a/tests/d_binary_no_source/testlib.d b/tests/d_binary_no_source/testlib.d new file mode 100644 index 0000000..f1027fa --- /dev/null +++ b/tests/d_binary_no_source/testlib.d @@ -0,0 +1,13 @@ + +int f(int x) { + return x * 2; +} + +unittest +{ + assert(f(2) == 4); + assert(f(3) == 6); + assert(f(0) == 0); + assert(f(-1) == -2); + assert(f(-5) == -10); +} \ No newline at end of file diff --git a/tests/d_lib/BUILD b/tests/d_lib/BUILD new file mode 100644 index 0000000..7548ea3 --- /dev/null +++ b/tests/d_lib/BUILD @@ -0,0 +1,20 @@ +load("//d:d.bzl", "d_binary", "d_lib") + +d_lib( + name = "d_lib", + srcs = ["lib.d"], + exports = ["lib.d"], +) + +d_lib( + name = "d_lib2", + srcs = ["lib2.d"], + exports = ["lib2.d"], + deps = [":d_lib"], +) + +d_binary( + name = "main", + srcs = ["main.d"], + deps = [":d_lib2"], +) \ No newline at end of file diff --git a/tests/d_lib/lib.d b/tests/d_lib/lib.d new file mode 100644 index 0000000..d248f29 --- /dev/null +++ b/tests/d_lib/lib.d @@ -0,0 +1,6 @@ +module tests.d_lib.lib; + +int plusOne(int x) +{ + return x + 1; +} \ No newline at end of file diff --git a/tests/d_lib/lib2.d b/tests/d_lib/lib2.d new file mode 100644 index 0000000..3651497 --- /dev/null +++ b/tests/d_lib/lib2.d @@ -0,0 +1,8 @@ +module tests.d_lib.lib2; + +import tests.d_lib.lib; + +int plusOneTwice(int x) +{ + return plusOne(plusOne(x)); +} \ No newline at end of file diff --git a/tests/d_lib/main.d b/tests/d_lib/main.d new file mode 100644 index 0000000..1409cd5 --- /dev/null +++ b/tests/d_lib/main.d @@ -0,0 +1,11 @@ +module tests.d_lib.main; + +import tests.d_lib.lib2; + +void main() +{ + int x = 5; + int result = plusOneTwice(x); + import std.stdio; + writeln("The result of plusOne(", x, ") is: ", result); +} \ No newline at end of file diff --git a/tests/d_lib_headers/BUILD b/tests/d_lib_headers/BUILD new file mode 100644 index 0000000..3e1c74a --- /dev/null +++ b/tests/d_lib_headers/BUILD @@ -0,0 +1,6 @@ +load("//d:d.bzl", "d_header_generator") + +d_header_generator( + name = "d_lib_headers", + src = "lib.d", +) \ No newline at end of file diff --git a/tests/d_lib_headers/lib.d b/tests/d_lib_headers/lib.d new file mode 100644 index 0000000..6e95086 --- /dev/null +++ b/tests/d_lib_headers/lib.d @@ -0,0 +1,6 @@ +module tests.d_lib_headers.lib; + +int plusOne(int x) +{ + return x + 1; +} \ No newline at end of file diff --git a/tests/d_library_compile_via_bc/BUILD b/tests/d_library_compile_via_bc/BUILD new file mode 100644 index 0000000..5653250 --- /dev/null +++ b/tests/d_library_compile_via_bc/BUILD @@ -0,0 +1,9 @@ +package(default_visibility = ["//visibility:public"]) + +load("@rules_d//d:d.bzl", "d_library") + +d_library( + name = "simple_d_library", + compile_via_bc = True, + srcs = ["simple_library.d"], +) diff --git a/tests/d_library_compile_via_bc/simple_library.d b/tests/d_library_compile_via_bc/simple_library.d new file mode 100644 index 0000000..5b162ad --- /dev/null +++ b/tests/d_library_compile_via_bc/simple_library.d @@ -0,0 +1,6 @@ +module simple_library; + +int plusOne(uint x) +{ + return x + 1; +} diff --git a/tests/d_library_usage/BUILD b/tests/d_library_usage/BUILD index f668a20..a1a4d2f 100644 --- a/tests/d_library_usage/BUILD +++ b/tests/d_library_usage/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") +load("@rules_d//d:d.bzl", "d_test") d_test( name = "d_library_usage", diff --git a/tests/deps_only_library/BUILD b/tests/deps_only_library/BUILD new file mode 100644 index 0000000..1e6b97c --- /dev/null +++ b/tests/deps_only_library/BUILD @@ -0,0 +1,16 @@ +load("//d:d.bzl", "d_library", "d_test") + +d_library( + name = "deps_only_library", + srcs = [], + deps = [ + "//tests/header_only_library:header_only_library", + "//tests/simple_d_library:simple_d_library", + ], +) + +d_test( + name = "deps_only_library_test", + srcs = ["test.d"], + deps = [":deps_only_library"], +) \ No newline at end of file diff --git a/tests/deps_only_library/test.d b/tests/deps_only_library/test.d new file mode 100644 index 0000000..6cec4d0 --- /dev/null +++ b/tests/deps_only_library/test.d @@ -0,0 +1,15 @@ +module tests.deps_only_library.test; + +void main() { + import tests.header_only_library.lib; + + int result = add(2, 3); + + assert(result == 5); + + import tests.simple_d_library.simple_library; + + int result2 = plusOne(4); + + assert(result2 == 5); +} \ No newline at end of file diff --git a/tests/directory_srcs/BUILD b/tests/directory_srcs/BUILD index 9c440a5..8f3c810 100644 --- a/tests/directory_srcs/BUILD +++ b/tests/directory_srcs/BUILD @@ -1,5 +1,5 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") -load("@io_bazel_rules_d//tests/directory_srcs:directory_generator.bzl", "directory_generator") +load("@rules_d//d:d.bzl", "d_test") +load("@rules_d//tests/directory_srcs:directory_generator.bzl", "directory_generator") # Provides a single declared directory File as its output in Default Info, # containing a copy of all srcs. This is similar to capturing the output of the diff --git a/tests/fiber_thread_usage/BUILD b/tests/fiber_thread_usage/BUILD index 6836ce4..3380ce2 100644 --- a/tests/fiber_thread_usage/BUILD +++ b/tests/fiber_thread_usage/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") +load("@rules_d//d:d.bzl", "d_test") d_test( name = "fiber_thread_usage", diff --git a/tests/header_only_library/BUILD b/tests/header_only_library/BUILD new file mode 100644 index 0000000..d84eae3 --- /dev/null +++ b/tests/header_only_library/BUILD @@ -0,0 +1,17 @@ +load("//d:d.bzl", "d_library", "d_test") + +package( + default_visibility = ["//visibility:public"], +) + +d_library( + name = "header_only_library", + srcs = [], + hdrs = ["lib.di"], +) + +d_test( + name = "header_only_library_test", + srcs = ["header_only_library_test.d"], + deps = [":header_only_library"], +) \ No newline at end of file diff --git a/tests/header_only_library/header_only_library_test.d b/tests/header_only_library/header_only_library_test.d new file mode 100644 index 0000000..d4ec9aa --- /dev/null +++ b/tests/header_only_library/header_only_library_test.d @@ -0,0 +1,9 @@ +module tests.header_only_library.header_only_library_test; + +void main() { + import tests.header_only_library.lib; + + int result = add(2, 3); + + assert(result == 5); +} \ No newline at end of file diff --git a/tests/header_only_library/lib.di b/tests/header_only_library/lib.di new file mode 100644 index 0000000..c763937 --- /dev/null +++ b/tests/header_only_library/lib.di @@ -0,0 +1,5 @@ +module tests.header_only_library.lib; + +int add(T)(T a, T b) { + return a + b; +} diff --git a/tests/implementation_deps/BUILD b/tests/implementation_deps/BUILD new file mode 100644 index 0000000..0fded26 --- /dev/null +++ b/tests/implementation_deps/BUILD @@ -0,0 +1,17 @@ +load("//d:d.bzl", "d_lib") + +d_lib( + name = "liba", + srcs = ["liba.d"], + implementation_deps = [ + "//tests/simple_d_library", + ], +) + +d_lib( + name = "libb", + srcs = ["libb.d"], + deps = [ + ":liba", + ], +) \ No newline at end of file diff --git a/tests/implementation_deps/liba.d b/tests/implementation_deps/liba.d new file mode 100644 index 0000000..40dbfc0 --- /dev/null +++ b/tests/implementation_deps/liba.d @@ -0,0 +1,6 @@ +module tests.implementation_deps.liba; + +int public_func(int x) { + import tests.simple_d_library.simple_library; + return plusOne(x); +} \ No newline at end of file diff --git a/tests/implementation_deps/libb.d b/tests/implementation_deps/libb.d new file mode 100644 index 0000000..056b0d1 --- /dev/null +++ b/tests/implementation_deps/libb.d @@ -0,0 +1,7 @@ +module tests.implementation_deps.libb; + +import tests.implementation_deps.liba; + +int libb_func(int x) { + return public_func(x); +} \ No newline at end of file diff --git a/tests/lib_that_depends_on_lib/BUILD b/tests/lib_that_depends_on_lib/BUILD index 3c09675..7e6f693 100644 --- a/tests/lib_that_depends_on_lib/BUILD +++ b/tests/lib_that_depends_on_lib/BUILD @@ -1,6 +1,6 @@ package(default_visibility = ["//visibility:public"]) -load("@io_bazel_rules_d//d:d.bzl", "d_library") +load("@rules_d//d:d.bzl", "d_library") d_library( name = "lib_that_depends_on_lib", diff --git a/tests/lib_that_depends_on_lib_test/BUILD b/tests/lib_that_depends_on_lib_test/BUILD index 2c8b87b..63982d4 100644 --- a/tests/lib_that_depends_on_lib_test/BUILD +++ b/tests/lib_that_depends_on_lib_test/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") +load("@rules_d//d:d.bzl", "d_test") d_test( name = "lib_that_depends_on_lib_test", diff --git a/tests/mix_sources_and_generated/BUILD b/tests/mix_sources_and_generated/BUILD new file mode 100644 index 0000000..1c84eca --- /dev/null +++ b/tests/mix_sources_and_generated/BUILD @@ -0,0 +1,39 @@ +load("//d:d.bzl", "d_binary", "d_library") + +genrule( + name = "generate_b", + srcs = ["b.d"], + outs = ["b_generated.d"], + cmd = "cat $< > $@", +) + +d_library( + name = "lib", + srcs = ["a.d", ":generate_b"], + generated_srcs = { + ":generate_b": "b.d", + }, +) + +d_library( + name = "lib_no_map", + srcs = ["a.d", ":generate_b"], +) + +d_binary( + name = "bin", + srcs = ["main.d"], + deps = [ + ":lib", + ], +) + +# This is expected to fail because the generated source file is not mapped +d_binary( + name = "bin_no_map", + srcs = ["main.d"], + deps = [ + ":lib_no_map", + ], + tags = ["manual"], +) \ No newline at end of file diff --git a/tests/mix_sources_and_generated/a.d b/tests/mix_sources_and_generated/a.d new file mode 100644 index 0000000..e7c4379 --- /dev/null +++ b/tests/mix_sources_and_generated/a.d @@ -0,0 +1,7 @@ +module tests.mix_sources_and_generated.a; + +import tests.mix_sources_and_generated.b; + +int a() { + return bfun(); +} diff --git a/tests/mix_sources_and_generated/b.d b/tests/mix_sources_and_generated/b.d new file mode 100644 index 0000000..ce8b226 --- /dev/null +++ b/tests/mix_sources_and_generated/b.d @@ -0,0 +1,5 @@ +module tests.mix_sources_and_generated.b; + +int bfun() { + return 42; +} diff --git a/tests/mix_sources_and_generated/main.d b/tests/mix_sources_and_generated/main.d new file mode 100644 index 0000000..9bdd5e6 --- /dev/null +++ b/tests/mix_sources_and_generated/main.d @@ -0,0 +1,9 @@ +import tests.mix_sources_and_generated.b; + +void main() { + // This is a test to check if the mix of sources and generated code works + // The generated code is in the `generated` directory + // The source code is in the `src` directory + // The test should pass if the mix works + assert(bfun() == 42); +} diff --git a/tests/simple/BUILD b/tests/simple/BUILD index 429a644..1e672d6 100644 --- a/tests/simple/BUILD +++ b/tests/simple/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") +load("@rules_d//d:d.bzl", "d_test") d_test( name = "simple", diff --git a/tests/simple_as_binary/BUILD b/tests/simple_as_binary/BUILD index c1168c1..a9ce516 100644 --- a/tests/simple_as_binary/BUILD +++ b/tests/simple_as_binary/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_binary") +load("@rules_d//d:d.bzl", "d_binary") d_binary( name = "simple", diff --git a/tests/simple_c_library/BUILD b/tests/simple_c_library/BUILD index 278aedf..292bd77 100644 --- a/tests/simple_c_library/BUILD +++ b/tests/simple_c_library/BUILD @@ -1,6 +1,6 @@ package(default_visibility = ["//visibility:public"]) -load("@io_bazel_rules_d//d:d.bzl", "d_source_library") +load("@rules_d//d:d.bzl", "d_source_library") cc_library( name = "simple_c_library", diff --git a/tests/simple_d_library/BUILD b/tests/simple_d_library/BUILD index 59eb77a..1004b3a 100644 --- a/tests/simple_d_library/BUILD +++ b/tests/simple_d_library/BUILD @@ -1,6 +1,6 @@ package(default_visibility = ["//visibility:public"]) -load("@io_bazel_rules_d//d:d.bzl", "d_library") +load("@rules_d//d:d.bzl", "d_library") d_library( name = "simple_d_library", diff --git a/tests/simplest/BUILD b/tests/simplest/BUILD index 2f494b9..e489339 100644 --- a/tests/simplest/BUILD +++ b/tests/simplest/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_d//d:d.bzl", "d_test") +load("@rules_d//d:d.bzl", "d_test") d_test( name = "simplest",