Skip to content

Commit

Permalink
make cross compile a bit easier
Browse files Browse the repository at this point in the history
  • Loading branch information
adamdruppe committed Oct 24, 2024
1 parent 5fece24 commit 325ff73
Show file tree
Hide file tree
Showing 2 changed files with 310 additions and 3 deletions.
2 changes: 1 addition & 1 deletion ldc/ldc2.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ default:
rpath = "@SHARED_LIBS_RPATH@";
};

"^wasm(32|64)-":
"^wasm(32|64)-.*-none":
{
switches = [
"-defaultlib=",@WASM_DEFAULT_LDC_SWITCHES@
Expand Down
311 changes: 309 additions & 2 deletions opend/src/opend.d
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,172 @@ struct Commands {
/// Does a debug build with the given arguments
int build(string[] args) {
// FIXME: pull info out of the cache to get the right libs and -i modifiers out
return dmd(["-i"] ~ args);
return sendToCompilerDriver(["-i"] ~ args, "dmd");
}

/// Does a release build with the given arguments
int publish(string[] args) {
return ldmd2(["-i", "-O2"] ~ args);
return sendToCompilerDriver(["-i", "-O2"] ~ args, "ldmd2");
}

int sendToCompilerDriver(string[] args, string preferredCompiler = null) {
// extract --target
string[] argsToKeep;
argsToKeep.reserve(args.length);

int translateTarget(string target) {
import std.string;

string os;
string platform;
string cpu;
string detail;

foreach(part; target.toLower.split("-")) {
switch(part) {
case "windows":
case "win64":
cpu = "x86_64";
os = "windows";
detail = "msvc";
break;
case "mac":
case "macos":
if(cpu is null)
cpu = "x86_64,aarch64";
os = "apple";
detail = "darwin";
break;
case "ipad":
case "iphone":
if(cpu is null)
cpu = "aarch64,x86_64";
os = "apple";
detail = "ios";
break;
case "android":
if(cpu is null)
cpu = "aarch64,x86_64";
os = "linux";
detail = "android";
break;
// FIXME: i should add some bsd stuff too
case "linux":
if(cpu is null)
cpu = "x86_64";
os = "linux";
detail = "gnu";
break;
case "arm":
case "aarch64":
cpu = "aarch64";
break;
case "amd64":
case "x86_64":
case "intel":
cpu = "x86_64";
break;
case "wasm":
case "webassembly":
cpu = "wasm32";
if(os is null)
os = "emscripten";
break;
case "musl":
if(cpu is null)
cpu = "x86_64";
if(os is null)
os = "linux";
detail = "musl";
break;
case "emscripten":
os = "emscripten";
if(cpu is null) cpu = "wasm32";
break;
case "wasi":
detail = "wasi";
if(cpu is null) cpu = "wasm32";
break;
case "none":
os = "unknown";
detail = "none";
break;
case "x86":
import std.stdio;
stderr.writeln("32 bit not supported right now by opend, contact us to ask for it. Try amd64 instead.\n");
return 1;
case "win32":
import std.stdio;
stderr.writeln("32 bit not supported right now by opend, contact us to ask for it. Try win64 instead.\n");
return 1;
default:
import std.stdio;
stderr.writeln("Unknown part ", part, " try using -mtriple instead.");
return 1;
}
}

string triple;
void addPart(string w) {
if(w.length) {
if(triple.length)
triple ~= "-";
triple ~= w;
}
}

auto comma = cpu.indexOf(",");
if(comma != -1)
cpu = cpu[0 .. comma]; // FIXME: should actually spawn two instances

addPart(cpu);
addPart(platform);
addPart(os);
addPart(detail);

argsToKeep ~= "--mtriple=" ~ triple;
if(preferredCompiler.length == 0 || preferredCompiler == "dmd")
preferredCompiler = "ldmd2";

return 0;
}

bool nextIsTarget;
bool verbose;
import std.algorithm;
import std.string;
foreach(arg; args) {
if(nextIsTarget) {
nextIsTarget = false;
if(auto err = translateTarget(arg)) return err;
} else if(arg == "--target" || arg == "-target") {
nextIsTarget = true;
} else if(arg.startsWith("--target=")) {
if(auto err = translateTarget(arg["--target=".length .. $])) return err;
} else if(arg.indexOf("-mtriple") != -1) {
preferredCompiler = "ldmd2";
} else if(arg == "-v") {
argsToKeep ~= arg;
verbose = true;
} else
argsToKeep ~= arg;
}
args = argsToKeep;

if(verbose) {
import std.stdio;
stderr.writeln(preferredCompiler, " ", args);
}
switch(preferredCompiler) {
case "dmd":
return dmd(args);
case "ldmd2":
return ldmd2(args);
case "ldc2":
return ldc2(args);
default:
goto case "ldmd2";
}
}

// publish-source which puts the dependencies together?
Expand Down Expand Up @@ -121,6 +281,81 @@ struct Commands {
int ldc2(string[] args) {
return spawnProcess([getCompilerPath("ldc2")] ~ args, null).wait;
}

/// Installs optional components or updates to opend
int install(string[] args) {
// create the ../xpacks directory

static import std.file;
if(!std.file.exists(getXpackPath()))
std.file.mkdir(getXpackPath());

switch(args[0]) {
case "update":
// get the new update, if available, then repeat other xpack installs
return 1;
case "xpack-android":
// can extract the libs from the android downloads
// you must also install the ndk
return 1;
case "xpack-emscripten":
// https://github.com/opendlang/opend/releases/download/CI/opend-latest-xpack-emscripten.tar.xz
// you must also install the emsdk

downloadXpack("xpack-emscripten");
// phobos is compiled but puts out some warnings so gonna reenable it with -i and not link the phobos
// tbh might be a good idea to do that for other platforms too
installConfig(`
"^wasm(32|64)-.*-emscripten":
{
lib-dirs = [
"%%ldcbinarypath%%/../xpacks/opend-latest-xpack-emscripten/lib",
];
switches = [
"-defaultlib=druntime-ldc",
"--linker=emcc",
"-i=std",
];
};
`);

import std.stdio;
writeln("Installation complete, build with `opend build -mtriple=wasm32-emscripten <other args>`");
writeln("You will need the emsdk. Install that separately and follow its instructions to activate it before trying to build D code because opend will use emcc to finish the link step.");
writeln("https://emscripten.org/docs/getting_started/downloads.html");

return 0;
case "xpack-win64":
// https://github.com/opendlang/opend/releases/download/CI/opend-latest-xpack-win64.tar.xz
downloadXpack("xpack-win64");
installConfig(`
"x86_64-.*-windows-msvc":
{
lib-dirs = [
"%%ldcbinarypath%%/../xpacks/opend-latest-xpack-win64/lib",
];
};
`);

import std.stdio;
writeln("Installation complete, build with `opend build -mtriple=x86_64-windows-msvc <other args>`");

return 0;
default:
import std.stdio;
stderr.writeln("Unknown thing");
return 1;

// maybe should do xpack-freestanding-{amd64,aarch64}
// xpack-linux-aarch64, xpack-linux-musl
}
}
}

void installConfig(string configInfo) {
import std.file, std.path;
std.file.append(buildPath([dirName(thisExePath()), "../etc/ldc2.conf"]), configInfo);
}

string getCompilerPath(string compiler) {
Expand All @@ -137,6 +372,12 @@ string getRuntimeLibPath() {
return buildPath([dirName(thisExePath()), "../lib/"]);
}

string getXpackPath() {
import std.file, std.path;
return buildPath([dirName(thisExePath()), "../xpacks/"]);
}


struct OutputExecutable {
string exe;
string[] args;
Expand Down Expand Up @@ -167,3 +408,69 @@ OutputExecutable getOutputExecutable(string[] args) {
import std.path;
return OutputExecutable(buildPath(".", name), args[splitter .. $]);
}

void downloadXpack(string which) {
import arsd.archive;

import std.net.curl;

import core.thread.fiber;

ubyte[] availableData;

string url = "https://github.com/opendlang/opend/releases/download/CI/opend-latest-" ~ which ~ ".tar.xz";
string destination = getXpackPath();

void processor() {
TarFileHeader tfh;
long size;
ubyte[512] tarBuffer;

import std.stdio;
File file;
long currentFileSize;

decompressLzma(
(in ubyte[] chunk) => cast(void) processTar(&tfh, &size, chunk,
(header, isNewFile, fileFinished, data) {
if(isNewFile) {
import std.stdio; writeln("inflating xpack file ", header.filename);
import std.path, std.file;
mkdirRecurse(dirName(buildPath(destination, header.filename)));
file = File(buildPath(destination, header.filename), "wb");
currentFileSize = header.size;
}
file.rawWrite(data);
if(fileFinished)
file.close();
}),
(ubyte[] buffer) {
try_again:
auto canUse = buffer.length < availableData.length ? buffer.length : availableData.length;
if(canUse) {
buffer[0 .. canUse] = availableData[0 .. canUse];
availableData = availableData[canUse .. $];
return buffer[0 .. canUse];
} else {
Fiber.yield();
goto try_again;
}
},
tarBuffer[]
);
}

auto fiber = new Fiber(&processor, 1 * 1024 * 1024 /* reserve 1 MB stack */);

import std.stdio;
writeln("Downloading...");

auto http = HTTP(url);
http.onReceive = (ubyte[] data) {
availableData = data;
fiber.call();
return data.length - availableData.length;
};
http.perform();

}

0 comments on commit 325ff73

Please sign in to comment.