March 24, 2007
Andrei Alexandrescu (See Website For Email) wrote:

> Which brings me to the question: what is the project style with D that
> people use?

Same as with C/C++, I am using sh/perl for scripting - or even lua/ruby.

> What tool(s) do you use, and in what sequence?

GNU make or IDEs, which calls upon either $DC - normally gdc (also dmd)

> The way I
> currently do things is, I have a bunch of modules in a directory tree
> and I import them in whichever programs I'm writing. I edit the program,
> save it, and then just start it (the .d program; the fact that object
> files and a binary executable are generated is entirely transparent) from the command line. I never need to explicitly compile or build anything, and I only see any messages (such as gcc's link command) when the program has an error.

I build the project and then install the import modules and libraries
into a system directory, like /usr/local/include/d and /usr/local/lib.
When it's finished, use something like RPM to package the binaries up...

Still haven't got the entire hang of using build or something like rdmd.
(prefer installing first, over linking to the source directory directly)
But at least they compile and work OK now, using rebuild and GDC rdmd...


But if there's any demand, rdmd could be added to the GDC distribution ?
For some tasks it is *very* useful, kinda like the gdmd syntax wrapper.
Bud or Rebuild are probably large enough to be separate installations.

Shouldn't add more than 250k to the gdcmac download (or 750k unpacked)

/usr/local/bin/rdmd: Mach-O universal binary with 2 architectures
/usr/local/bin/rdmd (for architecture i386):    Mach-O executable i386
/usr/local/bin/rdmd (for architecture ppc):     Mach-O executable ppc

--anders
March 24, 2007

Andrei Alexandrescu (See Website For Email) wrote:
> Daniel Keep wrote:
>>
>> Andrei Alexandrescu (See Website For Email) wrote:
>>> [snipitty do dah, snippity day]
>>>
>>> Which brings me to the question: what is the project style with D that people use? What tool(s) do you use, and in what sequence?  The way I currently do things is, I have a bunch of modules in a directory tree and I import them in whichever programs I'm writing. I edit the program, save it, and then just start it (the .d program; the fact that object files and a binary executable are generated is entirely transparent) from the command line. I never need to explicitly compile or build anything, and I only see any messages (such as gcc's link command) when the program has an error.
>>>
>>> Andrei
>>
>> I have a slowly growing library of bits & pieces (stuff like my functools, vectors, colors, some concurrency stuff, etc.).  Any "throwaway" programs I write tend to end up in my D sandbox directory.
>>
>> Things I will actually use/want to keep end up in a directory all of their own, with an appropriate package structure, etc.  I tend to have various GVim windows open, editing the source files.
>>
>> In terms of running the programs, half the time I crack open a Cygwin bash shell and use "bud foo -clean -debug -etc -exec", "bud +foo -exec" if I've set up a build.cfg file, I've started using "rebuild -rffoo.rrf && foo" (which I hope is made a little cleaner in future), or just invoke it from the GVim window itself.
>>
>> I rarely, if ever, use dmd directly, since I hate having all those extra files cavorting with my pristine source files, so I tend to use -clean an awful lot :)
>>
>> The #! thing would be cool, but since I run Windows, I don't tend to use it.  That, and the fact that I tend to use lots of switches :3
> 
> Do your switches vary from one build to the next, or only from one file to the next? If the latter, you could use:
> 
> #!/path/to/rundmd -clean -debug -etc
> 
> as the first line of the program containing main(), and that works under cygwin. You don't have to build your program - ever. It builds itself when necessary.

They don't vary a great deal.  Although there are times when I'll add in some experimental code hidden behind a version identifier, and then play with the program with and without the code.

The other problem is that some projects are not simply a single program.
 For instance, with my current research project, the base programs are
altered by specifying additional user modules on the compile-line.  I
would be very annoyed having to modify a "main" script every time that
changed :p

