Skip to content

Commit bc93693

Browse files
committed
Implement arm64-windows builds
1 parent 026e2b4 commit bc93693

File tree

2 files changed

+121
-11
lines changed

2 files changed

+121
-11
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
release: # test + build + release
1010
types: [ published ]
1111
env:
12-
DC: ldc-1.41.0-beta1
12+
DC: ldc-1.41.0
1313

1414
defaults:
1515
run:
@@ -20,7 +20,7 @@ jobs:
2020
name: Build vanilla D
2121
strategy:
2222
matrix:
23-
os: [ubuntu-latest, macos-15-intel, windows-latest]
23+
os: [ubuntu-latest, macos-15-intel, windows-latest, windows-11-arm]
2424
build: [debug-fast, release-fast]
2525
runs-on: ${{ matrix.os }}
2626
steps:
@@ -48,6 +48,8 @@ jobs:
4848
# target: arm64-macos
4949
- runner: windows-latest
5050
target: x64-windows
51+
- runner: windows-11-arm
52+
target: arm64-windows
5153
v:
5254
- build: debug-fast,release-fast
5355
config: nih-cli,nih-static,nih-shared,vbe-static,vbe-shared

build/builder.d

Lines changed: 117 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ struct GlobalSettings
229229
bool prettyPrint;
230230
bool printCallees;
231231
bool verboseCallees;
232+
bool verbose;
232233
bool printTotalTime;
233234
bool timeTrace;
234235

@@ -244,6 +245,7 @@ struct GlobalSettings
244245

