On Sun, Feb 02, 2020 at 03:16:46AM +0000, Saurabh Das via Digitalmars-d-learn wrote: > On Saturday, 1 February 2020 at 20:37:03 UTC, H. S. Teoh wrote: [...] > > I've actually done this before in an equation grapher program: the > > user inputs an equation, the program generates D code to compute the > > equation, then runs dmd to compile it into a shared library, and > > opens the shared library and looks up the symbol to execute the > > compiled code. Dmd is fast enough that this actually works fairly > > well. When the input to dmd is small, it's so fast you don't even > > notice it. [...] > This approach seems more tractable at present. Would you have any > example code lying around for this? [...]
It's very simple. Let's say you have your code in some string called 'code'. Since dmd nowadays can take stdin as input (specify "-" as input filename), all you have to do is to assemble your dmd command and use std.process's awesome API to run it: /* * Step 1: Compile the code */ string code = ...; auto cmd = [ "/usr/bin/dmd", // or wherever your dmd is "-O", // or whatever other flags you need "-fPIC", "-shared", // this is important "-of" ~ soFilename, // specify output filename "-" // read from stdin ] // This part is a bit involved because we have to spawn the // compiler as a child process then write our code string into // its stdin. // Alternatively, just write your code into a temporary file and // pass the filename to dmd, then you can just use // std.process.execute() which has a much simpler API. import std.process : pipeProcess, Redirect, wait; auto pipes = pipeProcess(cmd, Redirect.stdin | Redirect.stdout | Redirect.stderrToStdout); // Send code to compiler pipes.stdin.write(code); pipes.stdin.flush(); pipes.stdin.close(); // Read compiler output (optional) auto app = appender!string(); enum chunkSize = 4096; pipes.stdout.byChunk(chunkSize) .copy(app); // Wait for compiler to finish auto status = wait(pipes.pid); auto output = app.data; if (status != 0) throw new Exception("Failed to compile code:\n" ~ output); /* * Step 2: Load the compiled library. */ // This is for Posix; replace with Windows equivalent if you're // on Windows. auto libhandle = dlopen(soFilename.toStringz, RTLD_LAZY | RTLD_LOCAL); if (libhandle is null) ... /* handle error here */ // Look up entry point by symbol. string entryPoint = ...; /* symbol of library entry point */ alias FunType = int function(string); // your function signature here auto funptr = cast(FunType) dlsym(libhandle, entryPoint.toStringz); /* * Step 3: Use the compiled code. */ // Call the compiled function with whatever arguments. int result = funptr("my input"); ... // Cleanup once you're done with the library. dlclose(libhandle); std.file.remove(soFilename); T -- First Rule of History: History doesn't repeat itself -- historians merely repeat each other.