>> I think rdmd would be far more useful if it pulled in all the needed modules automatically like build and rebuild do.
>>
>> I'm not sure associating .d files with rdmd under Windows would do much good.  One problem is that Windows makes a distinction between console and window apps, so either your console apps never output anything, or your window apps always have a console window lying around.  Python solves this by having python.exe and pythonw.exe (the latter is a window app, thus it has no console window), and using two extensions: .py and .pyw.
>>
>> To be honest, I think that D really lacks one important thing that I would make shell/system scripting far more appealing: an interpreter.
> 
> I already use D largely as an interpreter. It takes about as long as the equivalent Perl script to build and run, and much less to run - with readln() of course :o). That's why I can't figure out people's indifference vis-a-vis the shebang. It fosters a very attractive development cycle. If I had to build each and all of my D programs before running and dedicate one flagged command to each, I'd be much more frustrated.
> 
> 
> Andrei

I should have qualified: an *interactive* interpreter.  Python is so massively productive because I can drop into a Python shell and start playing with code.  It would be an incredible thing if D had an interactive interpreter and I could say

  "I wonder what happens when I cast a real straight to a ubyte..."

Then just drop into the interpreter and type

  >>> cast(ubyte)3.14159
  3

  "Ah, it turns into an integer.  What?  Well, it *might* have tried to
