@@ -68,12 +68,172 @@ struct Commands {
6868 // / Does a debug build with the given arguments
6969 int build (string [] args) {
7070 // FIXME: pull info out of the cache to get the right libs and -i modifiers out
71- return dmd ([" -i" ] ~ args);
71+ return sendToCompilerDriver ([" -i" ] ~ args, " dmd " );
7272 }
7373
7474 // / Does a release build with the given arguments
7575 int publish (string [] args) {
76- return ldmd2 ([" -i" , " -O2" ] ~ args);
76+ return sendToCompilerDriver ([" -i" , " -O2" ] ~ args, " ldmd2" );
77+ }
78+
79+ int sendToCompilerDriver (string [] args, string preferredCompiler = null ) {
80+ // extract --target
81+ string [] argsToKeep;
82+ argsToKeep.reserve (args.length);
83+
84+ int translateTarget (string target) {
85+ import std.string ;
86+
87+ string os;
88+ string platform;
89+ string cpu;
90+ string detail;
91+
92+ foreach (part; target.toLower.split(" -" )) {
93+ switch (part) {
94+ case " windows" :
95+ case " win64" :
96+ cpu = " x86_64" ;
97+ os = " windows" ;
98+ detail = " msvc" ;
99+ break ;
100+ case " mac" :
101+ case " macos" :
102+ if (cpu is null )
103+ cpu = " x86_64,aarch64" ;
104+ os = " apple" ;
105+ detail = " darwin" ;
106+ break ;
107+ case " ipad" :
108+ case " iphone" :
109+ if (cpu is null )
110+ cpu = " aarch64,x86_64" ;
111+ os = " apple" ;
112+ detail = " ios" ;
113+ break ;
114+ case " android" :
115+ if (cpu is null )
116+ cpu = " aarch64,x86_64" ;
117+ os = " linux" ;
118+ detail = " android" ;
119+ break ;
120+ // FIXME: i should add some bsd stuff too
121+ case " linux" :
122+ if (cpu is null )
123+ cpu = " x86_64" ;
124+ os = " linux" ;
125+ detail = " gnu" ;
126+ break ;
127+ case " arm" :
128+ case " aarch64" :
129+ cpu = " aarch64" ;
130+ break ;
131+ case " amd64" :
132+ case " x86_64" :
133+ case " intel" :
134+ cpu = " x86_64" ;
135+ break ;
136+ case " wasm" :
137+ case " webassembly" :
138+ cpu = " wasm32" ;
139+ if (os is null )
140+ os = " emscripten" ;
141+ break ;
142+ case " musl" :
143+ if (cpu is null )
144+ cpu = " x86_64" ;
145+ if (os is null )
146+ os = " linux" ;
147+ detail = " musl" ;
148+ break ;
149+ case " emscripten" :
150+ os = " emscripten" ;
151+ if (cpu is null ) cpu = " wasm32" ;
152+ break ;
153+ case " wasi" :
154+ detail = " wasi" ;
155+ if (cpu is null ) cpu = " wasm32" ;
156+ break ;
157+ case " none" :
158+ os = " unknown" ;
159+ detail = " none" ;
160+ break ;
161+ case " x86" :
162+ import std.stdio ;
163+ stderr.writeln(" 32 bit not supported right now by opend, contact us to ask for it. Try amd64 instead.\n " );
164+ return 1 ;
165+ case " win32" :
166+ import std.stdio ;
167+ stderr.writeln(" 32 bit not supported right now by opend, contact us to ask for it. Try win64 instead.\n " );
168+ return 1 ;
169+ default :
170+ import std.stdio ;
171+ stderr.writeln(" Unknown part " , part, " try using -mtriple instead." );
172+ return 1 ;
173+ }
174+ }
175+
176+ string triple;
177+ void addPart (string w) {
178+ if (w.length) {
179+ if (triple.length)
180+ triple ~= " -" ;
181+ triple ~= w;
182+ }
183+ }
184+
185+ auto comma = cpu.indexOf(" ," );
186+ if (comma != - 1 )
187+ cpu = cpu[0 .. comma]; // FIXME: should actually spawn two instances
188+
189+ addPart(cpu);
190+ addPart(platform);
191+ addPart(os);
192+ addPart(detail);
193+
194+ argsToKeep ~= " --mtriple=" ~ triple;
195+ if (preferredCompiler.length == 0 || preferredCompiler == " dmd" )
196+ preferredCompiler = " ldmd2" ;
197+
198+ return 0 ;
199+ }
200+
201+ bool nextIsTarget;
202+ bool verbose;
203+ import std.algorithm ;
204+ import std.string ;
205+ foreach (arg; args) {
206+ if (nextIsTarget) {
207+ nextIsTarget = false ;
208+ if (auto err = translateTarget(arg)) return err;
209+ } else if (arg == " --target" || arg == " -target" ) {
210+ nextIsTarget = true ;
211+ } else if (arg.startsWith(" --target=" )) {
212+ if (auto err = translateTarget(arg[" --target=" .length .. $])) return err;
213+ } else if (arg.indexOf(" -mtriple" ) != - 1 ) {
214+ preferredCompiler = " ldmd2" ;
215+ } else if (arg == " -v" ) {
216+ argsToKeep ~= arg;
217+ verbose = true ;
218+ } else
219+ argsToKeep ~= arg;
220+ }
221+ args = argsToKeep;
222+
223+ if (verbose) {
224+ import std.stdio ;
225+ stderr.writeln(preferredCompiler, " " , args);
226+ }
227+ switch (preferredCompiler) {
228+ case " dmd" :
229+ return dmd (args);
230+ case " ldmd2" :
231+ return ldmd2 (args);
232+ case " ldc2" :
233+ return ldc2 (args);
234+ default :
235+ goto case " ldmd2" ;
236+ }
77237 }
78238
79239 // publish-source which puts the dependencies together?
@@ -121,6 +281,81 @@ struct Commands {
121281 int ldc2 (string [] args) {
122282 return spawnProcess ([getCompilerPath(" ldc2" )] ~ args, null ).wait;
123283 }
284+
285+ // / Installs optional components or updates to opend
286+ int install (string [] args) {
287+ // create the ../xpacks directory
288+
289+ static import std.file ;
290+ if (! std.file.exists (getXpackPath()))
291+ std.file.mkdir (getXpackPath());
292+
293+ switch (args[0 ]) {
294+ case " update" :
295+ // get the new update, if available, then repeat other xpack installs
296+ return 1 ;
297+ case " xpack-android" :
298+ // can extract the libs from the android downloads
299+ // you must also install the ndk
300+ return 1 ;
301+ case " xpack-emscripten" :
302+ // https://github.com/opendlang/opend/releases/download/CI/opend-latest-xpack-emscripten.tar.xz
303+ // you must also install the emsdk
304+
305+ downloadXpack(" xpack-emscripten" );
306+ // phobos is compiled but puts out some warnings so gonna reenable it with -i and not link the phobos
307+ // tbh might be a good idea to do that for other platforms too
308+ installConfig(`
309+ "^wasm(32|64)-.*-emscripten":
310+ {
311+ lib-dirs = [
312+ "%%ldcbinarypath%%/../xpacks/opend-latest-xpack-emscripten/lib",
313+ ];
314+
315+ switches = [
316+ "-defaultlib=druntime-ldc",
317+ "--linker=emcc",
318+ "-i=std",
319+ ];
320+ };
321+ ` );
322+
323+ import std.stdio ;
324+ writeln(" Installation complete, build with `opend build -mtriple=wasm32-emscripten <other args>`" );
325+ 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." );
326+ writeln(" https://emscripten.org/docs/getting_started/downloads.html" );
327+
328+ return 0 ;
329+ case " xpack-win64" :
330+ // https://github.com/opendlang/opend/releases/download/CI/opend-latest-xpack-win64.tar.xz
331+ downloadXpack(" xpack-win64" );
332+ installConfig(`
333+ "x86_64-.*-windows-msvc":
334+ {
335+ lib-dirs = [
336+ "%%ldcbinarypath%%/../xpacks/opend-latest-xpack-win64/lib",
337+ ];
338+ };
339+ ` );
340+
341+ import std.stdio ;
342+ writeln(" Installation complete, build with `opend build -mtriple=x86_64-windows-msvc <other args>`" );
343+
344+ return 0 ;
345+ default :
346+ import std.stdio ;
347+ stderr.writeln(" Unknown thing" );
348+ return 1 ;
349+
350+ // maybe should do xpack-freestanding-{amd64,aarch64}
351+ // xpack-linux-aarch64, xpack-linux-musl
352+ }
353+ }
354+ }
355+
356+ void installConfig (string configInfo) {
357+ import std.file , std.path ;
358+ std.file.append (buildPath([dirName(thisExePath()), " ../etc/ldc2.conf" ]), configInfo);
124359}
125360
126361string getCompilerPath (string compiler) {
@@ -137,6 +372,12 @@ string getRuntimeLibPath() {
137372 return buildPath ([dirName(thisExePath()), " ../lib/" ]);
138373}
139374
375+ string getXpackPath () {
376+ import std.file , std.path ;
377+ return buildPath ([dirName(thisExePath()), " ../xpacks/" ]);
378+ }
379+
380+
140381struct OutputExecutable {
141382 string exe;
142383 string [] args;
@@ -167,3 +408,69 @@ OutputExecutable getOutputExecutable(string[] args) {
167408 import std.path ;
168409 return OutputExecutable (buildPath(" ." , name), args[splitter .. $]);
169410}
411+
412+ void downloadXpack (string which) {
413+ import arsd.archive;
414+
415+ import std.net.curl ;
416+
417+ import core.thread.fiber ;
418+
419+ ubyte [] availableData;
420+
421+ string url = " https://github.com/opendlang/opend/releases/download/CI/opend-latest-" ~ which ~ " .tar.xz" ;
422+ string destination = getXpackPath();
423+
424+ void processor () {
425+ TarFileHeader tfh;
426+ long size;
427+ ubyte [512 ] tarBuffer;
428+
429+ import std.stdio ;
430+ File file;
431+ long currentFileSize;
432+
433+ decompressLzma(
434+ (in ubyte [] chunk) => cast (void ) processTar(&tfh, &size, chunk,
435+ (header, isNewFile, fileFinished, data) {
436+ if (isNewFile) {
437+ import std.stdio ; writeln(" inflating xpack file " , header.filename);
438+ import std.path , std.file ;
439+ mkdirRecurse(dirName(buildPath(destination, header.filename)));
440+ file = File (buildPath(destination, header.filename), " wb" );
441+ currentFileSize = header.size;
442+ }
443+ file.rawWrite(data);
444+ if (fileFinished)
445+ file.close();
446+ }),
447+ (ubyte [] buffer) {
448+ try_again:
449+ auto canUse = buffer.length < availableData.length ? buffer.length : availableData.length;
450+ if (canUse) {
451+ buffer[0 .. canUse] = availableData[0 .. canUse];
452+ availableData = availableData[canUse .. $];
453+ return buffer[0 .. canUse];
454+ } else {
455+ Fiber .yield();
456+ goto try_again;
457+ }
458+ },
459+ tarBuffer[]
460+ );
461+ }
462+
463+ auto fiber = new Fiber (&processor, 1 * 1024 * 1024 /* reserve 1 MB stack */ );
464+
465+ import std.stdio ;
466+ writeln(" Downloading..." );
467+
468+ auto http = HTTP (url);
469+ http.onReceive = (ubyte [] data) {
470+ availableData = data;
471+ fiber.call();
472+ return data.length - availableData.length;
473+ };
474+ http.perform();
475+
476+ }
0 commit comments