Prototype buildsystem "Drake"

Jacob Carlborg doob at me.com
Thu Jul 14 01:28:50 PDT 2011


On 2011-07-13 23:41, Nick Sabalausky wrote:
> "Jacob Carlborg"<doob at me.com>  wrote in message
> news:ivke5k$2m78$1 at digitalmars.com...
>>
>> First I have to say that I know you are doing this because you want to use
>> D as the language for the build scripts. The reason I did choose Ruby
>> because I think D will be too verbose and when I'm looking at drakefile.d
>> I do think it's too verbose.
>
> Yea, D is likely to be a little more verbose than what could be done in Ruby
> (or Python). Personally, I think that's well worth it, though. I don't know
> how many others would agree or not.
>
>
>> But instead of starting a debate between Ruby and D I'm going to give you
>> a few suggestions and comments instead.
>>
>> The minimal drakefile doesn't look that minimal.
>
> I think I may be able to make the "immutable modes = [];" optional by
> checking for it with some compile-time reflecion.
>
> The other parts I'll address further below...
>
>
>> This is the idea I have for a minimal build script file:
>>
>> target("main.d"); // builds "main.d" as an executable
>>
>> Or:
>>
>> target("foobar"); // builds the directory "foobar" as a library
>>
>> DSSS did this very good.
>>
>
> I've never been very comfortable with build systems magically understanding
> and inferring all those details about a language and filetypes. It just
> feels too "magic", it's much more difficult to expand to new
> languages/tools, and every time I use a system like that I feel completely
> lost every time I need to include even just one custom buildstep.
>
> However, Drake's design is expandable. Add-on modules can be created that
> define new target types, so you could do:
>
>      module drake_dlang;
>      class DLang : Target (or File)
>      {
>          //...etc
>      }
>
>      target!DLang("main.d");
>
> And that would essentially wrap a File target, adding in any D-specific
> things such as "The target is 'main.exe'". And if you really wanted you
> could take it one more step and do:
>
>      void targetD(string source)
>      {
>          target!DLang(source);
>      }
>
>      targetD("main.d");
>

If that's possible, then great, I was hoping this could be default. I 
see no reason why it should be more complicated or requires more syntax 
to such a simple thing as building a standard executable with default 
configurations. If it's not this easy by default, then I think the build 
tool have failed, just my opinion.

> Good add-ons could even be folded into the standard Drake.
>
>
>> Now looking in the drakefile.d. You have targets and tasks all over the
>> place, almost every target has "Task" as a template parameter. Why is this
>> necessary? Have one function for targets and one for tasks. Example from
>> the drakefile.d:
>>
>>          target!Task("upload", "all",
>>                  (Target t)
>>                  {
>>                          system("ftp ...");
>>                  }
>>          );
>>
>> Seems this could look like this:
>>
>> task("upload", "all", {
>>      system("ftp...");
>> }); // if D just could get a better looking delegate syntax
>>
>
> Some Drake terminology first: Every "node" in the dependency tree is a
> "Target". There are three pre-defined types of targets: "Task", "File" and
> "Dir". Other new target types can also be defined. So the template param is
> due to that.
>
> However, I suppose it may be a good idea for every target type to come with
> a matching shortcut:
>
>      alias target!Task task;
>      alias target!File file;
>      alias target!Dir  dir;
>
> Then your "task("upload", ...);" example should work.

Ok, now I see. I think this is quite important the you first show the 
most simple forms and then show what they actually are.

> I agree that D's delegate syntax could be better. I think something like
> your example would be possible, but I ran into what seemed like some type
> inference limitations with all the overloading and templates, etc.

Ok.

>> "getDCompiler" seems unnecessary, both ldc and gdc have a dmd compatible
>> wrapper, ldmd and gdmd. These wrappers takes the same flags as dmd and
>> translate them to the correct "native" flags.
>>
>
> That's great, I didn't know that. But, you still have to say "ldmd" or
> "gdmd" instead of "dmd". And since the idea of "getDCompiler" is to allow
> the user to select which compiler to use (if the drakefile's author wants to
> support that), something roughly like "getDCompiler" may still be needed,
> albeit in a greatly simplified form.
>
> In any case, it was just an example of using the "modes" feature.

Ok, I see. I would prefer if the tool had built-in support for this. 
Just calling a function named "compiler" and it will use that particular 
compiler.

>> The "drakfile" function seems unnecessary. I would use a string import (or
>> what it's called), importing the whole build script into a method in a
>> class. All code in the "drakefile" function would instead be at top level.
>>
>
> I'm not entirely opposed to that idea, but here are the (perhaps minor?)
> reasons I did it this way:
>
> - Using "import" inside functions is brand-new and likely still buggy. And
> unless I'm mistaken, I think there's other problems that still exist with
> using the same code inside a function as outside (such as some
> order-of-declaration limitations, IIRC). I wanted to get moving on something
> that would work reliably right away without being too sensitive to bleeding
> edge-cases. I figured if all that gets sorted out later on, then maybe a
> Drake v2 could go that route.

I was referring to this:

void main ()
{
     writeln(import("main.d"));
}

This has been working as long as I've been using D. It works in D1 as well.

> - I wasn't sure if a D file that isn't strictly a proper D file would be too
> weird, too confusing, too magical, or would confuse the fuck out of advanced
> IDE's.

I have no idea how an IDE would behave with an incomplete file like 
that. I pretty sure this only matters if the IDE does some semantic 
processing, i.e. something more than just syntax highlighting. Textmate, 
which basically only does syntax highlighting, has no problem with an 
incomplete D file.

> If those are really just totally bullshit reasons, then I'm certainly open
> to the idea of doing it as you suggest.
>
>
>> Most of the functions called in the build script should be instance
>> methods, this will allow to use threading, possible invoke multiple
>> targets/tasks simultaneously and running several build scripts
>> simultaneously.
>>
>
> My understanding is that with thread-local being the default, they *don't*
> need to be instance methods to be thread-safe.
>
> Also, dependency-checking and task-invocation (once they're implemented)
> won't occur at all until *after* the drakefile() function completes. The
> target!...(...) function merely defines the targets, adding them to an
> internal list - nothing more. So I'm not sure that's not really a
> thread-appropriate matter.
>
> Not really sure what you mean about running several build scripts
> simultaneously. The buildscript gets compiled into an exe, so the
> buildscripts all run in separate processes anyway.

Hm, it may actually not be a problem. I'll have to give this some more 
thought, if there is any problem or not. It's probably me doesn't think 
straight.

>> I see installation related code in the build script. I think a package
>> manager should be responsible for that. A build tool should deal with
>> single files and a package manager should deal with packages (of files).
>>
>
> Those are just there as examples. You can do it however you want.
>
>
> -------------------------------
> Not sent from an iPhone.
>
>

Ok, I see.

-- 
/Jacob Carlborg


More information about the Digitalmars-d mailing list