reinterpret it literally, you know... :("

	-- Daniel

P.S. Incidentally, running that example above has highlighted a new problem with my Phobos+Tango joint set up... I can't actually run dmd directly anymore :P

-- 
int getRandomNumber()
{
    return 4; // chosen by fair dice roll.
              // guaranteed to be random.
}

http://xkcd.com/

v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP  http://hackerkey.com/
March 24, 2007
Andrei Alexandrescu (See Website For Email) wrote:

>> The #! thing would be cool, but since I run Windows, I don't tend to use
>> it.  That, and the fact that I tend to use lots of switches :3
> 
> Do your switches vary from one build to the next, or only from one file to the next? If the latter, you could use:
> 
> #!/path/to/rundmd -clean -debug -etc
> 
> as the first line of the program containing main(), and that works under cygwin. You don't have to build your program - ever. It builds itself when necessary.

When doing more complex such "scripts", this seems to work OK:

#!/usr/bin/env rdmd --compiler=rebuild

i.e. just using rebuild as a drop-in replacement for gdmd/dmd


This caches the resulting program in /tmp (or $TEMP on Windows)
and passes any additional arguments over to the compiled program:

$ more run.d
#!/usr/bin/env rdmd --compiler=rebuild

import std.stdio;

void main(char[][] args)
{
  foreach (char[] arg; args)
    writefln("%s", arg);
}

$ ./run.d foo bar
/tmp/run-501-234881028-13386453-4D8B5B0DF758A62AAB383FC432A9EED4
foo
bar

The program name is a little "interesting", but otherwise it's good.
(for shell scripts or perl programs, then $0 would be the script...)

Tested briefly under Mac OS X and Linux, without larger incidents ?
(rdmd --force would rebuild the program if external things changed)


Should also work OK with Tango.
--anders


PS.
http://www.algonet.se/~afb/d/rdmd.d (GDC version of DMD bin)
http://svn.dsource.org/projects/dsss/downloads/rebuild/0.14/
March 24, 2007
Daniel Keep wrote:
>>> The #! thing would be cool, but since I run Windows, I don't tend to use
>>> it.  That, and the fact that I tend to use lots of switches :3
>> Do your switches vary from one build to the next, or only from one file
>> to the next? If the latter, you could use:
>>
>> #!/path/to/rundmd -clean -debug -etc
>>
>> as the first line of the program containing main(), and that works under
>> cygwin. You don't have to build your program - ever. It builds itself
>> when necessary.
> 
> They don't vary a great deal.  Although there are times when I'll add in
> some experimental code hidden behind a version identifier, and then play
> with the program with and without the code.
> 
> The other problem is that some projects are not simply a single program.
>  For instance, with my current research project, the base programs are
> altered by specifying additional user modules on the compile-line.  I
> would be very annoyed having to modify a "main" script every time that
> changed :p

No, but it's good you have a default. The shebang does not prevent you from actually compiling the program from the command line - it will be ignored.

>>> To be honest, I think that D really lacks one important thing that I
>>> would make shell/system scripting far more appealing: an interpreter.
>> I already use D largely as an interpreter. It takes about as long as the
>> equivalent Perl script to build and run, and much less to run - with
>> readln() of course :o). That's why I can't figure out people's
>> indifference vis-a-vis the shebang. It fosters a very attractive
>> development cycle. If I had to build each and all of my D programs
>> before running and dedicate one flagged command to each, I'd be much
>> more frustrated.
>>
>>
>> Andrei
> 
> I should have qualified: an *interactive* interpreter.  Python is so
> massively productive because I can drop into a Python shell and start
> playing with code.  It would be an incredible thing if D had an
> interactive interpreter and I could say
> 
>   "I wonder what happens when I cast a real straight to a ubyte..."
> 
> Then just drop into the interpreter and type
> 
>   >>> cast(ubyte)3.14159
>   3
> 
>   "Ah, it turns into an integer.  What?  Well, it *might* have tried to
> reinterpret it literally, you know... :("

I actually toyed a little with the idea of writing a little shell that reads a line, builds a small program with main() around that line, and compiles and runs that program. Should be reasonably fast. The problem is that this approach won't remember the previously-defined symbols.

> P.S. Incidentally, running that example above has highlighted a new
> problem with my Phobos+Tango joint set up... I can't actually run dmd
> directly anymore :P

Yah, me too. But you can put ". dmdconf phobos" or ". dmdconf tango" in your startup file.


Andrei
March 24, 2007
Anders F Björklund wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
> 
>>> The #! thing would be cool, but since I run Windows, I don't tend to use
>>> it.  That, and the fact that I tend to use lots of switches :3
>>
>> Do your switches vary from one build to the next, or only from one file to the next? If the latter, you could use:
>>
>> #!/path/to/rundmd -clean -debug -etc
>>
>> as the first line of the program containing main(), and that works under cygwin. You don't have to build your program - ever. It builds itself when necessary.
> 
> When doing more complex such "scripts", this seems to work OK:
> 
> #!/usr/bin/env rdmd --compiler=rebuild
> 
> i.e. just using rebuild as a drop-in replacement for gdmd/dmd
> 
> 
> This caches the resulting program in /tmp (or $TEMP on Windows)
> and passes any additional arguments over to the compiled program:
> 
> $ more run.d
> #!/usr/bin/env rdmd --compiler=rebuild
> 
> import std.stdio;
> 
> void main(char[][] args)
> {
>   foreach (char[] arg; args)
>     writefln("%s", arg);
> }
> 
> $ ./run.d foo bar
> /tmp/run-501-234881028-13386453-4D8B5B0DF758A62AAB383FC432A9EED4
> foo
> bar
> 
> The program name is a little "interesting", but otherwise it's good.
> (for shell scripts or perl programs, then $0 would be the script...)
> 
> Tested briefly under Mac OS X and Linux, without larger incidents ?
> (rdmd --force would rebuild the program if external things changed)
> 
> 
> Should also work OK with Tango.

This won't work if your script includes one of your own modules.

Andrei
March 24, 2007
Andrei Alexandrescu (See Website For Email) wrote:

>> When doing more complex such "scripts", this seems to work OK:
>>
>> #!/usr/bin/env rdmd --compiler=rebuild
>>
>> i.e. just using rebuild as a drop-in replacement for gdmd/dmd
>>
>> This caches the resulting program in /tmp (or $TEMP on Windows)
>> and passes any additional arguments over to the compiled program:
...
>> Should also work OK with Tango.
> 
> This won't work if your script includes one of your own modules.

I'm not sure what you mean. If I import foo and bar, then rebuild
will include foo.o and bar.o when compiling the main D program...

Had I used gdmd, then I *would* have needed to include foo.o/bar.o
(or a library containing those), but rebuild picks dependencies up:

run.d:
======
#!/usr/bin/env rdmd -v --verbose --compiler=rebuild

import std.stdio;

import foo;
import bar;

void main(char[][] args)
{
  writefln("%s %s", foo.foo, bar.bar);
}

foo.d:
======
module foo;

char[] foo()
{
  return "Hello";
}

bar.d:
======
module bar;

char[] bar()
{
  return "World";
}

And if we run this program with full verbosity, it will show us:

$ ./run.d
running: rebuild -quiet -v ./run.d -of/tmp/run-501-234881028-13386453-A1689B41B25F1EA1A08CED3004FB04D6 -od/tmp/
parse     run
meta      run
import    std.stdio     (/usr/bin/../include/d/4.0.1/std/stdio.d)
import    std.c.stdio   (/usr/bin/../include/d/4.0.1/std/c/stdio.d)
import    std.stdint    (/usr/bin/../include/d/4.0.1/std/stdint.d)
import    gcc.builtins  (/usr/bin/../include/d/4.0.1/gcc/builtins.d)
import    std.c.stddef  (/usr/bin/../include/d/4.0.1/std/c/stddef.d)
import    std.c.stdarg  (/usr/bin/../include/d/4.0.1/std/c/stdarg.d)
import    gcc.config (/usr/bin/../include/d/4.0.1/i686-apple-darwin8/gcc/config.d)
import    gcc.configext (/usr/bin/../include/d/4.0.1/gcc/configext.d)
import    std.c.darwin.ldblcompat (/usr/bin/../include/d/4.0.1/std/c/darwin/ldblcompat.d)
import    std.format    (/usr/bin/../include/d/4.0.1/std/format.d)
import    std.stdarg    (/usr/bin/../include/d/4.0.1/std/stdarg.d)
import    std.utf       (/usr/bin/../include/d/4.0.1/std/utf.d)
import    std.c.stdlib  (/usr/bin/../include/d/4.0.1/std/c/stdlib.d)
import    std.c.string  (/usr/bin/../include/d/4.0.1/std/c/string.d)
import    std.string    (/usr/bin/../include/d/4.0.1/std/string.d)
import    std.uni       (/usr/bin/../include/d/4.0.1/std/uni.d)
import    std.array     (/usr/bin/../include/d/4.0.1/std/array.d)
import    std.ctype     (/usr/bin/../include/d/4.0.1/std/ctype.d)
import    foo   (foo.d)
import    bar   (bar.d)
meta      stdio
meta      stdio
meta      stdint
meta      builtins
meta      stddef
meta      stdarg
meta      config
meta      configext
meta      ldblcompat
meta      format
meta      stdarg
meta      utf
meta      stdlib
meta      string
meta      string
meta      uni
meta      array
meta      ctype
meta      foo
meta      bar
code      run
code      stdio
code      stdio
code      stdint
code      builtins
code      stddef
code      stdarg
code      config
code      configext
code      ldblcompat
code      format
code      stdarg
code      utf
code      stdlib
code      string
code      string
code      uni
code      array
code      ctype
code      foo
code      bar
compile   gdmd -version=Posix -c ./run.d foo.d bar.d  -quiet  -od/tmp/
link      gdmd /tmp/run.o /tmp/foo.o /tmp/bar.o -of/tmp/run-501-234881028-13386453-A1689B41B25F1EA1A08CED3004FB04D6
running: /tmp/run-501-234881028-13386453-A1689B41B25F1EA1A08CED3004FB04D6
Hello World

I'm not sure it caches the object files (like C/C++'s "ccache"* does),
but it does cache the resulting program which works fine for "scripts".
If you have the same module name in different levels, you can use the
-oq flag that writes object files using fully-qualified module names.

