|
| 1 | +#!/usr/bin/env dub |
| 2 | +/+ dub.sdl: |
| 3 | + name "build" |
| 4 | + dependency "std" version="*" |
| 5 | ++/ |
| 6 | + |
| 7 | +/** |
| 8 | + * OpenDAL D Bindings Build Script |
| 9 | + * |
| 10 | + * This script builds the OpenDAL C library with specified features |
| 11 | + * and copies the necessary files for D bindings. |
| 12 | + * |
| 13 | + * This script is automatically executed during: |
| 14 | + * dub build |
| 15 | + * dub test |
| 16 | + * dub run |
| 17 | + * |
| 18 | + * For manual execution with custom options: |
| 19 | + * OPENDAL_TEST=memory dmd -run build.d |
| 20 | + * OPENDAL_TEST=fs OPENDAL_VERBOSE=1 dmd -run build.d release |
| 21 | + */ |
1 | 22 | module build;
|
2 |
| -import std.stdio: writeln; |
3 |
| -import std.path: buildPath; |
4 |
| -import std.process: spawnShell, wait; |
5 |
| -import std.exception; |
6 |
| -import std.file: copy, mkdir, exists; |
7 |
| -import std.conv: to; |
| 23 | + |
| 24 | +import std.stdio : writeln, stderr; |
| 25 | +import std.path : buildPath; |
| 26 | +import std.process : spawnShell, wait, environment; |
| 27 | +import std.exception : enforce; |
| 28 | +import std.file : copy, mkdir, exists; |
| 29 | +import std.conv : to; |
| 30 | +import std.string : startsWith, split, strip, toLower; |
| 31 | +import std.array : join; |
| 32 | + |
8 | 33 |
|
9 | 34 | version (Windows)
|
10 | 35 | enum staticlib = "opendal_c.lib";
|
11 | 36 | else
|
12 | 37 | enum staticlib = "libopendal_c.a";
|
13 | 38 |
|
14 |
| -void main (string[] args) |
| 39 | +struct BuildConfig |
15 | 40 | {
|
16 |
| - bool isRelease = args.length > 1 && args[1] == "release"; |
17 |
| - string buildType = isRelease ? "release" : "debug"; |
| 41 | + bool isRelease; |
| 42 | + string[] services; |
| 43 | + bool verbose; |
| 44 | + bool help; |
| 45 | +} |
18 | 46 |
|
19 |
| - // Run cargo build |
20 |
| - auto cargoCmd = "cargo build --manifest-path " ~ buildPath( |
21 |
| - "..", "c", "Cargo.toml") ~ (isRelease ? " --release" : ""); |
| 47 | +void printHelp() |
| 48 | +{ |
| 49 | + writeln("OpenDAL D Bindings Build Script"); |
| 50 | + writeln(); |
| 51 | + writeln("This script is automatically executed during:"); |
| 52 | + writeln(" dub build - Build the D bindings"); |
| 53 | + writeln(" dub test - Run unit tests"); |
| 54 | + writeln(" dub run - Build and run examples"); |
| 55 | + writeln(); |
| 56 | + writeln("Environment Variables (for use with dub commands):"); |
| 57 | + writeln(" OPENDAL_TEST The service to test (e.g., fs, s3, memory, etc.)"); |
| 58 | + writeln(" OPENDAL_{SERVICE}_* Service-specific configuration (e.g., OPENDAL_FS_ROOT)"); |
| 59 | + writeln(" OPENDAL_VERBOSE Set to '1' or 'true' for verbose output"); |
| 60 | + writeln(); |
| 61 | + writeln("Examples with environment variables:"); |
| 62 | + writeln(" OPENDAL_TEST=memory dub build"); |
| 63 | + writeln(" OPENDAL_TEST=fs OPENDAL_FS_ROOT=/tmp/test dub test"); |
| 64 | + writeln(" OPENDAL_TEST=memory OPENDAL_VERBOSE=1 dub build -b release"); |
| 65 | + writeln(); |
| 66 | + writeln("For manual execution with command line options:"); |
| 67 | + writeln(" dmd -run build.d [options]"); |
| 68 | + writeln(); |
| 69 | + writeln("Command line options:"); |
| 70 | + writeln(" release Build in release mode (default: debug)"); |
| 71 | + writeln(" --verbose Enable verbose output"); |
| 72 | + writeln(" --help Show this help message"); |
| 73 | + writeln(); |
| 74 | + writeln("Manual execution examples:"); |
| 75 | + writeln(" OPENDAL_TEST=memory dmd -run build.d"); |
| 76 | + writeln(" OPENDAL_TEST=fs OPENDAL_FS_ROOT=/tmp/test dmd -run build.d release"); |
| 77 | + writeln(" OPENDAL_TEST=fs OPENDAL_FS_ROOT=/tmp OPENDAL_VERBOSE=1 dmd -run build.d release"); |
| 78 | +} |
22 | 79 |
|
23 |
| - auto status = wait(spawnShell(cargoCmd)); |
24 |
| - if (status != 0) |
| 80 | +BuildConfig parseArgs(string[] args) |
| 81 | +{ |
| 82 | + BuildConfig config; |
| 83 | + config.services = []; // No default services - user must specify |
| 84 | + |
| 85 | + // Check environment variables first |
| 86 | + auto envTest = environment.get("OPENDAL_TEST", ""); |
| 87 | + if (envTest.length > 0) |
25 | 88 | {
|
26 |
| - throw new Exception("Cargo build failed with status: " ~ status.to!string); |
| 89 | + config.services = [envTest]; |
27 | 90 | }
|
28 |
| - else |
| 91 | + |
| 92 | + auto envVerbose = environment.get("OPENDAL_VERBOSE", ""); |
| 93 | + if (envVerbose == "1" || envVerbose.toLower() == "true") |
29 | 94 | {
|
30 |
| - writeln("Cargo build completed successfully"); |
| 95 | + config.verbose = true; |
| 96 | + } |
| 97 | + |
| 98 | + foreach (arg; args[1..$]) |
| 99 | + { |
| 100 | + if (arg == "release") |
| 101 | + { |
| 102 | + config.isRelease = true; |
| 103 | + } |
| 104 | + else if (arg == "--verbose") |
| 105 | + { |
| 106 | + config.verbose = true; |
| 107 | + } |
| 108 | + else if (arg == "--help" || arg == "-h") |
| 109 | + { |
| 110 | + config.help = true; |
| 111 | + } |
| 112 | + |
| 113 | + else |
| 114 | + { |
| 115 | + stderr.writeln("Unknown argument: ", arg); |
| 116 | + stderr.writeln("Use --help for usage information"); |
| 117 | + } |
31 | 118 | }
|
32 | 119 |
|
33 |
| - // Get opendal.h |
34 |
| - copy(buildPath("..", "c", "include", "opendal.h"), buildPath("source", "opendal", "opendal.h")); |
| 120 | + return config; |
| 121 | +} |
| 122 | + |
| 123 | +void buildCargoLibrary(BuildConfig config) |
| 124 | +{ |
| 125 | + // Check if services are specified |
| 126 | + if (config.services.length == 0) |
| 127 | + { |
| 128 | + stderr.writeln("Warning: No OpenDAL service specified for testing!"); |
| 129 | + stderr.writeln("Use OPENDAL_TEST environment variable to specify the service to test."); |
| 130 | + stderr.writeln("Example: OPENDAL_TEST=memory dub build"); |
| 131 | + stderr.writeln("Available services: memory, fs, s3, etc. (see OpenDAL documentation)"); |
| 132 | + stderr.writeln(); |
| 133 | + stderr.writeln("Building with only core functionality (no storage backends)..."); |
| 134 | + } |
| 135 | + |
| 136 | + // Build features list |
| 137 | + string[] features = ["opendal/blocking"]; |
| 138 | + foreach (service; config.services) |
| 139 | + { |
| 140 | + features ~= "opendal/services-" ~ service.strip(); |
| 141 | + } |
| 142 | + |
| 143 | + // Construct cargo command |
| 144 | + auto cargoCmd = "cargo build --manifest-path " ~ buildPath("..", "c", "Cargo.toml"); |
| 145 | + |
| 146 | + if (config.isRelease) |
| 147 | + cargoCmd ~= " --release"; |
| 148 | + |
| 149 | + cargoCmd ~= " --features \"" ~ features.join(",") ~ "\""; |
| 150 | + |
| 151 | + if (config.verbose) |
| 152 | + cargoCmd ~= " --verbose"; |
| 153 | + |
| 154 | + writeln("Building OpenDAL C library..."); |
| 155 | + writeln("Features: ", features.join(", ")); |
| 156 | + if (config.verbose) |
| 157 | + writeln("Command: ", cargoCmd); |
35 | 158 |
|
36 |
| - // Get libopendal_c.a |
37 |
| - auto libPath = buildPath("..", "c", "target", buildType, staticlib); |
38 |
| - writeln("Copying ", libPath, " to ", buildPath("lib", staticlib)); |
| 159 | + auto status = wait(spawnShell(cargoCmd)); |
| 160 | + enforce(status == 0, "Cargo build failed with status: " ~ status.to!string); |
| 161 | + |
| 162 | + writeln("✓ Cargo build completed successfully"); |
| 163 | +} |
| 164 | + |
| 165 | +void copyArtifacts(BuildConfig config) |
| 166 | +{ |
| 167 | + string buildType = config.isRelease ? "release" : "debug"; |
| 168 | + |
| 169 | + writeln("Copying build artifacts..."); |
| 170 | + |
| 171 | + // Copy header file |
| 172 | + auto headerSrc = buildPath("..", "c", "include", "opendal.h"); |
| 173 | + auto headerDst = buildPath("source", "opendal", "opendal.h"); |
| 174 | + |
| 175 | + if (config.verbose) |
| 176 | + writeln("Copying header: ", headerSrc, " -> ", headerDst); |
| 177 | + |
| 178 | + copy(headerSrc, headerDst); |
| 179 | + |
| 180 | + // Ensure lib directory exists |
39 | 181 | if (!exists("lib"))
|
40 |
| - mkdir ("lib"); |
41 |
| - copy(libPath, buildPath("lib", staticlib)); |
| 182 | + { |
| 183 | + if (config.verbose) |
| 184 | + writeln("Creating lib directory"); |
| 185 | + mkdir("lib"); |
| 186 | + } |
| 187 | + |
| 188 | + // Copy static library |
| 189 | + auto libSrc = buildPath("..", "c", "target", buildType, staticlib); |
| 190 | + auto libDst = buildPath("lib", staticlib); |
| 191 | + |
| 192 | + if (config.verbose) |
| 193 | + writeln("Copying library: ", libSrc, " -> ", libDst); |
| 194 | + |
| 195 | + copy(libSrc, libDst); |
| 196 | + |
| 197 | + writeln("✓ Build artifacts copied successfully"); |
| 198 | +} |
| 199 | + |
| 200 | +void main(string[] args) |
| 201 | +{ |
| 202 | + try |
| 203 | + { |
| 204 | + auto config = parseArgs(args); |
| 205 | + |
| 206 | + if (config.help) |
| 207 | + { |
| 208 | + printHelp(); |
| 209 | + return; |
| 210 | + } |
| 211 | + |
| 212 | + writeln("OpenDAL D Bindings Build"); |
| 213 | + writeln("========================"); |
| 214 | + writeln("Build mode: ", config.isRelease ? "release" : "debug"); |
| 215 | + writeln("Services: ", config.services.join(", ")); |
| 216 | + writeln(); |
| 217 | + |
| 218 | + buildCargoLibrary(config); |
| 219 | + copyArtifacts(config); |
| 220 | + |
| 221 | + writeln(); |
| 222 | + writeln("✓ Build completed successfully!"); |
| 223 | + writeln("Ready for: dub build, dub test, or dub run"); |
| 224 | + } |
| 225 | + catch (Exception e) |
| 226 | + { |
| 227 | + stderr.writeln("❌ Build failed: ", e.msg); |
| 228 | + import core.stdc.stdlib : exit; |
| 229 | + exit(1); |
| 230 | + } |
42 | 231 | }
|
0 commit comments