diff --git a/.gitignore b/.gitignore index 6419010722..0b30bb3735 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,9 @@ modlist-release.ddoc /d.tag /.generated + +# DUB binaries +/assert_writeln_magic + +# Generated changelogs +changelog/*_pre.dd diff --git a/README.md b/README.md index 2410a6ef19..1c506defc4 100644 --- a/README.md +++ b/README.md @@ -13,4 +13,4 @@ documentation, and some articles. * [Wiki](https://wiki.dlang.org/) If you wish to contribute to the website or language documentation, please see -the [CONTRIBUTING.md file] (CONTRIBUTING.md). +the [CONTRIBUTING.md file](CONTRIBUTING.md) and [wiki entry](https://wiki.dlang.org/Contributing_to_dlang.org). diff --git a/assert_writeln_magic.d b/assert_writeln_magic.d new file mode 100755 index 0000000000..b770c113ff --- /dev/null +++ b/assert_writeln_magic.d @@ -0,0 +1,323 @@ +#!/usr/bin/env dub +/++ +dub.sdl: +dependency "libdparse" version="0.7.0-beta.7" +name "assert_writeln_magic" ++/ +/* + * Tries to convert `assert`'s into user-friendly `writeln` calls. + * The objective of this tool is to be conservative as + * broken example look a lot worse than a few statements + * that could have potentially been rewritten. + * + * - only EqualExpressions are "lowered" + * - static asserts are ignored + * - only single-line assers are rewritten + * + * Copyright (C) 2017 by D Language Foundation + * + * Author: Sebastian Wilzbach + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) +*/ +// Written in the D programming language. + +import dparse.ast; +import std.algorithm; +import std.conv; +import std.experimental.logger; +import std.range; +import std.stdio; +import std.typecons; + +private string formatNode(T)(const T t) +{ + import dparse.formatter; + import std.array : appender; + + auto writer = appender!string(); + auto formatter = new Formatter!(typeof(writer))(writer); + formatter.format(t); + return writer.data; +} + +class TestVisitor : ASTVisitor +{ + import dparse.lexer : tok, Token; + + this(string fileName, string destFile) + { + this.fileName = fileName; + fl = FileLines(fileName, destFile); + } + + alias visit = ASTVisitor.visit; + + override void visit(const Unittest test) + { + resetTestState(); + inTest = true; + scope(exit) inTest = false; + test.accept(this); + + processLastAssert(); + } + + override void visit(const EqualExpression expr) + { + enum eqToken = tok!"=="; + if (inAssert && expr.operator == eqToken && expr.left !is null && expr.right !is null) + lastEqualExpression = expr; + } + + override void visit(const AssertExpression expr) + { + if (inFunctionCall) + return; + + lastAssert = expr; + inAssert = true; + expr.accept(this); + inAssert = false; + fromAssert = true; + } + + // for now static asserts are ignored + override void visit(const StaticAssertStatement expr) + { + fromStaticAssert = true; + expr.accept(this); + } + + /** + The following code (in std.concurrency) leads to false positives: + + assertNotThrown!AssertError(assert(receiveOnly!int() == i)); + + Hence we simply ignore all asserts in function calls. + */ + override void visit(const FunctionCallExpression expr) + { + inFunctionCall = true; + expr.accept(this); + inFunctionCall = false; + } + + /// A single line + override void visit(const DeclarationOrStatement expr) + { + processLastAssert(); + expr.accept(this); + } + + void processLastAssert() + { + import std.uni : isWhite; + import std.format : format; + + if (fromAssert && !fromStaticAssert && + lastEqualExpression !is null && lastAssert !is null) + { + auto e = lastEqualExpression; + if (e.left !is null && e.right !is null) + { + // libdparse starts the line count with 1 + auto lineNr = lastAssert.line - 1; + + // only replace single-line expressions (for now) + if (fl[lineNr].endsWith(";")) + { + auto wsLen = fl[lineNr].countUntil!(u => !u.isWhite); + auto indent = fl[lineNr][0 .. wsLen]; + + if (fl[lineNr][wsLen .. $].startsWith("assert", "static assert")) + { + auto left = lastEqualExpression.left.formatNode; + auto right = lastEqualExpression.right.formatNode; + + if (left.length + right.length > 80) + fl[lineNr] = format("%s// %s\n%swriteln(%s);", indent, right, indent, left); + else + fl[lineNr] = format("%swriteln(%s); // %s", indent, left, right); + + //writefln("line: %d, column: %d", lastAssert.line, lastAssert.column); + } + } + } + } + resetTestState(); + } + +private: + + void resetTestState() + { + fromAssert = false; + fromStaticAssert = false; + lastEqualExpression = null; + lastAssert = null; + } + + /// within in the node + bool inTest; + bool inAssert; + bool inFunctionCall; + + /// at a sibling after the node was seen, but the upper parent hasn't been reached yet + bool fromAssert; + bool fromStaticAssert; + + Rebindable!(const AssertExpression) lastAssert; + Rebindable!(const EqualExpression) lastEqualExpression; + + string fileName; + FileLines fl; +} + +void parseFile(string fileName, string destFile) +{ + import dparse.lexer; + import dparse.parser : parseModule; + import dparse.rollback_allocator : RollbackAllocator; + import std.array : uninitializedArray; + + auto inFile = File(fileName); + if (inFile.size == 0) + warningf("%s is empty", inFile.name); + + ubyte[] sourceCode = uninitializedArray!(ubyte[])(to!size_t(inFile.size)); + inFile.rawRead(sourceCode); + LexerConfig config; + auto cache = StringCache(StringCache.defaultBucketCount); + const(Token)[] tokens = getTokensForParser(sourceCode, config, &cache).array; + + RollbackAllocator rba; + auto m = parseModule(tokens, fileName, &rba); + auto visitor = new TestVisitor(fileName, destFile); + visitor.visit(m); + delete visitor; +} + +// Modify a path under oldBase to a new path with the same subpath under newBase. +// E.g.: `/foo/bar`.rebasePath(`/foo`, `/quux`) == `/quux/bar` +string rebasePath(string path, string oldBase, string newBase) +{ + import std.path : absolutePath, buildPath, relativePath; + return buildPath(newBase, path.absolutePath.relativePath(oldBase.absolutePath)); +} + +void main(string[] args) +{ + import std.file; + import std.getopt; + import std.path; + + string inputDir, outputDir; + string[] ignoredFiles; + + auto helpInfo = getopt(args, config.required, + "inputdir|i", "Folder to start the recursive search for unittest blocks (can be a single file)", &inputDir, + "outputdir|o", "Alternative folder to use as output (can be a single file)", &outputDir, + "ignore", "List of files to exclude (partial matching is supported)", &ignoredFiles); + + if (helpInfo.helpWanted) + { + return defaultGetoptPrinter(`assert_writeln_magic +Tries to lower EqualExpression in AssertExpressions of Unittest blocks to commented writeln calls. +`, helpInfo.options); + } + + inputDir = inputDir.asNormalizedPath.array; + + DirEntry[] files; + + // inputDir as default output directory + if (!outputDir.length) + outputDir = inputDir; + + if (inputDir.isFile) + { + files = [DirEntry(inputDir)]; + inputDir = ""; + } + else + { + files = dirEntries(inputDir, SpanMode.depth).filter!( + a => a.name.endsWith(".d") && !a.name.canFind(".git")).array; + } + + foreach (file; files) + { + if (!ignoredFiles.any!(x => file.name.canFind(x))) + { + // single files + if (inputDir.length == 0) + parseFile(file.name, outputDir); + else + parseFile(file.name, file.name.rebasePath(inputDir, outputDir)); + } + } +} + +/** +A simple line-based in-memory representation of a file. + - will automatically write all changes when the object is destructed + - will use a temporary file to do safe, whole file swaps +*/ +struct FileLines +{ + import std.array, std.file, std.path; + + string[] lines; + string destFile; + bool overwriteInputFile; + bool hasWrittenChanges; + + this(string inputFile, string destFile) + { + stderr.writefln("%s -> %s", inputFile, destFile); + this.overwriteInputFile = inputFile == destFile; + this.destFile = destFile; + lines = File(inputFile).byLineCopy.array; + + destFile.dirName.mkdirRecurse; + } + + // dumps all changes + ~this() + { + if (overwriteInputFile) + { + if (hasWrittenChanges) + { + auto tmpFile = File(destFile ~ ".tmp", "w"); + writeLinesToFile(tmpFile); + tmpFile.close; + tmpFile.name.rename(destFile); + } + } + else + { + writeLinesToFile(File(destFile, "w")); + } + } + + // writes all changes to a random, temporary file + void writeLinesToFile(File outFile) { + // dump file + foreach (line; lines) + outFile.writeln(line); + // within the docs we automatically inject std.stdio (hence we need to do the same here) + // writeln needs to be @nogc, @safe, pure and nothrow (we just fake it) + outFile.writeln("// \nprivate void writeln(T)(T l) { }"); + outFile.flush; + } + + string opIndex(size_t i) { return lines[i]; } + void opIndexAssign(string line, size_t i) { + hasWrittenChanges = true; + lines[i] = line; + } +} diff --git a/changelog/2.073.0.dd b/changelog/2.073.0.dd index d16ada0114..a6acd42dda 100644 --- a/changelog/2.073.0.dd +++ b/changelog/2.073.0.dd @@ -84,10 +84,10 @@ $(LI $(LNAME2 std-algorithm-searching-maxindex,Added `std.algorithm.searching.ma ------- import std.algorithm.searching : maxIndex; int[] a = [5, 4, 2, 1, 9, 10]; - assert(a.minIndex == 5); + assert(a.maxIndex == 5); int[] a; - assert(a.minIndex == -1); + assert(a.maxIndex == -1); ------- ) diff --git a/changelog/2.073.2.dd b/changelog/2.073.2.dd index 587d04a368..cdd135cf54 100644 --- a/changelog/2.073.2.dd +++ b/changelog/2.073.2.dd @@ -29,5 +29,5 @@ $(LI $(BUGZILLA 17198): rdmd does not recompile when --extra-file is added) ) $(CHANGELOG_NAV_LAST 2.073.1) Macros: - VER=LATEST + VER=2.073.2 TITLE=Change Log: $(VER) diff --git a/changelog/changelog.ddoc b/changelog/changelog.ddoc index a452b0153f..41b96aaf62 100644 --- a/changelog/changelog.ddoc +++ b/changelog/changelog.ddoc @@ -25,6 +25,15 @@ $(SMALL released $1, $2) $4 ) +NIGHTLY_VERSION= +$(DIVC version, +$(P +$(B $(LARGE $(LINK2 http://nightlies.dlang.org, Download D nightlies)))$(BR) +$(SMALL $1) +) +$4 +) + BUGZILLA = Bugzilla $0 CPPBUGZILLA = Bugzilla $0 DSTRESS = dstress $0 diff --git a/cpptod.dd b/cpptod.dd index 83efe76167..0bc5b3e2ef 100644 --- a/cpptod.dd +++ b/cpptod.dd @@ -45,7 +45,7 @@ class Foo $(H4 The D Way) - Constructors are defined with the this keyword: + Constructors are defined with the `this` keyword: ------ class Foo @@ -76,7 +76,7 @@ class B : A $(H4 The D Way) - The base class constructor is called with the super syntax: + The base class constructor is called with the `super` syntax: ------ class A { this() { ... } } @@ -573,24 +573,33 @@ void test() $(H4 The D Way) The D version is analogous, though a little simpler, taking - advantage of promotion of single template members to the + advantage of + $(HTTPS dlang.org/spec/template.html#implicit_template_properties, + Eponymous Templates) - promotion of single template members to the enclosing name space: - ------ template factorial(int n) { - enum { factorial = n * .factorial!(n-1) } + enum factorial = n * .factorial!(n-1); } template factorial(int n : 1) { - enum { factorial = 1 } + enum factorial = 1; } void test() { - writefln("%d", factorial!(4)); // prints 24 + writeln(factorial!(4)); // prints 24 } +------ + The template blocks can be made shorter using + $(HTTPS dlang.org/spec/template.html#variable-template, + Enum Template) syntax: +------ +enum factorial(int n) = n * .factorial!(n-1); + +enum factorial(int n : 1) = 1; ------
$(COMMENT -------------------------------------------- ) @@ -800,7 +809,7 @@ template IsFunctionT(T) void test() { - typedef int fp(int); + alias int fp(int); assert(IsFunctionT!(fp) == 1); } diff --git a/css/style.css b/css/style.css index 7575bc9b4a..bf1760b13c 100644 --- a/css/style.css +++ b/css/style.css @@ -79,6 +79,12 @@ body > .container position: relative; } +input, textarea +{ + background: white; + color: #333; +} + /* top nav bar */ #top @@ -991,6 +997,32 @@ table td:not(:last-child), table th:not(:last-child) padding-right: 1em; } +/* + These next two rules are for pages like: + http://dlang.org/phobos-prerelease/std_regex.html + + The idea is if we have a list of links, we want space + to the right of each one. But detecting a list of links + vs just a single link requires some thought: the css + adjacent sibling rule does well detecting all but the first + one in a list, so we'll add space to the right of them (that's + the second rule here), but that leaves an inconsistent space + after the first item. + + That's where the following rule comes in: on the item directly + following the first link, add some left padding to simulate the + first one having the same space as the others. +*/ +table.book tbody a:first-child + a +{ + padding-left: .6em; +} + +table.book tbody a + a +{ + padding-right: .6em; +} + hr { margin: 2em 0; @@ -1610,7 +1642,7 @@ div.changelog-nav /* Runnable-examples css */ textarea.d_code {display: none;} -textarea.d_code_output, textarea.d_code_stdin, textarea.d_code_args +textarea.d_code_stdin, textarea.d_code_args { text-align: left; border: none; @@ -1624,6 +1656,11 @@ textarea.d_code_output, textarea.d_code_stdin, textarea.d_code_args outline: none; } +pre.d_code_output { + border: none; + max-height: 30em; +} + div.d_code {margin: 0; padding: 0; background: #F5F5F5;} div.d_run_code {display: none;} div.d_code_output, div.d_code_stdin, div.d_code_args, div.d_code_unittest @@ -1681,6 +1718,11 @@ input.editButton:active position: relative; top: 1px; } input.resetButton{display: none} + +/* Style for the example run buttons on the Phobos library documentation */ +.d_example_buttons { + text-align: left; +} /* Runnable-examples css -end */ .page-contents @@ -2113,8 +2155,3 @@ dt.d_decl:hover .decl_anchor { text-decoration: none; color: #333; } - -/* Style for the example run buttons on the Phobos library documentation */ -.d_example_buttons { - text-align: right; -} diff --git a/ctod.dd b/ctod.dd index d40703191b..634d25ef2d 100644 --- a/ctod.dd +++ b/ctod.dd @@ -78,7 +78,7 @@ sizeof(struct Foo) $(H4 The D Way) -$(P Use the size property:) +$(P Use the `sizeof` property:) ---------------------------- int.sizeof @@ -137,8 +137,8 @@ _Imaginary long double => ireal _Complex long double => creal ) $(P - Although char is an unsigned 8 bit type, and - wchar is an unsigned 16 bit type, they have their own separate types + Although `char` is an unsigned 8-bit type, and + `wchar` is an unsigned 16-bit type, they have their own separate types in order to aid overloading and type safety. ) $(P Ints and unsigneds in C are of varying size; not so in D.) @@ -194,7 +194,7 @@ long double r = fmodl(x,y); $(H4 The D Way) -D supports the remainder ('%') operator on floating point operands: +D supports the remainder (`%`) operator on floating point operands: ---------------------------- float f = x % y; @@ -208,14 +208,14 @@ $(H3 Dealing with NANs in floating point compares) $(H4 The C Way) C doesn't define what happens if an operand to a compare - is NAN, and few C compilers check for it (the Digital Mars - C compiler is an exception, DM's compilers do check for NAN operands). + is `NAN`, and few C compilers check for it (the Digital Mars + C compiler is an exception, DM's compilers do check for `NAN` operands). $(CCODE #include <math.h> if (isnan(x) || isnan(y)) - result = FALSE; + result = false; else result = (x < y); ) @@ -233,9 +233,10 @@ result = (x < y); // false if x or y is nan $(H3 Asserts are a necessary part of any good defensive coding strategy) $(H4 The C Way) -$(P C doesn't directly support assert, but does support __FILE__ -and __LINE__ from which an assert macro can be built. In fact, -there appears to be practically no other use for __FILE__ and __LINE__.) +$(P C doesn't directly support assert in the language, but does define a macro +in the standard library header assert.h. That macro writes a diagnostic message +on stderr when the condition given as parameter is not true. The message will +use __FILE__, __LINE__ and __func__ (C99) to localize the failing assertion.) $(CCODE #include <assert.h> @@ -275,8 +276,8 @@ $(H3 Looping through an array) $(H4 The C Way) $(P - The array length is defined separately, or a clumsy - sizeof() expression is used to get the length.) + The array length is defined separately, or a clumsy and error prone + `sizeof()` expression is used to get the length.) $(CCODE #define ARRAY_LENGTH 17 @@ -295,7 +296,7 @@ for (i = 0; i < sizeof(array) / sizeof(array[0]); i++) $(H4 The D Way) -The length of an array is accessible through the property "length". +The length of an array is accessible through the `length` property. ---------------------------- int[17] array; @@ -319,7 +320,7 @@ foreach (value; array) func(value); ---------------------------- -or through the ref keyword (for reference access): +or through the `ref` keyword (for reference access): ---------------------------- int[17] array; @@ -343,8 +344,7 @@ int array_length; int *array; int *newarray; -newarray = (int *) - realloc(array, (array_length + 1) * sizeof(int)); +newarray = realloc(array, (array_length + 1) * sizeof(int)); if (!newarray) error("out of memory"); array = newarray; @@ -380,9 +380,8 @@ char *s2; char *s; // Concatenate s1 and s2, and put result in s -free(s); -s = (char *)malloc((s1 ? strlen(s1) : 0) + - (s2 ? strlen(s2) : 0) + 1); +s = malloc((s1 ? strlen(s1) : 0) + + (s2 ? strlen(s2) : 0) + 1); if (!s) error("out of memory"); if (s1) @@ -394,10 +393,8 @@ if (s2) // Append "hello" to s char hello[] = "hello"; -char *news; size_t lens = s ? strlen(s) : 0; -news = (char *) - realloc(s, (lens + sizeof(hello) + 1) * sizeof(char)); +char *news = realloc(s, lens + sizeof(hello) + 1); if (!news) error("out of memory"); s = news; @@ -406,7 +403,7 @@ memcpy(s + lens, hello, sizeof(hello)); $(H4 The D Way) - D overloads the operators ~ and ~= for char and wchar arrays to mean + D overloads the operators `~` and `~=` for char and wchar arrays to mean concatenate and append, respectively: ---------------------------- @@ -582,7 +579,7 @@ $(H3 Struct tag name space) $(H4 The C Way) - It's annoying to have to put the struct keyword every time a type is specified, + It's annoying to have to use the `struct` keyword every time a type is specified, so a common idiom is to use: $(CCODE @@ -612,7 +609,9 @@ $(CCODE void dostring(char *s) { enum Strings { Hello, Goodbye, Maybe, Max }; - static char *table[] = { "hello", "goodbye", "maybe" }; + static char *table[] = { [Hello] ="hello", + [Goodbye]="goodbye", + [Maybe] ="maybe" }; int i; for (i = 0; i < Max; i++) @@ -634,7 +633,9 @@ void dostring(char *s) structures, the enum, the table, and the switch cases. If there are a lot of values, the connection between the 3 may not be so obvious when doing maintenance, and so the situation is ripe for - bugs. + bugs. Designated initializers as were introduced with C99 allow + to link correctly 2 of the 3 data structures, but at the cost of + a lot of typing. Additionally, if the number of values becomes large, a binary or hash lookup will yield a considerable performance increase over @@ -718,23 +719,23 @@ Sometimes, it's nice to control the layout of a struct with nested structs and u $(H4 The C Way) - C doesn't allow anonymous structs or unions, which means that dummy tag names - and dummy members are necessary: + Before C11 C didn't allow for anonymous structs or unions, which meant that + dummy member names were necessary: $(CCODE struct Foo { int i; - union Bar + union { - struct Abc { int x; long y; } _abc; + struct { int x; long y; } abc; char *p; - } _bar; + } bar; }; -#define x _bar._abc.x -#define y _bar._abc.y -#define p _bar.p +#define x bar.abc.x +#define y bar.abc.y +#define p bar.p struct Foo f; @@ -839,10 +840,12 @@ $(H4 The C Way) $(CCODE union U { int a; long b; }; union U x = { 5 }; // initialize member 'a' to 5 +union U y = { .b = 42l }; // initialize member 'b' to 42 (C99) + ) Adding union members or rearranging them can have disastrous consequences - for any initializers. + for any initializers. Designated initializers in C99 fix that issue. $(H4 The D Way) @@ -865,13 +868,15 @@ $(H4 The C Way) $(CCODE struct S { int a; int b; }; struct S x = { 5, 3 }; +struct S y = { .b=3, .a=5 }; /* C99 */ ) This isn't much of a problem with small structs, but when there are numerous members, it becomes tedious to get the initializers carefully lined up with the field declarations. Then, if members are added or rearranged, all the initializations have to be found and - modified appropriately. This is a minefield for bugs. + modified appropriately. This is a minefield for bugs. Designated + initializers in C99 fix that issue. $(H4 The D Way) @@ -889,9 +894,11 @@ $(H3 Array Initializations) $(H4 The C Way) - C initializes array by positional dependence: + C initializes array by positional dependence. C99 fixes the issue: $(CCODE -int a[3] = { 3,2,2 }; +int a[3] = { 3,2,1 }; +int a[3] = { [2]=1, [0]=3, [1]=2 }; /* C99 designated initializer */ +int a[3] = { [2]=1, [0]=3, 2 }; /* C99 designated initializer */ ) Nested arrays may or may not have the { }: $(CCODE @@ -901,6 +908,7 @@ int b[3][2] = { 2,3, {6,5}, 3,4 }; $(H4 The D Way) D does it by positional dependence too, but an index can be used as well. + The D syntax is lighter than C99 designated initializers. The following all produce the same result: ---------------------------- @@ -981,9 +989,18 @@ $(CCODE #include <tchar.h> tchar string[] = TEXT("hello"); ) + Furthermore, in praxis `wchar_t` is not usable in portable code as its size + is implementation dependent. On POSIX conforming machines it generally + represents an UTF-32 codeunit, on Windows an UTF-16 codeunit. C11 introduced + C++11 types char16_t and char32_t to overcome this issue. + $(H4 The D Way) -The type of a string is determined by semantic analysis, so there is no need to wrap strings in a macro call. Alternatively if type inference is used the string can have a $(B c), $(B w) or $(B d) suffix, representing UTF-8, UTF-16 and UTF-32 encoding, respectively. If no suffix is used the type is inferred to be a UTF-8 string: + The type of a string is determined by semantic analysis, so there is no need + to wrap strings in a macro call. Alternatively if type inference is used the + string can have a `c`, `w` or `d` suffix, representing UTF-8, + UTF-16 and UTF-32 encoding, respectively. If no suffix is used the type is + inferred to be a UTF-8 string: ----------------------------- string utf8 = "hello"; // UTF-8 string wstring utf16 = "hello"; // UTF-16 string @@ -1004,8 +1021,12 @@ $(H4 The C Way) $(CCODE enum COLORS { red, blue, green, max }; char *cstring[max] = {"red", "blue", "green" }; +char *cstring[max] = {[red]="red", [blue]="blue", [green]="green" }; /* C99 */ ) - This is fairly easy to get right because the number of entries is small. But suppose it gets to be fairly large. Then it can get difficult to maintain correctly when new entries are added. + This is fairly easy to get right because the number of entries is small. + But suppose it gets to be fairly large. Then it can get difficult to + maintain correctly when new entries are added. C99 added designated + initializers to solve that problem. $(H4 The D Way) ----------------------------- @@ -1071,7 +1092,7 @@ if (h != HANDLE_INIT) $(CCODE struct Handle__ HANDLE_INIT; -void init_handle() // call this function upon startup +void init_handle(void) // call this function upon startup { HANDLE_INIT.value = (void *)-1; } @@ -1087,9 +1108,9 @@ if (memcmp(&h,&HANDLE_INIT,sizeof(Handle)) != 0) $(H4 The D Way) - D has powerful metaprogramming abilties which allow it to implement - $(D typedef) as a library feature. Simply import $(B std.typecons) and - use the $(B Typedef) template: + D has powerful metaprogramming abilities which allow it to implement + $(D typedef) as a library feature. Simply import `std.typecons` and + use the `Typedef` template: ----------------------------- import std.typecons; @@ -1103,7 +1124,7 @@ foo(h); // syntax error bar(h); // ok ----------------------------- - To handle a default value, pass the initializer to the $(B Typedef) + To handle a default value, pass the initializer to the `Typedef` template as the second argument and refer to it with the $(D .init) property: @@ -1181,7 +1202,7 @@ if (strcmp(str, "betty") == 0) // do strings match? $(H4 The D Way) - Why not use the == operator? + Why not use the `==` operator? ----------------------------- string str = "hello"; @@ -1230,12 +1251,14 @@ qsort(array, sizeof(array)/sizeof(array[0]), ) A compare() must be written for each type, and much careful - typo-prone code needs to be written to make it work. + typo-prone code needs to be written to make it work. The indirect function + call required for each comparison limits the achievable performance of the + `qsort()` routine. $(H4 The D Way) - D has a powerful $(B std.algorithm) module with optimized + D has a powerful `std.algorithm` module with optimized sorting routines, which work for any built-in or user-defined type which can be compared: @@ -1258,6 +1281,14 @@ $(CCODE "This text spans\n\ multiple\n\ lines\n" +) + + C's string literal concatenation doesn't really solve the problem: + +$(CCODE +"This text spans\n" +"multiple\n" +"lines\n" ) If there is a lot of text, this can wind up being tedious. @@ -1394,7 +1425,7 @@ $(H3 Unsigned Right Shift) $(H4 The C Way) - The right shift operators >> and >>= are signed + The right shift operators `>>` and `>>=` are signed shifts if the left operand is a signed integral type, and are unsigned right shifts if the left operand is an unsigned integral type. To produce an unsigned right shift on an int, @@ -1422,9 +1453,9 @@ j = (unsigned)i >> 3; $(H4 The D Way) - D has the right shift operators >> and >>= which + D has the right shift operators `>>` and `>>=` which behave as they do in C. But D also has explicitly unsigned - right shift operators >>> and >>>= which will + right shift operators `>>>` and `>>>=` which will do an unsigned right shift regardless of the sign of the left operand. Hence, @@ -1579,7 +1610,7 @@ int main() $(H4 The D Way) - The ... following an array parameter declaration means that + The `...` following an array parameter declaration means that the trailing arguments are collected together to form an array. The arguments are type checked against the array type, and the number of arguments becomes a property diff --git a/dlang.org.ddoc b/dlang.org.ddoc index ee19198ab6..5667b38727 100644 --- a/dlang.org.ddoc +++ b/dlang.org.ddoc @@ -40,7 +40,7 @@ COMMON_SCRIPTS_DLANG = _= CONSOLE=$(TC pre, console notranslate, $0) -COPYRIGHT=Copyright © 1999-$(YEAR) by the $(LINK2 $(ROOT)/foundation.html, D Language Foundation) +COPYRIGHT_FOUNDATION=Copyright © 1999-$(YEAR) by the $(LINK2 $(ROOT_DIR)foundation.html, D Language Foundation) CPPCODE=$(TC pre, cppcode notranslate, $0) CPPLISTING=$(CPPCODE $0) CROSS=✘ @@ -54,9 +54,9 @@ DDOC= @@ -152,7 +152,7 @@ EXTRA_FOOTERS= _= FAVICON=$(STATIC favicon.ico) -FOOTER = $(DIVCID smallprint, copyright, $(COPYRIGHT) | Page generated by +FOOTER = $(DIVCID smallprint, copyright, $(COPYRIGHT_FOUNDATION) | Page generated by $(LINK2 $(ROOT_DIR)spec/ddoc.html, Ddoc) on $(GEN_DATETIME)) FOOTNOTE=$(SPANC footnote, $0) FULL_TITLE=$(TITLE) - D Programming Language diff --git a/dpl-docs/dub.selections.json b/dpl-docs/dub.selections.json index 940e1a480a..461d91224a 100644 --- a/dpl-docs/dub.selections.json +++ b/dpl-docs/dub.selections.json @@ -1,15 +1,15 @@ { "fileVersion": 1, "versions": { - "ddox": "0.15.15", + "ddox": "0.15.18", "experimental_allocator": "2.70.0-b1", "hyphenate": "1.1.1", "libasync": "0.7.9", - "libdparse": "0.6.0", + "libdparse": "0.7.0-beta.2", "libev": "5.0.0+4.04", - "libevent": "2.0.1+2.0.16", - "memutils": "0.4.5", + "libevent": "2.0.2+2.0.16", + "memutils": "0.4.8", "openssl": "1.1.4+1.0.1g", - "vibe-d": "0.7.28" + "vibe-d": "0.7.30" } } diff --git a/dpl-docs/source/app.d b/dpl-docs/source/app.d index 1a9b1b2d36..3956a32f2b 100644 --- a/dpl-docs/source/app.d +++ b/dpl-docs/source/app.d @@ -5,12 +5,16 @@ import std.getopt; import std.process; import vibe.core.log; +bool noExactSourceCodeLinks; + int main(string[] args) { string git_target = "master"; getopt(args, std.getopt.config.passThrough, - "git-target", &git_target); + "git-target", &git_target, + "no-exact-source-links", &noExactSourceCodeLinks); environment["GIT_TARGET"] = git_target; + environment["NO_EXACT_SOURCE_CODE_LINKS"] = noExactSourceCodeLinks ? "1" : "0"; setLogFormat(FileLogger.Format.plain); return ddoxMain(args); } diff --git a/dpl-docs/views/layout.dt b/dpl-docs/views/layout.dt index 6e127c1fd4..3be1eaf5d5 100644 --- a/dpl-docs/views/layout.dt +++ b/dpl-docs/views/layout.dt @@ -1,11 +1,14 @@ !!! 5 html(lang='en-US') + - import std.datetime : Clock; + - auto year = Clock.currTime.year; // - | Copyright (c) 1999-2016 by Digital Mars - | All Rights Reserved Written by Walter Bright - | http://digitalmars.com + | Copyright (c) 1999-$#{year} by the D Language Foundation + | All Rights Reserved. + | https://dlang.org/foundation.html - import std.process : environment; - string version_id = environment["GIT_TARGET"]; + - bool noExactSourceCodeLinks = environment["NO_EXACT_SOURCE_CODE_LINKS"] == "1"; - bool haveVersion = version_id.startsWith("v"); - string version_name = haveVersion ? version_id[1 .. $] : "Prerelease"; - string root_dir = info.linkTo(null) ~ (req is null ? "../" : ""); @@ -28,7 +31,7 @@ html(lang='en-US') script(type="text/javascript", src="#{root_dir}js/ddox.js") meta(name='viewport', content='width=device-width, initial-scale=1.0, minimum-scale=0.1, maximum-scale=10.0') - body.std(id='Phobos Runtime Library') + body.std(id='#{info.node.moduleName}') script(type='text/javascript'). document.body.className += ' have-javascript'; #top @@ -164,7 +167,7 @@ html(lang='en-US') - project = "druntime", path_prefix = "src/"; - else - project = "phobos", path_prefix = ""; - - if (info.docGroups.length == 1) + - if (info.docGroups.length >= 1 && !noExactSourceCodeLinks) - if (auto decl = cast(Declaration)info.docGroups[0].members[0]) line_suffix = "#L"~to!string(decl.line); - if (info.node.module_.isPackageModule) - filename = replace(modname, ".", "/") ~ "/package.d"; @@ -211,9 +214,8 @@ html(lang='en-US') | #quickindex.quickindex - #copyright - block copyright - | | Page generated by ddox. + #copyright.smallprint + | Copyright © 1999-#{year} by the D Language Foundation | Page generated by ddox. script(type='text/javascript', src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js') | @@ -223,7 +225,7 @@ html(lang='en-US') script(type='text/javascript', src='#{root_dir}js/codemirror-compressed.js') | script(type='text/javascript', src='#{root_dir}js/run.js') - | + script(type='text/javascript', src='#{root_dir}js/run_examples.js') script(type='text/javascript', src='#{root_dir}js/dlang.js') script(type='text/javascript', src='#{root_dir}js/listanchors.js') script(type='text/javascript'). diff --git a/dstyle.dd b/dstyle.dd index 63c8707341..f7039d2dc3 100644 --- a/dstyle.dd +++ b/dstyle.dd @@ -252,10 +252,10 @@ $(P Phobos and other official D source code, there are additional requirements: ) -$(UL - $(LI Braces should be on their own line. There are a few exceptions to this - (such as when declaring lambda functions), but with any normal function - block or type definition, the braces should be on their own line.) +$(H4 Brackets) + $(P Braces should be on their own line. There are a few exceptions to this + (such as when declaring lambda functions), but with any normal function + block or type definition, the braces should be on their own line.) ------------------------------- void func(int param) @@ -270,12 +270,17 @@ void func(int param) } } ------------------------------- - - $(LI Lines have a soft limit of 80 characters and a hard limit of 120 + $(P Avoid unnecessary parentheses:) +------------------------------- +(a == b) ? "foo" : "bar"; // NO +a == b ? "foo" : "bar"; // OK +------------------------------- +$(H4 Line length) + $(P Lines have a soft limit of 80 characters and a hard limit of 120 characters. This means that most lines of code should be no longer than 80 characters long but that they $(I can) exceed 80 characters when appropriate. However, they can $(I never) exceed 120 characters.) - +$(LISTSECTION Whitespace, $(LI Put a space after `for`, `foreach`, `if`, and `while`: ) ------------------------------- for (…) { … } @@ -286,7 +291,7 @@ while (…) { … } do { … } while (…); ------------------------------- $(LI Chains containing `else if (…)` or `else static if (…)` should set the - keywords on the same line:) + keywords on the same line:) ------------------------------- if (…) { @@ -297,38 +302,82 @@ else if (…) … } ------------------------------- + $(LI Put a space between binary operators, assignments, `cast`, and lambdas:) +------------------------------- +a + b +a / b +a == b +a && b +arr[1 .. 2] +int a = 100; +b += 1; +short c = cast(short) a; +filter!(a => a == 42); +------------------------------- + $(LI Put no space between unary operators, after `assert`, function calls:) +------------------------------- +a = !a && !(2 == -1); +bool b = ~a; +auto d = &c; +e++; +assert(*d == 42); +callMyFancyFunction("hello world"); +------------------------------- +) +$(LISTSECTION Imports, + $(LI Local, selective imports should be preferred over global imports) + $(LI Selective imports should have a space before and after the colon (`:`) like + `import std.range : zip`) + $(LI Imports should be sorted lexiographically.) +) +$(LISTSECTION Return type, + $(LI The return type should be stated $(I explicitly) wherever possible, + as it makes the documentation and source code easier to read.) + $(LI $(LINK2 https://dlang.org/spec/struct.html#nested, Function-nested) structs + (aka $(LINK2 https://wiki.dlang.org/Voldemort_types, Voldemort types)) + should be preferred over public `struct`s.) +) +$(LISTSECTION Attributes, + $(LI $(I Non-templated) functions should be annotated with + matching attributes (`@nogc`, `@safe`, `pure`, `nothrow`).) + $(LI $(I Templated) functions should $(B not) be annotated with attributes + as the compiler can infer them.) + $(LI $(B Every) $(I unittest) should be annotated + (e.g. `pure nothrow @nogc @safe unittest { ... }`) + to ensure the existence of attributes on the templated function.) +) +$(LISTSECTION Templates, $(LI `unittest` blocks should be avoided in templates. They will generate a new `unittest` for each instance, hence tests should be put outside of the template.) - ) - $(SUBLIST Imports, - $(LI Local, selective imports should be preferred over global imports) - $(LI Selective imports should have a space before and after the colon (`:`) like - `import std.range : zip`) - ) - $(SUBLIST Return type, - $(LI The return type should be stated $(I explicitly) wherever possible, - as it makes the documentation and source code easier to read.) - $(LI $(LINK2 https://dlang.org/spec/struct.html#nested, Function-nested) structs - (aka $(LINK2 https://wiki.dlang.org/Voldemort_types, Voldemort types)) - should be preferred over public `struct`s.) - ) - $(SUBLIST Attributes, - $(LI $(I Non-templated) functions should be annotated with - matching attributes (`@nogc`, `@safe`, `pure`, `nothrow`).) - $(LI $(I Templated) functions should $(B not) be annotated with attributes - as the compiler can infer them.) - $(LI $(B Every) $(I unittest) should be annotated - (e.g. `pure nothrow @nogc @safe unittest { ... }`) - to ensure the existence of attributes on the templated function.) - ) +) +$(LISTSECTION Declarations, $(LI Constraints on declarations should have the same indentation level as their declaration:) ------------------------------- -void foo(R) +void foo(R)(R r) if (R == 1) ------------------------------- +) +$(LISTSECTION Class/Struct Field Declarations, + $(LI In structs and classes, there should only be one space between the type of + the field and its name. This avoids problems with future changes generating a + larger git diff than necessary.) +------------------------------- +class MyClass +{ + // bad + int a; + double b; + + // good + int x; + double y; +} +------------------------------- +) +$(BR) $(P We are not necessarily recommending that all code follow these rules. They're likely to be controversial in any discussion on coding standards. @@ -339,5 +388,5 @@ $(P Macros: TITLE=The D Style - SUBLIST=$(H4 $1) $(UL $+) + LISTSECTION=$(H4 $1) $(UL $+) diff --git a/ebook.ddoc b/ebook.ddoc index 5d13dfd68d..5505dae711 100644 --- a/ebook.ddoc +++ b/ebook.ddoc @@ -3,9 +3,9 @@ DDOC= diff --git a/errorpage.ddoc b/errorpage.ddoc new file mode 100644 index 0000000000..528e27e824 --- /dev/null +++ b/errorpage.ddoc @@ -0,0 +1,2 @@ +ROOT_DIR=/ +ROOT= diff --git a/faq.dd b/faq.dd index c59bd63e9f..a803a26717 100644 --- a/faq.dd +++ b/faq.dd @@ -118,8 +118,7 @@ $(ITEM shared_synchronized, What does shared have to do with synchronization?) $(ITEM shared_memory_barriers, What does shared have to do with memory barriers?) - $(P Reading/writing shared data emits memory barriers to ensure sequential consistency (not - implemented). + $(Currently the compiler does not insert memory barriers around shared variables. ) $(ITEM casting_to_shared, What are the semantics of casting FROM unshared TO shared?) diff --git a/foundation.dd b/foundation.dd index d7a39abcd7..43222b0824 100644 --- a/foundation.dd +++ b/foundation.dd @@ -3,7 +3,7 @@ Ddoc $(D_S $(TITLE), $(H4 The D Language Foundation is a - $(HTTPS en.wikipedia.org/wiki/501(c)_organization, 501(c) non-profit public charity) + $(HTTPS en.wikipedia.org/wiki/501(c)_organization, 501(c)(3) non-profit public charity) devoted to advancing open source technology related to the D programming language. ) diff --git a/images/orgs-using-d/gnex.png b/images/orgs-using-d/gnex.png new file mode 100644 index 0000000000..dc6a145079 Binary files /dev/null and b/images/orgs-using-d/gnex.png differ diff --git a/images/orgs-using-d/gnex_hq.png b/images/orgs-using-d/gnex_hq.png new file mode 100644 index 0000000000..071ab816e8 Binary files /dev/null and b/images/orgs-using-d/gnex_hq.png differ diff --git a/index.dd b/index.dd index a75a365fd6..fcbdac302c 100644 --- a/index.dd +++ b/index.dd @@ -84,12 +84,10 @@ $(DIVID news, $(DIVC boxes, $(DIVC row, $(TOUR newspaper-o, News, - $(P $(LINK2 http://dconf.org/2017/index.html, DConf 2017): - Call for Submissions is open. $(BR) - The $(LINK2 $(ROOT_DIR)foundation.html, D Language Foundation) - has been accepted as a 501(c) non-profit public charity - and thus can handle - $(LINK2 $(ROOT_DIR)donate.html, donations). + $(P $(LINK2 http://dconf.org/2017/index.html, DConf 2017) + is coming up: May 4-7 in Berlin, Germany. $(BR) + $(LINK2 http://dconf.org/2017/registration.html, Secure your seat) + before it's sold out! ) $(P Stay updated with $(LINK2 http://arsdnet.net/this-week-in-d, @@ -125,7 +123,7 @@ $(DIVC boxes, on $(LINK2 https://twitter.com/D_Programming, Twitter). Browse the $(LINK2 https://wiki.dlang.org/, wiki) where among other things you can find the - $(LINK2 https://wiki.dlang.org/Vision/2016H2, high-level vision) + $(LINK2 https://wiki.dlang.org/Vision/2017H1, high-level vision) of the $(LINK2 $(ROOT_DIR)foundation.html, D foundation). ) ) diff --git a/js/run.js b/js/run.js index afddb1403b..63a82ed5d4 100644 --- a/js/run.js +++ b/js/run.js @@ -370,7 +370,7 @@ $(document).ready(function() + '' + '
Command line arguments
' + '
' - + '
Application output
' + + '
Application output
Running...
' + '' + '' + '' @@ -456,7 +456,7 @@ function setupTextarea(el, opts) var plainSourceCode = parent.parent().children("div.d_code"); - var output = outputDiv.children("textarea.d_code_output"); + var output = outputDiv.children("pre.d_code_output"); var outputTitle = outputDiv.children("span.d_code_title"); if (opts.args) { var argsBtn = parent.children("input.argsButton"); @@ -471,9 +471,9 @@ function setupTextarea(el, opts) var orgStdin = stdin.val(); } - var hideAllWindows = function(args) + var hideAllWindows = function(optArguments) { - args = args || {}; + optArguments = optArguments || {}; if (opts.stdin) { stdinDiv.css('display', 'none'); } @@ -481,10 +481,10 @@ function setupTextarea(el, opts) argsDiv.css('display', 'none'); } outputDiv.css('display', 'none'); - if (!args.keepPlainSourceCode) { + if (!optArguments.keepPlainSourceCode) { plainSourceCode.css('display', 'none'); } - if (!args.keepCode) { + if (!optArguments.keepCode) { code.css('display', 'none'); } }; @@ -531,13 +531,13 @@ function setupTextarea(el, opts) runBtn.click(function(){ resetBtn.css('display', 'inline-block'); $(this).attr("disabled", true); - var args = {}; + var optArguments = {}; // check what boxes are currently open if (opts.keepCode) { - args.keepCode = code.is(":visible"); - args.keepPlainSourceCode = plainSourceCode.is(":visible"); + optArguments.keepCode = code.is(":visible"); + optArguments.keepPlainSourceCode = plainSourceCode.is(":visible"); } - hideAllWindows(args); + hideAllWindows(optArguments); output.css('height', opts.outputHeight || height(31)); outputDiv.css('display', 'block'); outputTitle.text("Application output"); @@ -576,6 +576,7 @@ function setupTextarea(el, opts) } }); }); + return editor; }; diff --git a/js/run_examples.js b/js/run_examples.js index 28804beb93..a7b775cf92 100644 --- a/js/run_examples.js +++ b/js/run_examples.js @@ -8,7 +8,7 @@ // turns asserts into writeln function reformatExample(code) { - return code.replace(/(assert<\/span>\((.*)==(.*)\);)+/g, function(match, text, left, right) { + return code.replace(/(assert<\/span>(?:)?\((.*)==(.*)\);)+/g, function(match, text, left, right) { return "writeln(" + left.trim() + "); " + "// " + right.trim() + ""; }); @@ -44,28 +44,29 @@ $(document).ready(function() if (!$('body').hasClass("std")) return; - // only enable for pre-release version - if (location.pathname.indexOf("prerelease") < 0) - return; - // ignore not yet compatible modules // copied from Phobos posix.mak - var ignoredModulesList = "allocator/allocator_list.d,allocator/building_blocks/allocator_list.d,allocator/building_blocks/free_list.d,allocator/building_blocks/quantizer,allocator/building_blocks/quantizer,allocator/building_blocks/stats_collector.d,base64.d,bitmanip.d,concurrency.d,conv.d,csv.d,datetime.d,digest/hmac.d,digest/sha.d,file.d,index.d,isemail.d,logger/core.d,logger/nulllogger.d,math.d,ndslice/selection.d,ndslice/slice.d,numeric.d,stdio.d,traits.d,typecons.d,uni.d,utf.d,uuid.d".split(",") - var currentModulePath = $('body')[0].id.replace('.', '/') + '.d'; - if (ignoredModulesList.filter(function(x) { currentModulePath.indexOf(x) >= 0 }).length > 0) { + var ignoredModulesList = "base64.d,building_blocks/free_list,building_blocks/quantizer,digest/hmac.d,file.d,index.d,math.d,ndslice/selection.d,stdio.d,traits.d,typecons.d,uuid.d".split(",") + var currentModulePath = $('body')[0].id.split('.').join('/') + '.d'; + if (ignoredModulesList.filter(function(x) { return currentModulePath.indexOf(x) >= 0 }).length > 0) { return; } - $('pre[class~=d_code]').each(function(index) + // first selector is for ddoc - second for ddox + var codeBlocks = $('pre[class~=d_code]').add('pre[class~=code]'); + codeBlocks.each(function(index) { var currentExample = $(this); var orig = currentExample.html(); - orig = reformatExample(orig); + // disable regex assert -> writeln rewrite logic (for now) + //orig = reformatExample(orig); // check whether it is from a ddoced unittest + // 1) check is for ddoc, 2) for ddox // manual created tests most likely can't be run without modifications - if (!$(this).parent().parent().prev().hasClass("dlang_runnable")) + if (!($(this).parent().parent().prev().hasClass("dlang_runnable") || + $(this).prev().children(":last").hasClass("dlang_runnable"))) return; currentExample.replaceWith( @@ -81,7 +82,7 @@ $(document).ready(function() + '
' + '' + '
' - + '
Application output
' + + '
Application output
Running...
' + '
' ); }); @@ -90,15 +91,15 @@ $(document).ready(function() var parent = $(this).parent(); var btnParent = parent.parent().children(".d_example_buttons"); var outputDiv = parent.parent().children(".d_code_output"); - setupTextarea(this, { - parent: btnParent, - outputDiv: outputDiv, - stdin: false, - args: false, - transformOutput: wrapIntoMain, - defaultOutput: "All tests passed", - keepCode: true, - outputHeight: "auto" - }); + var editor = setupTextarea(this, { + parent: btnParent, + outputDiv: outputDiv, + stdin: false, + args: false, + transformOutput: wrapIntoMain, + defaultOutput: "All tests passed", + keepCode: true, + outputHeight: "auto" + }); }); }); diff --git a/modlist.d b/modlist.d index 88ab5df6f4..033d66017f 100644 --- a/modlist.d +++ b/modlist.d @@ -4,7 +4,7 @@ * License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(HTTP code.dawg.eu, Martin Nowak) */ -import std.algorithm, std.file, std.path, std.stdio, std.string, std.range; +import std.algorithm, std.file, std.getopt, std.path, std.stdio, std.string, std.range; struct Tree { @@ -72,6 +72,7 @@ struct Tree ref Tree opIndex(string part) { auto tail = leaves.find!((tr, pkg) => tr.name == pkg)(part); + assert(!tail.empty, part ~ " can't be found."); return tail.front; } @@ -86,17 +87,24 @@ struct Tree Tree[] leaves; } +alias I(alias X) = X; + int main(string[] args) { - if (args.length < 3) + string[] excludes, packages; + + auto prog = getopt(args, + "ex", &excludes, + "dump", &packages, + ); + + if (prog.helpWanted || args.length <= 1) { - stderr.writeln("usage: ./modlist [--ex=std.internal.] [--ex=core.sys.]"); + defaultGetoptPrinter("./modlist ... ", prog.options); return 1; } - auto druntime = args[1]; - auto phobos = args[2]; - auto excludes = args[3 .. $].map!(ex => ex.chompPrefix("--ex=")).array; + auto dirs = args[1 .. $]; bool included(string mod) { @@ -115,15 +123,28 @@ int main(string[] args) tree.insert(name.splitter(".")); } Tree tree; - add(phobos, tree); - add(buildPath(druntime, "src"), tree); + foreach (dir; dirs) + { + // search for common root folders (fallback to the root directory) + ["source", "src", ""] + .map!(f => buildPath(dir, f)) + .filter!exists + .front // no UFCS for local symbols + .I!(name => add(name, tree)); + } + tree.sort(); writeln("MODULE_MENU="); - writeln("$(MENU object.html, $(TT object))"); - tree["std"].dumpRoot(); - tree["etc"].dumpRoot(); - tree["core"].dumpRoot(); + foreach (part; packages) + { + // check whether it's a package or file + auto subTree = tree[part]; + if (subTree.leaves.length) + subTree.dumpRoot; + else + writefln("$(MENU %s.html, $(TT %1$s))", part); + } writeln("_="); return 0; } diff --git a/orgs-using-d.dd b/orgs-using-d.dd index fb71da6e94..ad5eb657b8 100644 --- a/orgs-using-d.dd +++ b/orgs-using-d.dd @@ -100,6 +100,13 @@ $(DIVC orgs-using-d center, $(FA_HIRING www.funkwerk.com/karriere/stellenangebote) ) ) + $(DORG GNEX, https://globalnet-ex.com, gnex.png, + Digital Marketing Solutions Company., + $(LINK_ROW + $(FA_GITHUB gnexltd) $(FA_SEPARATOR) + $(FA_HIRING globalnet-ex.com/employment/engineer) + ) + ) $(DORG Infognition, http://www.infognition.com, infognition.svg, Video processing, $(FA_QUOTE @@ -113,7 +120,7 @@ $(DIVC orgs-using-d center, Science and technology for kids, Large scale use of D for distributed systems and cloud storage. $(LINK_ROW - $(FA_GITHUB putaolabs) $(FA_SEPARATOR) + $(FA_GITHUB huntlabs) $(FA_SEPARATOR) $(FA_HIRING job.oschina.net/position/792_118197_21895) ) ) diff --git a/osmodel.mak b/osmodel.mak new file mode 100644 index 0000000000..04e58669ff --- /dev/null +++ b/osmodel.mak @@ -0,0 +1,53 @@ +# This Makefile snippet detects the OS and the architecture MODEL +# Keep this file in sync between dmd, druntime, phobos, dlang.org and tools +# repositories! + +ifeq (,$(OS)) + uname_S:=$(shell uname -s) + ifeq (Darwin,$(uname_S)) + OS:=osx + endif + ifeq (Linux,$(uname_S)) + OS:=linux + endif + ifeq (FreeBSD,$(uname_S)) + OS:=freebsd + endif + ifeq (OpenBSD,$(uname_S)) + OS:=openbsd + endif + ifeq (Solaris,$(uname_S)) + OS:=solaris + endif + ifeq (SunOS,$(uname_S)) + OS:=solaris + endif + ifeq (,$(OS)) + $(error Unrecognized or unsupported OS for uname: $(uname_S)) + endif +endif + +# When running make from XCode it may set environment var OS=MACOS. +# Adjust it here: +ifeq (MACOS,$(OS)) + OS:=osx +endif + +ifeq (,$(MODEL)) + ifeq ($(OS), solaris) + uname_M:=$(shell isainfo -n) + else + uname_M:=$(shell uname -m) + endif + ifneq (,$(findstring $(uname_M),x86_64 amd64)) + MODEL:=64 + endif + ifneq (,$(findstring $(uname_M),i386 i586 i686)) + MODEL:=32 + endif + ifeq (,$(MODEL)) + $(error Cannot figure 32/64 model from uname -m: $(uname_M)) + endif +endif + +MODEL_FLAG:=-m$(MODEL) diff --git a/posix.mak b/posix.mak index 885e3acd11..bd0271f37e 100644 --- a/posix.mak +++ b/posix.mak @@ -9,30 +9,60 @@ # make -f posix.mak rsync # +include osmodel.mak + # Latest released version ifeq (,${LATEST}) LATEST:=$(shell cat VERSION) endif +# Next major DMD release +NEXT_VERSION:=$(shell bash -c 'version=$$(cat VERSION);a=($${version//./ });a[1]="10\#$${a[1]}";((a[1]++)); a[2]=0; echo $${a[0]}.0$${a[1]}.$${a[2]};' ) -# Externals +# DLang directories DMD_DIR=../dmd PHOBOS_DIR=../phobos DRUNTIME_DIR=../druntime +TOOLS_DIR=../tools +INSTALLER_DIR=../installer DUB_DIR=../dub-${DUB_VER} -DMD=$(DMD_DIR)/src/dmd -DMD_REL=$(DMD_DIR)-${LATEST}/src/dmd + +# External binaries +DMD=$(DMD_DIR)/generated/$(OS)/release/$(MODEL)/dmd DUB=${DUB_DIR}/bin/dub + +# External directories DOC_OUTPUT_DIR:=$(shell pwd)/web GIT_HOME=https://github.com/dlang DPL_DOCS_PATH=dpl-docs DPL_DOCS=$(DPL_DOCS_PATH)/dpl-docs REMOTE_DIR=d-programming@digitalmars.com:data +TMP?=/tmp + +# Last released versions +DMD_STABLE_DIR=${DMD_DIR}-${LATEST} +DMD_REL=$(DMD_STABLE_DIR)/src/dmd +DRUNTIME_STABLE_DIR=${DRUNTIME_DIR}-${LATEST} +PHOBOS_STABLE_DIR=${PHOBOS_DIR}-${LATEST} + +################################################################################ +# Automatically generated directories GENERATED=.generated +PHOBOS_DIR_GENERATED=$(GENERATED)/phobos-prerelease +PHOBOS_STABLE_DIR_GENERATED=$(GENERATED)/phobos-release +# The assert_writeln_magic tool transforms all source files from Phobos. Hence +# - a temporary folder with a copy of Phobos needs to be generated +# - a list of all files in Phobos and the temporary copy is needed to setup proper +# Makefile dependencies and rules +PHOBOS_FILES := $(shell find $(PHOBOS_DIR) -name '*.d' -o -name '*.mak' -o -name '*.ddoc') +PHOBOS_FILES_GENERATED := $(subst $(PHOBOS_DIR), $(PHOBOS_DIR_GENERATED), $(PHOBOS_FILES)) +PHOBOS_STABLE_FILES := $(shell find $(PHOBOS_STABLE_DIR) -name '*.d' -o -name '*.mak' -o -name '*.ddoc') +PHOBOS_STABLE_FILES_GENERATED := $(subst $(PHOBOS_STABLE_DIR), $(PHOBOS_STABLE_DIR_GENERATED), $(PHOBOS_STABLE_FILES)) +################################################################################ # stable dub and dmd versions used to build dpl-docs -DUB_VER=0.9.25 -STABLE_DMD_VER=2.069.2 -STABLE_DMD_ROOT=/tmp/.stable_dmd-$(STABLE_DMD_VER) +DUB_VER=1.1.0 +STABLE_DMD_VER=2.072.2 +STABLE_DMD_ROOT=$(TMP)/.stable_dmd-$(STABLE_DMD_VER) STABLE_DMD_URL=http://downloads.dlang.org/releases/2.x/$(STABLE_DMD_VER)/dmd.$(STABLE_DMD_VER).$(OS).zip STABLE_DMD=$(STABLE_DMD_ROOT)/dmd2/$(OS)/$(if $(filter $(OS),osx),bin,bin$(MODEL))/dmd STABLE_DMD_CONF=$(STABLE_DMD).conf @@ -41,9 +71,10 @@ STABLE_RDMD=$(STABLE_DMD_ROOT)/dmd2/$(OS)/$(if $(filter $(OS),osx),bin,bin$(MODE # exclude lists MOD_EXCLUDES_PRERELEASE=$(addprefix --ex=, gc. rt. core.internal. core.stdc.config core.sys. \ - std.c. std.algorithm.internal std.internal. std.regex.internal. \ - std.windows.iunknown std.windows.registry etc.linux.memoryerror std.stream std.cstream \ - std.socketstream std.experimental.ndslice.internal) + std.algorithm.internal std.c. std.concurrencybase std.internal. std.regex.internal. \ + std.windows.iunknown std.windows.registry etc.linux.memoryerror \ + std.experimental.ndslice.internal std.stdiobase \ + tk. msvc_dmc msvc_lib) MOD_EXCLUDES_RELEASE=$(MOD_EXCLUDES_PRERELEASE) @@ -62,55 +93,22 @@ CHANGE_SUFFIX = \ for f in `find "$3" -iname '*.$1'`; do\ mv $$f `dirname $$f`/`basename $$f .$1`.$2; done -# Set to 1 in the command line to minify css files -CSS_MINIFY= - -# OS and MODEL -OS:= -uname_S:=$(shell uname -s) -ifeq (Darwin,$(uname_S)) - OS:=osx -endif -ifeq (Linux,$(uname_S)) - OS:=linux -endif -ifeq (FreeBSD,$(uname_S)) - OS:=freebsd -endif -ifeq (OpenBSD,$(uname_S)) - OS:=openbsd -endif -ifeq (Solaris,$(uname_S)) - OS:=solaris -endif -ifeq (SunOS,$(uname_S)) - OS:=solaris -endif -ifeq (,$(OS)) - $(error Unrecognized or unsupported OS for uname: $(uname_S)) -endif - -ifeq (,$(MODEL)) - uname_M:=$(shell uname -m) - ifneq (,$(findstring $(uname_M),x86_64 amd64)) - MODEL:=64 - endif - ifneq (,$(findstring $(uname_M),i386 i586 i686)) - MODEL:=32 - endif - ifeq (,$(MODEL)) - $(error Cannot figure 32/64 model from uname -m: $(uname_M)) - endif +# Disable all dynamic content that could potentially have an unrelated impact +# on a diff +ifeq (1,$(DIFFABLE)) + NODATETIME := nodatetime.ddoc + DPL_DOCS_PATH_RUN_FLAGS := --no-exact-source-links +else + CHANGELOG_VERSION_MASTER := "v${LATEST}..upstream/master" + CHANGELOG_VERSION_STABLE := "v${LATEST}..upstream/stable" endif -# Documents +################################################################################ +# Resources +################################################################################ -DDOC=$(addsuffix .ddoc, macros html dlang.org doc ${GENERATED}/${LATEST}) $(NODATETIME) -STD_DDOC=$(addsuffix .ddoc, macros html dlang.org ${GENERATED}/${LATEST} std std_navbar-release ${GENERATED}/modlist-${LATEST}) $(NODATETIME) -STD_DDOC_PRE=$(addsuffix .ddoc, macros html dlang.org ${GENERATED}/${LATEST} std std_navbar-prerelease ${GENERATED}/modlist-prerelease) $(NODATETIME) -SPEC_DDOC=${DDOC} spec/spec.ddoc -CHANGELOG_DDOC=${DDOC} changelog/changelog.ddoc $(NODATETIME) -CHANGELOG_PRE_DDOC=${CHANGELOG_DDOC} changelog/prerelease.ddoc +# Set to 1 in the command line to minify css files +CSS_MINIFY= ORGS_USING_D=$(wildcard images/orgs-using-d/*) IMAGES=favicon.ico $(ORGS_USING_D) $(addprefix images/, \ @@ -134,6 +132,17 @@ JAVASCRIPT=$(addsuffix .js, $(addprefix js/, \ STYLES=$(addsuffix .css, $(addprefix css/, \ style print codemirror ddox)) +################################################################################ +# HTML Files +################################################################################ + +DDOC=$(addsuffix .ddoc, macros html dlang.org doc ${GENERATED}/${LATEST}) $(NODATETIME) +STD_DDOC=$(addsuffix .ddoc, macros html dlang.org ${GENERATED}/${LATEST} std std_navbar-release ${GENERATED}/modlist-${LATEST}) $(NODATETIME) +STD_DDOC_PRE=$(addsuffix .ddoc, macros html dlang.org ${GENERATED}/${LATEST} std std_navbar-prerelease ${GENERATED}/modlist-prerelease) $(NODATETIME) +SPEC_DDOC=${DDOC} spec/spec.ddoc +CHANGELOG_DDOC=${DDOC} changelog/changelog.ddoc $(NODATETIME) +CHANGELOG_PRE_DDOC=${CHANGELOG_DDOC} changelog/prerelease.ddoc + PREMADE=appendices.html articles.html fetch-issue-cnt.php howtos.html \ language-reference.html robots.txt .htaccess .dpl_rewrite_map.txt \ d-keyring.gpg @@ -150,7 +159,8 @@ SPEC_ROOT=$(addprefix spec/, \ abi simd) SPEC_DD=$(addsuffix .dd,$(SPEC_ROOT)) -CHANGELOG_FILES=$(basename $(subst _pre.dd,.dd,$(wildcard changelog/*.dd))) +CHANGELOG_FILES=changelog/${NEXT_VERSION}_pre \ + $(basename $(subst _pre.dd,.dd,$(wildcard changelog/*.dd))) \ # Website root filenames. They have extension .dd in the source # and .html in the generated HTML. Save for the expansion of @@ -175,7 +185,9 @@ $(PREMADE) $(STYLES) $(IMAGES) $(JAVASCRIPT)) ALL_FILES = $(ALL_FILES_BUT_SITEMAP) $(DOC_OUTPUT_DIR)/sitemap.html +################################################################################ # Pattern rulez +################################################################################ # NOTE: Depending on the version of make, order matters here. Therefore, put # sub-directories before their parents. @@ -189,6 +201,9 @@ $(DOC_OUTPUT_DIR)/changelog/%.html : changelog/%_pre.dd $(CHANGELOG_PRE_DDOC) $( $(DOC_OUTPUT_DIR)/spec/%.html : spec/%.dd $(SPEC_DDOC) $(DMD) $(DMD) -c -o- -Df$@ $(SPEC_DDOC) $< +$(DOC_OUTPUT_DIR)/404.html : 404.dd $(DDOC) $(DMD) + $(DMD) -conf= -c -o- -Df$@ $(DDOC) errorpage.ddoc $< + $(DOC_OUTPUT_DIR)/%.html : %.dd $(DDOC) $(DMD) $(DMD) -conf= -c -o- -Df$@ $(DDOC) $< @@ -228,8 +243,8 @@ $(DOC_OUTPUT_DIR)/dmd-%.verbatim : %.ddoc dcompiler.dd verbatim.ddoc $(DMD) all : docs html -docs : dmd-prerelease phobos-prerelease druntime-prerelease druntime-release \ - phobos-release apidocs-release apidocs-prerelease +docs : dmd-release dmd-prerelease phobos-prerelease druntime-prerelease \ + druntime-release phobos-release apidocs-release apidocs-prerelease html : $(ALL_FILES) @@ -252,13 +267,15 @@ ${GENERATED}/${LATEST}.ddoc : mkdir -p $(dir $@) echo "LATEST=${LATEST}" >$@ -${GENERATED}/modlist-${LATEST}.ddoc : modlist.d ${STABLE_DMD} $(DRUNTIME_DIR)-$(LATEST) $(PHOBOS_DIR)-$(LATEST) +${GENERATED}/modlist-${LATEST}.ddoc : modlist.d ${STABLE_DMD} $(DRUNTIME_STABLE_DIR) $(PHOBOS_STABLE_DIR) mkdir -p $(dir $@) - $(STABLE_RDMD) modlist.d $(DRUNTIME_DIR)-$(LATEST) $(PHOBOS_DIR)-$(LATEST) $(MOD_EXCLUDES_RELEASE) >$@ + $(STABLE_RDMD) modlist.d $(DRUNTIME_STABLE_DIR) $(PHOBOS_STABLE_DIR) $(MOD_EXCLUDES_RELEASE) \ + $(addprefix --dump , object std etc core) >$@ ${GENERATED}/modlist-prerelease.ddoc : modlist.d ${STABLE_DMD} $(DRUNTIME_DIR) $(PHOBOS_DIR) mkdir -p $(dir $@) - $(STABLE_RDMD) modlist.d $(DRUNTIME_DIR) $(PHOBOS_DIR) $(MOD_EXCLUDES_PRERELEASE) >$@ + $(STABLE_RDMD) modlist.d $(DRUNTIME_DIR) $(PHOBOS_DIR) $(DMD_DIR) $(MOD_EXCLUDES_PRERELEASE) \ + $(addprefix --dump , object std etc core ddmd) >$@ # Run "make -j rebase" for rebasing all dox in parallel! rebase: rebase-dlang rebase-dmd rebase-druntime rebase-phobos @@ -271,7 +288,7 @@ clean: rm -rf $(DOC_OUTPUT_DIR) ${GENERATED} dpl-docs/.dub rm -rf auto dlangspec-consolidated.d $(addprefix dlangspec,.aux .d .dvi .fdb_latexmk .fls .log .out .pdf .tex .txt .verbatim.txt) rm -f docs.json docs-prerelease.json dpl-docs/dpl-docs - @echo You should issue manually: rm -rf ${DMD_DIR}-${LATEST} ${DRUNTIME_DIR}-${LATEST} ${PHOBOS_DIR}-${LATEST} ${STABLE_DMD_ROOT} ${DUB_DIR} + @echo You should issue manually: rm -rf ${DMD_STABLE_DIR} ${DRUNTIME_STABLE_DIR} ${PHOBOS_STABLE_DIR} ${STABLE_DMD_ROOT} ${DUB_DIR} RSYNC_FILTER=-f 'P /Usage' -f 'P /.dpl_rewrite*' -f 'P /install.sh*' @@ -340,7 +357,7 @@ dlangspec.verbatim.txt : $(DMD) verbatim.ddoc dlangspec-consolidated.d ../%-${DUB_VER} : git clone --depth=1 -b v${DUB_VER} ${GIT_HOME}/$* $@ -${DMD_DIR} ${DRUNTIME_DIR} ${PHOBOS_DIR} : +${DMD_DIR} ${DRUNTIME_DIR} ${PHOBOS_DIR} ${TOOLS_DIR} ${INSTALLER_DIR}: git clone --depth=1 ${GIT_HOME}/$(@F) $@ ################################################################################ @@ -350,13 +367,32 @@ ${DMD_DIR} ${DRUNTIME_DIR} ${PHOBOS_DIR} : $(DMD) : ${DMD_DIR} ${MAKE} --directory=${DMD_DIR}/src -f posix.mak AUTO_BOOTSTRAP=1 -j 4 -$(DMD_REL) : ${DMD_DIR}-${LATEST} - ${MAKE} --directory=${DMD_DIR}-${LATEST}/src -f posix.mak AUTO_BOOTSTRAP=1 -j 4 +$(DMD_REL) : ${DMD_STABLE_DIR} + ${MAKE} --directory=${DMD_STABLE_DIR}/src -f posix.mak AUTO_BOOTSTRAP=1 -j 4 + +dmd-release : $(STD_DDOC) $(DMD_DIR) $(DMD) + $(MAKE) AUTO_BOOTSTRAP=1 --directory=$(DMD_DIR) -f posix.mak -j4 html \ + STDDOC="$(addprefix `pwd`/, $(STD_DDOC))" \ + DOC_OUTPUT_DIR="${DOC_OUTPUT_DIR}/phobos" \ + DOCSRC="$(realpath .)" dmd-prerelease : $(STD_DDOC_PRE) $(DMD_DIR) $(DMD) - $(MAKE) AUTO_BOOTSTRAP=1 --directory=$(DMD_DIR) -f posix.mak html \ - DOCDIR=${DOC_OUTPUT_DIR}/dmd-prerelease \ - DOCFMT="$(addprefix `pwd`/, $(STD_DDOC_PRE))" + $(MAKE) AUTO_BOOTSTRAP=1 --directory=$(DMD_DIR) -f posix.mak -j4 html \ + STDDOC="$(addprefix `pwd`/, $(STD_DDOC_PRE))" \ + DOCSRC="$(realpath .)" \ + DOC_OUTPUT_DIR="${DOC_OUTPUT_DIR}/phobos-prerelease" + +dmd-prerelease-verbatim : $(STD_DDOC_PRE) $(DMD_DIR) \ + ${DOC_OUTPUT_DIR}/phobos-prerelease/mars.verbatim +${DOC_OUTPUT_DIR}/phobos-prerelease/mars.verbatim: verbatim.ddoc + mkdir -p $(dir $@) + $(MAKE) AUTO_BOOTSTRAP=1 --directory=$(DMD_DIR) -f posix.mak -j4 html \ + DOC_OUTPUT_DIR="${DOC_OUTPUT_DIR}/phobos-prerelease-verbatim" \ + STDDOC="`pwd`/verbatim.ddoc" \ + DOCSRC="$(realpath .)" + $(call CHANGE_SUFFIX,html,verbatim,${DOC_OUTPUT_DIR}/phobos-prerelease-verbatim) + mv ${DOC_OUTPUT_DIR}/phobos-prerelease-verbatim/* $(dir $@) + rm -r ${DOC_OUTPUT_DIR}/phobos-prerelease-verbatim ################################################################################ # druntime, latest released build and current build @@ -367,8 +403,8 @@ druntime-prerelease : ${DRUNTIME_DIR} $(DMD) $(STD_DDOC_PRE) DOCDIR=${DOC_OUTPUT_DIR}/phobos-prerelease \ DOCFMT="$(addprefix `pwd`/, $(STD_DDOC_PRE))" -druntime-release : ${DRUNTIME_DIR}-${LATEST} $(DMD_REL) $(STD_DDOC) - ${MAKE} --directory=${DRUNTIME_DIR}-${LATEST} -f posix.mak target doc \ +druntime-release : ${DRUNTIME_STABLE_DIR} $(DMD_REL) $(STD_DDOC) + ${MAKE} --directory=${DRUNTIME_STABLE_DIR} -f posix.mak target doc \ DMD=$(DMD_REL) \ DOCDIR=${DOC_OUTPUT_DIR}/phobos \ DOCFMT="$(addprefix `pwd`/, $(STD_DDOC))" @@ -389,26 +425,41 @@ ${DOC_OUTPUT_DIR}/phobos-prerelease/object.verbatim : $(DMD) ################################################################################ .PHONY: phobos-prerelease -phobos-prerelease : ${PHOBOS_DIR} $(STD_DDOC_PRE) druntime-prerelease - ${MAKE} --directory=${PHOBOS_DIR} -f posix.mak \ +phobos-prerelease : ${PHOBOS_FILES_GENERATED} $(STD_DDOC_PRE) druntime-prerelease + ${MAKE} --directory=${PHOBOS_DIR_GENERATED} -f posix.mak \ STDDOC="$(addprefix `pwd`/, $(STD_DDOC_PRE))" \ - DOC_OUTPUT_DIR=${DOC_OUTPUT_DIR}/phobos-prerelease html -j 4 - -phobos-release : ${PHOBOS_DIR}-${LATEST} $(DMD_REL) $(STD_DDOC) \ + DOC_OUTPUT_DIR="${DOC_OUTPUT_DIR}/phobos-prerelease" \ + DRUNTIME_PATH="$(realpath ${DRUNTIME_DIR})" \ + DMD="$(realpath ${DMD})" \ + DOCSRC="$(realpath .)" \ + VERSION="$(realpath ${DMD_DIR}/VERSION)" \ + html -j4 + +phobos-release : ${PHOBOS_STABLE_FILES_GENERATED} $(DMD_REL) $(STD_DDOC) \ druntime-release - ${MAKE} --directory=${PHOBOS_DIR}-${LATEST} -f posix.mak -j 4 \ - html \ + ${MAKE} --directory=${PHOBOS_STABLE_DIR_GENERATED} -f posix.mak \ DMD=$(DMD_REL) \ - DRUNTIME_PATH=${DRUNTIME_DIR}-${LATEST} \ + DRUNTIME_PATH=${DRUNTIME_STABLE_DIR} \ DOC_OUTPUT_DIR=${DOC_OUTPUT_DIR}/phobos \ - STDDOC="$(addprefix `pwd`/, $(STD_DDOC))" - -phobos-prerelease-verbatim : ${PHOBOS_DIR} ${DOC_OUTPUT_DIR}/phobos-prerelease/index.verbatim + STDDOC="$(addprefix `pwd`/, $(STD_DDOC))" \ + DRUNTIME_PATH="$(realpath ${DRUNTIME_DIR})" \ + DMD="$(realpath ${DMD})" \ + DOCSRC="$(realpath .)" \ + VERSION="$(realpath ${DMD_DIR}/VERSION)" \ + html -j4 + +phobos-prerelease-verbatim : ${PHOBOS_FILES_GENERATED} ${DOC_OUTPUT_DIR}/phobos-prerelease/index.verbatim ${DOC_OUTPUT_DIR}/phobos-prerelease/index.verbatim : verbatim.ddoc \ - ${DOC_OUTPUT_DIR}/phobos-prerelease/object.verbatim - ${MAKE} --directory=${PHOBOS_DIR} -f posix.mak \ + ${DOC_OUTPUT_DIR}/phobos-prerelease/object.verbatim \ + ${DOC_OUTPUT_DIR}/phobos-prerelease/mars.verbatim + ${MAKE} --directory=${PHOBOS_DIR_GENERATED} -f posix.mak \ STDDOC="`pwd`/verbatim.ddoc" \ - DOC_OUTPUT_DIR=${DOC_OUTPUT_DIR}/phobos-prerelease-verbatim html -j 4 + DOC_OUTPUT_DIR=${DOC_OUTPUT_DIR}/phobos-prerelease-verbatim \ + DRUNTIME_PATH="$(realpath ${DRUNTIME_DIR})" \ + DMD="$(realpath ${DMD})" \ + DOCSRC="$(realpath .)" \ + VERSION="$(realpath ${DMD_DIR}/VERSION)" \ + html -j4 $(call CHANGE_SUFFIX,html,verbatim,${DOC_OUTPUT_DIR}/phobos-prerelease-verbatim) mv ${DOC_OUTPUT_DIR}/phobos-prerelease-verbatim/* $(dir $@) rm -r ${DOC_OUTPUT_DIR}/phobos-prerelease-verbatim @@ -428,13 +479,15 @@ ${DOC_OUTPUT_DIR}/library-prerelease/sitemap.xml : docs-prerelease.json @mkdir -p $(dir $@) ${DPL_DOCS} generate-html --file-name-style=lowerUnderscored --std-macros=html.ddoc --std-macros=dlang.org.ddoc --std-macros=std.ddoc --std-macros=macros.ddoc --std-macros=std-ddox.ddoc \ --override-macros=std-ddox-override.ddoc --package-order=std \ - --git-target=master docs-prerelease.json ${DOC_OUTPUT_DIR}/library-prerelease + --git-target=master $(DPL_DOCS_PATH_RUN_FLAGS) \ + docs-prerelease.json ${DOC_OUTPUT_DIR}/library-prerelease ${DOC_OUTPUT_DIR}/library/sitemap.xml : docs.json @mkdir -p $(dir $@) ${DPL_DOCS} generate-html --file-name-style=lowerUnderscored --std-macros=html.ddoc --std-macros=dlang.org.ddoc --std-macros=std.ddoc --std-macros=macros.ddoc --std-macros=std-ddox.ddoc \ --override-macros=std-ddox-override.ddoc --package-order=std \ - --git-target=v${LATEST} docs.json ${DOC_OUTPUT_DIR}/library + --git-target=v${LATEST} $(DPL_DOCS_PATH_RUN_FLAGS) \ + docs.json ${DOC_OUTPUT_DIR}/library ${DOC_OUTPUT_DIR}/library/.htaccess : dpl_release_htaccess @mkdir -p $(dir $@) @@ -444,26 +497,40 @@ ${DOC_OUTPUT_DIR}/library-prerelease/.htaccess : dpl_prerelease_htaccess @mkdir -p $(dir $@) cp $< $@ -docs.json : ${DMD_REL} ${DRUNTIME_DIR}-${LATEST} \ - ${PHOBOS_DIR}-${LATEST} | dpl-docs - find ${DRUNTIME_DIR}-${LATEST}/src -name '*.d' | \ +DMD_EXCLUDE = +ifeq (osx,$(OS)) + DMD_EXCLUDE += -e /scanelf/d -e /libelf/d +else + DMD_EXCLUDE += -e /scanmach/d -e /libmach/d +endif + +docs.json : ${DMD_REL} ${DRUNTIME_STABLE_DIR} \ + ${PHOBOS_STABLE_FILES_GENERATED} | dpl-docs + find ${DRUNTIME_STABLE_DIR}/src -name '*.d' | \ sed -e /unittest.d/d -e /gcstub/d > .release-files.txt - find ${PHOBOS_DIR}-${LATEST} -name '*.d' | \ + find ${PHOBOS_STABLE_DIR_GENERATED} -name '*.d' | \ sed -e /unittest.d/d -e /windows/d | sort >> .release-files.txt ${DMD_REL} -c -o- -version=CoreDdoc -version=StdDdoc -Df.release-dummy.html \ - -Xfdocs.json -I${PHOBOS_DIR}-${LATEST} @.release-files.txt + -Xfdocs.json -I${PHOBOS_STABLE_DIR_GENERATED} @.release-files.txt ${DPL_DOCS} filter docs.json --min-protection=Protected \ --only-documented $(MOD_EXCLUDES_PRERELEASE) rm .release-files.txt .release-dummy.html -docs-prerelease.json : ${DMD} ${DRUNTIME_DIR} \ - ${PHOBOS_DIR} | dpl-docs +# DDox tries to generate the docs for all `.d` files. However for dmd this is tricky, +# because the `{mach, elf, mscoff}` are platform dependent. +# Thus the need to exclude these files (and the `objc.d` files). +docs-prerelease.json : ${DMD} ${DMD_DIR} ${DRUNTIME_DIR} \ + ${PHOBOS_FILES_GENERATED} | dpl-docs + find ${DMD_DIR}/src -name '*.d' | \ + sed -e /objc.d/d -e /mscoff/d -e /objc_glue.d/d ${DMD_EXCLUDE} \ + > .prerelease-files.txt find ${DRUNTIME_DIR}/src -name '*.d' | sed -e '/gcstub/d' \ - -e /unittest/d > .prerelease-files.txt - find ${PHOBOS_DIR} -name '*.d' | sed -e /unittest.d/d \ + -e /unittest/d >> .prerelease-files.txt + find ${PHOBOS_DIR_GENERATED} -name '*.d' | sed -e /unittest.d/d \ -e /windows/d | sort >> .prerelease-files.txt - ${DMD} -c -o- -version=CoreDdoc -version=StdDdoc -Df.prerelease-dummy.html \ - -Xfdocs-prerelease.json -I${PHOBOS_DIR} @.prerelease-files.txt + ${DMD} -J$(DMD_DIR)/res -J$(dir $(DMD)) -c -o- -version=MARS -version=CoreDdoc \ + -version=StdDdoc -Df.prerelease-dummy.html \ + -Xfdocs-prerelease.json -I${PHOBOS_DIR_GENERATED} @.prerelease-files.txt ${DPL_DOCS} filter docs-prerelease.json --min-protection=Protected \ --only-documented $(MOD_EXCLUDES_RELEASE) rm .prerelease-files.txt .prerelease-dummy.html @@ -507,6 +574,35 @@ chm-nav.json : $(DDOC) std.ddoc spec/spec.ddoc ${GENERATED}/modlist-${LATEST}.dd d.tag : chmgen.d $(STABLE_DMD) $(ALL_FILES) phobos-release druntime-release $(STABLE_RDMD) chmgen.d --root=$(DOC_OUTPUT_DIR) --only-tags +################################################################################ +# Assert -> writeln magic +# ----------------------- +# +# - This transforms assert(a = b) to writeln(a); // b +# - It creates a copy of Phobos to apply the transformations +# - All "d" files are piped through the transformator, +# other needed files (e.g. posix.mak) get copied over +################################################################################ + +ASSERT_WRITELN_BIN = $(GENERATED)/assert_writeln_magic + +$(ASSERT_WRITELN_BIN): assert_writeln_magic.d $(DUB) + @mkdir -p $(dir $@) + $(DUB) build --single --compiler=$(STABLE_DMD) $< + @mv ./assert_writeln_magic $@ + +$(PHOBOS_FILES_GENERATED): $(PHOBOS_DIR_GENERATED)/%: $(PHOBOS_DIR)/% $(DUB) $(ASSERT_WRITELN_BIN) + @mkdir -p $(dir $@) + @if [ $(subst .,, $(suffix $@)) == "d" ] && [ "$@" != "$(PHOBOS_DIR_GENERATED)/index.d" ] ; then \ + $(ASSERT_WRITELN_BIN) -i $< -o $@ ; \ + else cp $< $@ ; fi + +$(PHOBOS_STABLE_FILES_GENERATED): $(PHOBOS_STABLE_DIR_GENERATED)/%: $(PHOBOS_STABLE_DIR)/% $(DUB) $(ASSERT_WRITELN_BIN) + @mkdir -p $(dir $@) + @if [ $(subst .,, $(suffix $@)) == "d" ] && [ "$@" != "$(PHOBOS_STABLE_DIR_GENERATED)/index.d" ] ; then \ + $(ASSERT_WRITELN_BIN) -i $< -o $@ ; \ + else cp $< $@ ; fi + ################################################################################ # Style tests ################################################################################ @@ -519,7 +615,15 @@ test: # Changelog generation ################################################################################ -pending_changelog: - @echo "This command will be available soon." +changelog/${NEXT_VERSION}_pre.dd: ${STABLE_DMD} ../tools ../installer + $(STABLE_RDMD) $(TOOLS_DIR)/changed.d $(CHANGELOG_VERSION_MASTER) -o $@ \ + --version "${NEXT_VERSION} (upcoming)" --date "To be released" --nightly + +changelog/${NEXT_VERSION}.dd: ${STABLE_DMD} ../tools ../installer + $(STABLE_RDMD) $(TOOLS_DIR)/changed.d $(CHANGELOG_VERSION_STABLE) -o $@ \ + --version "${NEXT_VERSION}" + +pending_changelog: changelog/${NEXT_VERSION}.dd html + @echo "Please open file:///$(shell pwd)/web/changelog/${NEXT_VERSION}_pre.html in your browser" .DELETE_ON_ERROR: # GNU Make directive (delete output files on error) diff --git a/safed.dd b/safed.dd index 174a030a35..dcc3a73102 100644 --- a/safed.dd +++ b/safed.dd @@ -13,7 +13,7 @@ $(D_S SafeD—The Safe Subset of D, ) $(P - The universal reason I've heard from the turncoats was $(DOUBLEQUOTE productivity.) The consensus seems to be that programmers are more productive using Java, C#, Ruby, or Python then they are using C++. + The universal reason I've heard from the turncoats was $(DOUBLEQUOTE productivity.) The consensus seems to be that programmers are more productive using Java, C#, Ruby, or Python than they are using C++. ) $(P @@ -128,7 +128,7 @@ printf (format); ) $(P - Let's talk about pointers some more. Every memory allocation returns a valid pointer (unless the program runs out of memory). You might think that dereferencing such a pointer would be safe. That is correct as long as your program doesn't free the allocated memory thus ending the lifetime of the object. After that, you are dealing with a dangling pointer and all bets are off. Again, C Standard is pretty upfront about it. + Let's talk about pointers some more. Every memory allocation returns a valid pointer (unless the program runs out of memory). You might think that dereferencing such a pointer would be safe. That is correct as long as your program doesn't free the allocated memory thus ending the lifetime of the object. After that, you are dealing with a dangling pointer and all bets are off. Again, the C Standard is pretty upfront about it. )
@@ -160,7 +160,7 @@ std:cout << "Hello World!" << std::endl; ) ) $(P - Whereas pointers were important in C, C++ embraced them as the main vehicle for the Standard Library. STL algorithms use iterators, objects that are either pointers themselves or imitate the behavior (and the pitfalls) of pointers. Just like with pointers, a programmer's error in using iterators leads to undefined behavior (see the $(CODE swap_range) example). + Whereas pointers were important in C, C++ embraced them as the main vehicle for the Standard Library. STL algorithms use iterators, objects that are either pointers themselves or imitate the behavior (and the pitfalls) of pointers. Just like with pointers, a programmer's error in using iterators leads to undefined behavior (see the $(CODE swap_ranges) example). ) $(P @@ -189,14 +189,14 @@ writeln("Hello Safe World!"); --- $(P - The function $(CODE writeln) is the equivalent of the C $(CODE printf) (more precisely, it's the representative of a family of output functions including $(CODE write) and its formatting versions, $(CODE writef) and $(CODE writefln)). Just like $(CODE printf), $(CODE writeln) accepts a variable number of arguments of arbitrary types. But here the similarity ends. As long as you pass SafeD-arguments to $(CODE writeln), you are guaranteed not to encounter any undefined behavior. Here, $(CODE writeln) is called with a single argument of the type $(CODE string). In contrast to C, D $(CODE string) is not a pointer. It is an array of $(CODE immutable char), and arrays are a built into the safe subset of D. + The function $(CODE writeln) is the equivalent of the C $(CODE printf) (more precisely, it's the representative of a family of output functions including $(CODE write) and its formatting versions, $(CODE writef) and $(CODE writefln)). Just like $(CODE printf), $(CODE writeln) accepts a variable number of arguments of arbitrary types. But here the similarity ends. As long as you pass SafeD-arguments to $(CODE writeln), you are guaranteed not to encounter any undefined behavior. Here, $(CODE writeln) is called with a single argument of the type $(CODE string). In contrast to C, a D $(CODE string) is not a pointer. It is an array of $(CODE immutable char), and arrays are built into the safe subset of D. ) $(P You might be interested to know how the safety of $(CODE writeln) is accomplished in D. One possible approach would have been to make $(CODE writeln) a compiler intrinsic, so that correct code would be generated on a case-by-case basis. The beauty of D is that it gives a sophisticated programmer tools that allow such case-by-case code generation of code. The advanced features used in the implementation of writeln are: $(UL $(LI Compile-time code generation using templates, and) - $(LI A safe mechanism for dealing with variable number of arguments using tuples.) + $(LI A safe mechanism for dealing with a variable number of arguments using tuples.) ) ) @@ -208,11 +208,11 @@ $(SECTION2 SafeD Libraries, ) $(P - A lot of advanced features of D are compatible with SafeD, as long as they don't force the user to use unsafe types. For instance, a library may provide the implementation of a generic list. The list can be instantiated with any type, in particular with a pointer type. A list of pointers, by definition, cannot be safe, because pointer arithmetic is unsound. However, a list of ints or class objects can and should be safe. That's why such ageneric lists can be used in SafeD, even though their usage outside of SafeD may be unsafe. + A lot of advanced features of D are compatible with SafeD, as long as they don't force the user to use unsafe types. For instance, a library may provide the implementation of a generic list. The list can be instantiated with any type, in particular with a pointer type. A list of pointers, by definition, cannot be safe, because pointer arithmetic is unsound. However, a list of ints or class objects can and should be safe. That's why such generic lists can be used in SafeD, even though their usage outside of SafeD may be unsafe. ) $(P - Moreover, it might be more efficient to base the internal implementation of a list on pointers. As long as these pointers are not exposed to the client, such an implementation might be certified to be SafeD compatible1 . You can have a cake (advanced features of D) and eat it too (take advantage of them in SafeD). + Moreover, it might be more efficient to base the internal implementation of a list on pointers. As long as these pointers are not exposed to the client, such an implementation might be certified to be SafeD compatible1. You can have a cake (advanced features of D) and eat it too (take advantage of them in SafeD). ) ) diff --git a/spec/hash-map.dd b/spec/hash-map.dd index f27753df00..2facff429f 100644 --- a/spec/hash-map.dd +++ b/spec/hash-map.dd @@ -341,7 +341,11 @@ Properties for associative arrays are: ForeachStatement) which will iterate over key-value pairs of the associative array. The returned pairs are represented by an opaque type with $(D .key) and $(D .value) properties for accessing the key and - value of the pair, respectively.)) + value of the pair, respectively. Note that this is a low-level + interface to iterating over the associative array and is not compatible + with the $(LINK2 $(ROOT_DIR)phobos/std_typecons.html#.Tuple,`Tuple`) + type in Phobos. For compatibility with `Tuple`, use + $(LINK2 $(ROOT_DIR)phobos/std_array.html#.byPair,std.array.byPair) instead.)) $(TROW $(D .get(Key key, lazy Value defVal)), $(ARGS Looks up $(D key); if it exists returns corresponding value else evaluates and returns $(D defVal).)) diff --git a/spec/module.dd b/spec/module.dd index 547cb3469e..3efab02bc1 100644 --- a/spec/module.dd +++ b/spec/module.dd @@ -549,18 +549,19 @@ $(H3 $(LNAME2 override_cycle_abort, Overriding Cycle Detection Abort)) ) $(OL - $(LI `deprecate` The default behavior. This functions just like `abort`, - but will use the pre-2.072 algorithm to determine if the cycle was - undetected. If so, the old algorithm is used, but a deprecation - message is printed. After 2.073, the `abort` option will be the default.) - $(LI `abort` The normal behavior as described in the previous section. - After 2.073, this will be the default behavior.) + $(LI `abort` The default behavior. The normal behavior as described + in the previous section) + $(LI `deprecate` This functions just like `abort`, but upon cycle + detection the runtime will use a flawed pre-2.072 algorithm to + determine if the cycle was previously detected. If no cycles are + detected in the old algorithm, execution continues, but a + deprecation message is printed.) $(LI `print` Print all cycles detected, but do not abort execution. - Order of static construction is implementation defined, and not - guaranteed to be valid.) - $(LI `ignore` Do not abort execution or print any cycles. Order of - static construction is implementation defined, and not guaranteed - to be valid.) + When cycles are present, order of static construction is + implementation defined, and not guaranteed to be valid.) + $(LI `ignore` Do not abort execution or print any cycles. When + cycles are present, order of static construction is implementation + defined, and not guaranteed to be valid.) ) $(H3 $(LNAME2 order_of_static_ctors, Order of Static Construction within a Module)) diff --git a/spec/version.dd b/spec/version.dd index 5964007d45..e5550068c2 100644 --- a/spec/version.dd +++ b/spec/version.dd @@ -279,6 +279,8 @@ $(H3 $(LEGACY_LNAME2 PredefinedVersions, predefined-versions, Predefined Version $(TROW $(ARGS $(D MIPS_HardFloat)) , $(ARGS The MIPS $(D hard-float) ABI)) $(TROW $(ARGS $(D NVPTX)) , $(ARGS The Nvidia Parallel Thread Execution (PTX) architecture, 32-bit)) $(TROW $(ARGS $(D NVPTX64)) , $(ARGS The Nvidia Parallel Thread Execution (PTX) architecture, 64-bit)) + $(TROW $(ARGS $(D RISCV32)) , $(ARGS The RISC-V architecture, 32-bit)) + $(TROW $(ARGS $(D RISCV64)) , $(ARGS The RISC-V architecture, 64-bit)) $(TROW $(ARGS $(D SPARC)) , $(ARGS The SPARC architecture, 32-bit)) $(TROW $(ARGS $(D SPARC_V8Plus)) , $(ARGS The SPARC v8+ ABI)) $(TROW $(ARGS $(D SPARC_SoftFloat)) , $(ARGS The SPARC soft float ABI)) diff --git a/std-ddox.ddoc b/std-ddox.ddoc index a2e3230bb1..5129a2961f 100644 --- a/std-ddox.ddoc +++ b/std-ddox.ddoc @@ -9,4 +9,5 @@ REF_ALTTEXT=$(DDOX_NAMED_REF $(REF_HELPER $+), $1) MREF_HELPER=$1$(DOT_PREFIXED $+) MREF=$(D $(MREF_HELPER $1, $+)) MREF_ALTTEXT=$(DDOX_NAMED_REF $(MREF_HELPER $+), $1) +DDOX_UNITTEST_HEADER= _= diff --git a/std_navbar-release.ddoc b/std_navbar-release.ddoc index 7899a22e2c..3712f926fe 100644 --- a/std_navbar-release.ddoc +++ b/std_navbar-release.ddoc @@ -13,3 +13,4 @@ $(SUBNAV_TEMPLATE $(UL $(MODULE_MENU)) ) _= +EXTRA_FOOTERS=$(SCRIPTLOAD $(STATIC js/run_examples.js))