It also picks up needed system modules, such as the one Tango uses...
(but above it decided correctly that all std modules were in gphobos)
Think you can get it to pick up external libraries using the library
build/lib pragmas, or by adding the linker flags to the shebang line.


If I want to change between dmd or gdc, or between Phobos and Tango,
then all I need is to change the "default" setting of rebuild.conf/.

--anders

* See http://ccache.samba.org/
March 24, 2007
Anders F Björklund wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
> 
>>> When doing more complex such "scripts", this seems to work OK:
>>>
>>> #!/usr/bin/env rdmd --compiler=rebuild
>>>
>>> i.e. just using rebuild as a drop-in replacement for gdmd/dmd
>>>
>>> This caches the resulting program in /tmp (or $TEMP on Windows)
>>> and passes any additional arguments over to the compiled program:
> ...
>>> Should also work OK with Tango.
>>
>> This won't work if your script includes one of your own modules.
> 
> I'm not sure what you mean. If I import foo and bar, then rebuild
> will include foo.o and bar.o when compiling the main D program...
> 
> Had I used gdmd, then I *would* have needed to include foo.o/bar.o
> (or a library containing those), but rebuild picks dependencies up:
> 
> run.d:
> ======
> #!/usr/bin/env rdmd -v --verbose --compiler=rebuild