245246
// settings parser
246247
void setTarget(string option, string target) {
248+
247249
foreach(component; target.asLowerCase.text.splitter('-')) {
248250
auto aliasIndex = countUntil(targetAliases[].map!(a => a.from), component);
249251
if (aliasIndex >= 0) {
@@ -310,6 +312,7 @@ void printOptions() {
310312
stderr.writeln(" --print-commands Print commands that are being run");
311313
stderr.writeln(" --pretty Enable pretty printing of the commands");
312314
stderr.writeln(" --print-callees Print output of callee programs");
315+
stderr.writeln(" --verbose Verbose printing of a build process");
313316
stderr.writeln(" --verbose-callees Passes verbose flag to called programs");
314317
stderr.writeln(" --print-total-time Print time of all run commands");
315318
stderr.writeln(" --fuzzer Enable fuzzing");
@@ -362,6 +365,7 @@ GlobalSettings parseSettings(string[] args, const(Config)[] configs) {
362365
"pretty", "", &settings.prettyPrint,
363366
"print-callees", "", &settings.printCallees,
364367
"verbose-callees", "", &settings.verboseCallees,
368+
"verbose", "", &settings.verbose,
365369
"print-total-time", "", &settings.printTotalTime,
366370
"no-deps", "", &settings.nodeps,
367371
"fuzzer", "", &settings.fuzzer,
@@ -455,6 +459,7 @@ struct CompileParams {
455459
struct Job {
456460
CompileParams params;
457461
string[] args;
462+
string[string] envVars;
458463
string workDir;
459464
// When executable is produced it will be a first artifact
460465
string[] artifacts;
@@ -467,6 +472,95 @@ struct Job {
467472
bool printOutput;
468473
}
469474

475+
bool isSomeWindowsTarget(in GlobalSettings gs) {
476+
if (gs.targetOs != TargetOs.windows) return false;
477+
if (gs.targetArch == TargetArch.arm64) return true;
478+
if (gs.targetArch == TargetArch.x64) return true;
479+
return false;
480+
}
481+
482+
bool addWindowsLibs(in GlobalSettings gs, ref string[string] envVars) {
483+
import std.file;
484+
import std.path : baseName;
485+
486+
if (hostOs != TargetOs.windows) return true;
487+
if (!isSomeWindowsTarget(gs)) return true;
488+
// Only needed when cross-compiling
489+
if (!gs.isCrossCompiling) return true;
490+
491+
import std.process : execute, Config;
492+
auto result = execute(["vswhere", "-latest", "-property", "resolvedInstallationPath"], null, Config.none, size_t.max);
493+
494+
if (result.status != 0) {
495+
stderr.writeln("vswhere exited with ", result.status);
496+
stderr.writeln("Cannot find Windows SDK and Visual Studio");
497+
return false;
498+
}
499+
500+
// LDC will skip environment setup if it detects VSINSTALLDIR and VSCMD_ARG_TGT_ARCH
501+
auto vsPath = result.output.strip;
502+
envVars["VSINSTALLDIR"] = vsPath;
503+
envVars["VSCMD_ARG_TGT_ARCH"] = archName[gs.targetArch];
504+
505+
auto sdkPath = `C:\Program Files (x86)\Windows Kits\10\Lib`;
506+
if (!exists(sdkPath)) {
507+
stderr.writefln("Cannot find Windows SDK at %s", sdkPath);
508+
return false;
509+
}
510+
511+
string maxSdkPath;
512+
foreach(DirEntry e; dirEntries(sdkPath, SpanMode.shallow)) {
513+
if (gs.verbose) stderr.writefln("- SDK %s", e.name);
514+
// Filter out Windows Driver Kit (wdf)
515+
if (!e.name.baseName.startsWith("10.")) continue;
516+
if (maxSdkPath is null || e.name > maxSdkPath) {
517+
maxSdkPath = e.name;
518+
}
519+
}
520+
if (maxSdkPath is null) {
521+
stderr.writefln("Cannot find SDK at %s", sdkPath);
522+
return false;
523+
}
524+
525+
auto vsToolsPath = buildPath(vsPath, `VC\Tools\MSVC`);
526+
string maxVSPath;
527+
foreach(DirEntry e; dirEntries(vsToolsPath, SpanMode.shallow)) {
528+
if (gs.verbose) stderr.writefln("- VS %s", e.name);
529+
if (maxVSPath is null || e.name > maxVSPath) {
530+
maxVSPath = e.name;
531+
}
532+
}
533+
if (maxVSPath is null) {
534+
stderr.writefln("Cannot find Visual Studio at %s", vsToolsPath);
535+
return false;
536+
}
537+
538+
auto umLibsPath = buildPath(maxSdkPath, "um", archName[gs.targetArch]);
539+
auto ucrtLibsPath = buildPath(maxSdkPath, "ucrt", archName[gs.targetArch]);
540+
auto vsLibsPath = buildPath(maxVSPath, "lib", archName[gs.targetArch]);
541+
542+
auto umTestPath = buildPath(umLibsPath, "kernel32.lib");
543+
auto ucrtTestPath = buildPath(ucrtLibsPath, "libucrt.lib");
544+
auto vsTestPath = buildPath(vsLibsPath, "libcmt.lib");
545+
546+
if (!exists(umTestPath)) {
547+
stderr.writefln("Cannot find kernel32.lib in %s", umLibsPath);
548+
return false;
549+
}
550+
if (!exists(ucrtTestPath)) {
551+
stderr.writefln("Cannot find libucrt.lib in %s", ucrtLibsPath);
552+
return false;
553+
}
554+
if (!exists(vsTestPath)) {
555+
stderr.writefln("Cannot find libcmt.lib in %s", vsLibsPath);
556+
return false;
557+
}
558+
559+
import std.array : join;
560+
envVars["LIB"] = join([umLibsPath, ucrtLibsPath, vsLibsPath], ";");
561+
return true;
562+
}
563+
470564
Job makeCompileJob(in GlobalSettings gs, in CompileParams params) {
471565
import std.path : buildPath;
472566

@@ -499,7 +593,12 @@ Job makeCompileJob(in GlobalSettings gs, in CompileParams params) {
499593
extraArtifacts ~= params.makeArtifactPath(osObjExt[gs.targetOs]);
500594

501595
Flags flags = selectFlags(gs, params);
502-
string[] flagsStrings = flagsToStrings(gs, cast(size_t)flags, params);
596+
597+
string[string] envVars;
598+
string[] flagsStrings;
599+
string[] linkerFlags;
600+
addWindowsLibs(gs, envVars);
601+
flagsToStrings(gs, cast(size_t)flags, params, flagsStrings);
503602

504603
flagsStrings ~= gs.makeTargetTripleFlag;
505604

@@ -532,6 +631,7 @@ Job makeCompileJob(in GlobalSettings gs, in CompileParams params) {
532631
artifacts : artifacts,
533632
extraArtifacts : extraArtifacts,
534633
printOutput : gs.printCallees,
634+
envVars : envVars,
535635
};
536636
return job;
537637
}
@@ -619,10 +719,16 @@ JobResult runJob(in GlobalSettings gs, in Job job) {
619719
}
620720

621721
void printCommand() {
622-
if (gs.prettyPrint)
722+
if (gs.prettyPrint) {
623723
stderr.writefln("> %-(%s\n| %)", job.args);
624-
else
625-
stderr.writefln("> %-(%s %)", job.args);
724+
foreach(key, val; job.envVars)
725+
stderr.writefln("| $%s = %s", key, val);
726+
} else {
727+
stderr.writef("> %-(%s %)", job.args);
728+
foreach(key, val; job.envVars)
729+
stderr.writef(" $%s=%s", key, val);
730+
stderr.writeln;
731+
}
626732
}
627733

628734
if (gs.printCommands) printCommand;
@@ -632,7 +738,7 @@ JobResult runJob(in GlobalSettings gs, in Job job) {
632738
MonoTime startTime = currTime;
633739
import std.process : execute, Config;
634740
try {
635-
auto result = execute(job.args, null, Config.none, size_t.max, job.workDir);
741+
auto result = execute(job.args, job.envVars, Config.none, size_t.max, job.workDir);
636742
MonoTime endTime = currTime;
637743

638744
void printCalleeOutput() {
@@ -800,10 +906,14 @@ Flags selectFlags(in GlobalSettings g, in CompileParams params)
800906
return flags;
801907
}
802908

803-
string[] flagsToStrings(in GlobalSettings gs, in size_t bits, in CompileParams params) {
909+
void flagsToStrings(
910+
in GlobalSettings gs,
911+
in size_t bits,
912+
in CompileParams params,
913+
ref string[] flags)
914+
{
804915
import core.bitop : bsf;
805916

806-
string[] flags;
807917
string[] versions;
808918
string[] linkerFlags;
809919

@@ -1030,8 +1140,6 @@ string[] flagsToStrings(in GlobalSettings gs, in size_t bits, in CompileParams p
10301140
if (params.compiler == Compiler.dmd) flags ~= text("-version=", ver);
10311141
if (params.compiler == Compiler.ldc) flags ~= text("-d-version=", ver);
10321142
}
1033-
1034-
return flags;
10351143
}
10361144

10371145
enum TargetType : ubyte {

0 commit comments

Comments
 (0)