Great. For some reason, it didn't work in my initial tests; I guess I've
been sloppy somewhere.

Any chance you make the --compiler=rebuild a default? Or is rebuild a
separate product? (If so, that's not an attractive option.)

Essentially what you want is to make rdmd do the deed flag-free:

$ rdmd prog args

does whatever it takes to build prog.d (if necessary) and then runs it
passing args. Each extra needed flag cuts your cult following in half. :o)


Andrei

March 25, 2007
Andrei Alexandrescu (See Website For Email) skrev:

>> I'm not sure what you mean. If I import foo and bar, then rebuild
>> will include foo.o and bar.o when compiling the main D program...
>>
>> Had I used gdmd, then I *would* have needed to include foo.o/bar.o
>> (or a library containing those), but rebuild picks dependencies up:
>>
>> run.d:
>> ======
>> #!/usr/bin/env rdmd -v --verbose --compiler=rebuild
> 
> Great. For some reason, it didn't work in my initial tests; I guess I've
> been sloppy somewhere.
> 
> Any chance you make the --compiler=rebuild a default? Or is rebuild a
> separate product? (If so, that's not an attractive option.)

Let's see now...

rdmd as it stands at the moment is intended for dmd/gdmd, which means
that it won't work with multi-module programs (implicitly, that is...)
And Build/Bud or alternatively Rebuild are separate products as you say,
so it probably shouldn't be made the default option (even if it works)

Bud: http://dsource.org/projects/build/
Rebuild: http://dsource.org/projects/dsss/

But this is the same for all D programs, not just the "script" variant,
with the regular D compilers you need to give it all the object files
like you do with C/C++ compilers but with these alternative "build"
compilers you only give it the first program like you do with javac.

i.e. even if you do use your own modules, you *could* compile those into
a library and then link that with all your scripts using a -l option...
It's just that the "build" tools do this for you, and can also be taught
to pick up external libraries using: "version(build) pragma(link, baz);"

So I think it's fair to have the rdmd program default to using dmd/gdmd,
even if bud/rebuild do exist as an optional (and recommended) D add-on ?

> Essentially what you want is to make rdmd do the deed flag-free:
> 
> $ rdmd prog args
> 
> does whatever it takes to build prog.d (if necessary) and then runs it
> passing args. Each extra needed flag cuts your cult following in half. :o)

Currently this can be done by recompiling rdmd... (assuming here that
the rdmd source code eventually gets included in the DMD distribution)

This is the section to modify:
    char[] exepath, dfilepath, compiler = "dmd", tmpdir = "/tmp";
    version (GNU)
    {
        compiler = "gdmd";
    }
    version (Windows)
    {
        tmpdir = toString(getenv("TEMP"));
    }

Maybe it could even use a configuration file for those two options.
(i.e. a simple INI file for overriding --compiler and --tmpdir ?)

--anders
March 25, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Daniel Keep wrote:
>>>> The #! thing would be cool, but since I run Windows, I don't tend to use
>>>> it.  That, and the fact that I tend to use lots of switches :3
>>> Do your switches vary from one build to the next, or only from one file
>>> to the next? If the latter, you could use:
>>>
>>> #!/path/to/rundmd -clean -debug -etc
>>>
>>> as the first line of the program containing main(), and that works under
>>> cygwin. You don't have to build your program - ever. It builds itself
>>> when necessary.
>>
>> They don't vary a great deal.  Although there are times when I'll add in
>> some experimental code hidden behind a version identifier, and then play
>> with the program with and without the code.
>>
>> The other problem is that some projects are not simply a single program.
>>  For instance, with my current research project, the base programs are
>> altered by specifying additional user modules on the compile-line.  I
>> would be very annoyed having to modify a "main" script every time that
>> changed :p
> 
> No, but it's good you have a default. The shebang does not prevent you from actually compiling the program from the command line - it will be ignored.
> 
>>>> To be honest, I think that D really lacks one important thing that I
>>>> would make shell/system scripting far more appealing: an interpreter.
>>> I already use D largely as an interpreter. It takes about as long as the
>>> equivalent Perl script to build and run, and much less to run - with
>>> readln() of course :o). That's why I can't figure out people's
>>> indifference vis-a-vis the shebang. It fosters a very attractive
>>> development cycle. If I had to build each and all of my D programs
>>> before running and dedicate one flagged command to each, I'd be much
>>> more frustrated.
>>>
>>>
>>> Andrei
>>
>> I should have qualified: an *interactive* interpreter.  Python is so
>> massively productive because I can drop into a Python shell and start
>> playing with code.  It would be an incredible thing if D had an
>> interactive interpreter and I could say
>>
>>   "I wonder what happens when I cast a real straight to a ubyte..."
>>
>> Then just drop into the interpreter and type
>>
>>   >>> cast(ubyte)3.14159
>>   3
>>
>>   "Ah, it turns into an integer.  What?  Well, it *might* have tried to
>> reinterpret it literally, you know... :("
> 
> I actually toyed a little with the idea of writing a little shell that reads a line, builds a small program with main() around that line, and compiles and runs that program. Should be reasonably fast. The problem is that this approach won't remember the previously-defined symbols.

Yes!! I thought about making this too! Like the old times with MSX and C64! I loved having a "playground" like that.

It's possible to do in D as well, just append all lines to an in-memory D-file and it'll "remember" variables. You'll have to take care about multiply defined symbols, by ignoring the first? Not sure about the details yet.

L.
March 25, 2007
Anders F Björklund wrote:
> Andrei Alexandrescu (See Website For Email) skrev:
> 
>>> I'm not sure what you mean. If I import foo and bar, then rebuild
>>> will include foo.o and bar.o when compiling the main D program...
>>>
>>> Had I used gdmd, then I *would* have needed to include foo.o/bar.o
>>> (or a library containing those), but rebuild picks dependencies up:
>>>
>>> run.d:
>>> ======
>>> #!/usr/bin/env rdmd -v --verbose --compiler=rebuild
>>
>> Great. For some reason, it didn't work in my initial tests; I guess I've
>> been sloppy somewhere.
>>
>> Any chance you make the --compiler=rebuild a default? Or is rebuild a
>> separate product? (If so, that's not an attractive option.)
> 
> Let's see now...
> 
> rdmd as it stands at the moment is intended for dmd/gdmd, which means
> that it won't work with multi-module programs (implicitly, that is...)
> And Build/Bud or alternatively Rebuild are separate products as you say,
> so it probably shouldn't be made the default option (even if it works)
> 
> Bud: http://dsource.org/projects/build/
> Rebuild: http://dsource.org/projects/dsss/
> 
> But this is the same for all D programs, not just the "script" variant,
> with the regular D compilers you need to give it all the object files
> like you do with C/C++ compilers but with these alternative "build"
> compilers you only give it the first program like you do with javac.
> 
> i.e. even if you do use your own modules, you *could* compile those into
> a library and then link that with all your scripts using a -l option...
> It's just that the "build" tools do this for you, and can also be taught
> to pick up external libraries using: "version(build) pragma(link, baz);"
> 
> So I think it's fair to have the rdmd program default to using dmd/gdmd,
> even if bud/rebuild do exist as an optional (and recommended) D add-on ?

Well fair of course it is, it's IMHO just not enough. I strongly believe that an rdmd that automatically figures out dependencies must be part of the standard D distribution.

>> Essentially what you want is to make rdmd do the deed flag-free:
>>
>> $ rdmd prog args
>>
>> does whatever it takes to build prog.d (if necessary) and then runs it
>> passing args. Each extra needed flag cuts your cult following in half. :o)
> 
> Currently this can be done by recompiling rdmd... (assuming here that
> the rdmd source code eventually gets included in the DMD distribution)
> 
> This is the section to modify:
>     char[] exepath, dfilepath, compiler = "dmd", tmpdir = "/tmp";
>     version (GNU)
>     {
>         compiler = "gdmd";
>     }
>     version (Windows)
>     {
>         tmpdir = toString(getenv("TEMP"));
>     }
> 
> Maybe it could even use a configuration file for those two options.
> (i.e. a simple INI file for overriding --compiler and --tmpdir ?)

If you make the code open source, I'd be glad to hack into it to make it do the deed without relying on any other tool.


Andrei