1
0
Эх сурвалжийг харах

Added some crap for the node builder

Caleb James DeLisle 10 жил өмнө
parent
commit
5a411fa1a3

+ 0 - 0
dht/dhtcore/Link.h


+ 1 - 1
exception/Except.h

@@ -34,7 +34,7 @@ struct Except
 Gcc_NORETURN
 Gcc_PRINTF(4, 5)
 void Except__throw(char* file, int line, struct Except* eh, char* format, ...);
-#define Except_throw(...) Except__throw(__FILE__, __LINE__, __VA_ARGS__)
+#define Except_throw(...) Except__throw(Gcc_SHORT_FILE, Gcc_LINE, __VA_ARGS__)
 
 
 #endif

+ 9 - 8
memory/Allocator.h

@@ -16,6 +16,7 @@
 #define Allocator_H
 
 #include "util/Identity.h"
+#include "util/Gcc.h"
 #include "util/Linker.h"
 Linker_require("memory/Allocator.c")
 
@@ -152,7 +153,7 @@ void* Allocator__malloc(struct Allocator* allocator,
                         unsigned long length,
                         const char* fileName,
                         int lineNum);
-#define Allocator_malloc(a, b) Allocator__malloc((a),(b),__FILE__,__LINE__)
+#define Allocator_malloc(a, b) Allocator__malloc((a),(b),Gcc_SHORT_FILE,Gcc_LINE)
 
 /**
  * Allocate some memory from this memory allocator.
@@ -171,7 +172,7 @@ void* Allocator__calloc(struct Allocator* alloc,
                         unsigned long count,
                         const char* fileName,
                         int lineNum);
-#define Allocator_calloc(a, b, c) Allocator__calloc((a),(b),(c),__FILE__,__LINE__)
+#define Allocator_calloc(a, b, c) Allocator__calloc((a),(b),(c),Gcc_SHORT_FILE,Gcc_LINE)
 
 /**
  * Re-allocate memory so that an allocation can be expanded.
@@ -192,7 +193,7 @@ void* Allocator__realloc(struct Allocator* allocator,
                          unsigned long size,
                          const char* fileName,
                          int lineNum);
-#define Allocator_realloc(a, b, c) Allocator__realloc((a),(b),(c),__FILE__,__LINE__)
+#define Allocator_realloc(a, b, c) Allocator__realloc((a),(b),(c),Gcc_SHORT_FILE,Gcc_LINE)
 
 /**
  * Allocate some memory and copy something into that memory space.
@@ -210,7 +211,7 @@ void* Allocator__clone(struct Allocator* allocator,
                        unsigned long length,
                        const char* fileName,
                        int lineNum);
-#define Allocator_clone(a, b) Allocator__clone((a),(b),sizeof(*(b)),__FILE__,__LINE__)
+#define Allocator_clone(a, b) Allocator__clone((a),(b),sizeof(*(b)),Gcc_SHORT_FILE,Gcc_LINE)
 
 /**
  * Spawn a new child of this allocator.
@@ -221,7 +222,7 @@ void* Allocator__clone(struct Allocator* allocator,
  * @return a child allocator.
  */
 struct Allocator* Allocator__child(struct Allocator* alloc, const char* fileName, int lineNum);
-#define Allocator_child(a) Allocator__child((a),__FILE__,__LINE__)
+#define Allocator_child(a) Allocator__child((a),Gcc_SHORT_FILE,Gcc_LINE)
 
 /**
  * Sever the link between an allocator and it's original parent.
@@ -232,7 +233,7 @@ struct Allocator* Allocator__child(struct Allocator* alloc, const char* fileName
  * @param alloc the allocator to disconnect from it's parent.
  */
 void Allocator__free(struct Allocator* alloc, const char* file, int line);
-#define Allocator_free(a) Allocator__free((a),__FILE__,__LINE__)
+#define Allocator_free(a) Allocator__free((a),Gcc_SHORT_FILE,Gcc_LINE)
 
 /**
  * Add a function to be called when the allocator is freed.
@@ -246,7 +247,7 @@ struct Allocator_OnFreeJob* Allocator__onFree(struct Allocator* alloc,
                                               void* context,
                                               const char* file,
                                               int line);
-#define Allocator_onFree(a, b, c) Allocator__onFree((a), (b), (c), __FILE__, __LINE__)
+#define Allocator_onFree(a, b, c) Allocator__onFree((a), (b), (c), Gcc_SHORT_FILE, Gcc_LINE)
 
 /**
  * Remove a function which was registered with Allocator_onFree().
@@ -293,7 +294,7 @@ void Allocator__adopt(struct Allocator* parentAlloc,
                       struct Allocator* alloc,
                       const char* fileName,
                       int lineNum);
-#define Allocator_adopt(a, b) Allocator__adopt((a),(b),__FILE__,__LINE__)
+#define Allocator_adopt(a, b) Allocator__adopt((a),(b),Gcc_SHORT_FILE,Gcc_LINE)
 
 /**
  * Set the heap protection canary for the next child allocator.

+ 2 - 1
memory/BufferAllocator.h

@@ -17,6 +17,7 @@
 
 #include "memory/Allocator.h"
 #include "util/UniqueName.h"
+#include "util/Gcc.h"
 #include "util/Linker.h"
 Linker_require("memory/BufferAllocator.c")
 
@@ -35,7 +36,7 @@ struct Allocator* BufferAllocator__new(void* buffer,
                                        char* file,
                                        int line);
 
-#define BufferAllocator_new(a,b) BufferAllocator__new((a),(b),__FILE__,__LINE__)
+#define BufferAllocator_new(a,b) BufferAllocator__new((a),(b),Gcc_SHORT_FILE,Gcc_LINE)
 
 // This relies on the fact that UniqueName is only unique on a per-line basis.
 #define BufferAllocator_STACK(name, length) \

+ 2 - 1
memory/MallocAllocator.h

@@ -16,6 +16,7 @@
 #define MallocAllocator_H
 
 #include "memory/Allocator.h"
+#include "util/Gcc.h"
 #include "util/Linker.h"
 Linker_require("memory/MallocAllocator.c")
 
@@ -27,6 +28,6 @@ Linker_require("memory/MallocAllocator.c")
  *                  will be halted with an error.
  */
 struct Allocator* MallocAllocator__new(unsigned long sizeLimit, const char* file, int line);
-#define MallocAllocator_new(sl) MallocAllocator__new((sl),__FILE__,__LINE__)
+#define MallocAllocator_new(sl) MallocAllocator__new((sl),Gcc_SHORT_FILE,Gcc_LINE)
 
 #endif

+ 245 - 0
node_build/Codestyle.js

@@ -0,0 +1,245 @@
+/* vim: set expandtab ts=4 sw=4: */
+/*
+ * You may redistribute this program and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+var Fs = require('fs');
+var nThen = require('nthen');
+var Child = require('child_process');
+
+var headerLines;
+
+var parseFile = function (fileName, fileContent) {
+    var output = '';
+    var parenthCount = 0;
+    var functionParenthCount = 0;
+    var expectBracket = 0;
+    var name = fileName.replace(/^.*\//, '').replace(/\..*$/,'');
+
+    var lines = fileContent.split('\n');
+    for (var lineNum = 0; lineNum < lines.length; lineNum++) {
+        var line = lines[lineNum];
+
+        // switch to 1 indexing for human readability
+        var lineInfo = fileName + ":" + (lineNum+1);
+        var ignore = false;
+
+        var error = function(msg) {
+            if (!ignore) {
+                output += lineInfo + '  ' + msg + '\n';
+            }
+        };
+
+        if (lineNum < headerLines.length) {
+            var expectedLine = headerLines[lineNum];
+            if (line !== headerLines[lineNum]) {
+                error("missing header\n" + expectedLine + "\n" + line);
+            }
+        } else if (/\.h$/.test(fileName) && lineNum < headerLines + 1) {
+            if (line !== '#ifndef ' + name + "_H") {
+                error("expected #ifndef " + name + "_H found " + line);
+            }
+        } else if (/\.h$/.test(fileName) && lineNum < headerLines + 3) {
+            if (line !== '#define ' + name + "_H") {
+                error("expected #define " + name + "_H found " + line);
+            }
+        }
+
+        ignore = /CHECKFILES_IGNORE/.test(line);
+
+        if (expectBracket == 1) {
+            expectBracket = 0;
+            if (!(/^[\s]*{/.test(line))) {
+                error("expecting a { bracket " + line);
+            }
+        }
+
+        if (!(/_test/.test(fileName))) {
+            // implementations..  TUNConfigurator_Linux contains TUNConfigurator_doStuff...
+            var n = name.replace(/_.*/, '');
+            if ((/^\w+\s.*\(/).test(line)) {
+                if (!(/^int main\(/.test(line)
+                    || line.indexOf(' '+n) > -1
+                    || /^[ ]?static /.test(line)))
+                {
+                    error("all globally visible functions must begin with the name of the file.");
+                }
+            }
+        }
+
+        var matches;
+        if (functionParenthCount === 0) {
+            matches = /^\w+\s.*(\(.*)$/.exec(line);
+        }
+        if (functionParenthCount > 0 || matches) {
+            var txt = (functionParenthCount > 0) ? line : matches[1];
+            functionParenthCount += (txt.match(/\(/g)||[]).length;
+            functionParenthCount -= (txt.match(/\)/g)||[]).length;
+            if (functionParenthCount === 0) {
+                txt = txt.substring(txt.lastIndexOf(')') + 1);
+                if (/{/.test(txt)) {
+                    error("please put the opening bracket on the next line.");
+                }
+            }
+        }
+
+        if (/[\w]*int[\w]*\s+\*+\w/.test(line) || /[\w]*struct\s+[\w]+\s+\*+\w/.test(line)) {
+            error("int* blah; means int pointer named blah, int *blah; means int names splatblah");
+        }
+
+        if (line.length > 100) {
+            error("cjd's editor window is only 100 characters wide");
+        }
+
+        if (/\.h$/.test(fileName) && fileName.indexOf('util/platform/libc/') === -1) {
+
+            // If the name is CryptoAuth_pvt.h, it's ok to make a structure called CryptoAuth
+            var n = name.replace(/_pvt$/, '').replace(/_impl$/, '');
+
+            if (/^struct /.test(line) && line.indexOf('struct ' + n) !== 0 && !(/\(/.test(line))) {
+                error("all structures must begin with the name of the file.");
+            }
+
+            if (/#define /.test(line) && line.indexOf('#define ' + n) === -1) {
+                error("all defines must begin with the name of the file.");
+            }
+        }
+        if (/\t/.test(line)) {
+            error("tabs are not allowed, use 4 spaces.");
+        }
+
+        if (/\s$/.test(line)) {
+            error("trailing whitespace.");
+        }
+
+        if (/(if|for|while)\(/.test(line)) {
+            error("If/for/while statements must be followed by whitespace.");
+        }
+
+        matches = null;
+        if (parenthCount === 0) {
+            matches = /[^\w#](if|for|while) (\(.*$)/.exec(line);
+        }
+        if (parenthCount > 0 || matches) {
+            var txt = (parenthCount > 0) ? line : matches[2];
+            parenthCount += (txt.match(/\(/g)||[]).length;
+            parenthCount -= (txt.match(/\)/g)||[]).length;
+            if (parenthCount == 0) {
+                txt = txt.substring(txt.lastIndexOf(')') + 1);
+                // for (x; y; z) ;         <-- ok
+                // for (x; y; z) {         <-- ok
+                // for (x; y; z) {   \     <-- ok (in preprocessor macro)
+                // for (x; y; z)           <-- ok but you better put a bracket on the next line
+                // for (x; y; z) { j++; }  <-- ok
+                // for (x; y; z) j++;      <-- BZZZZZZZZZZT
+                if (!(/^[\s]*[;{].*$/.test(txt)) && !(/^[\s]+{[\s]*\\$/).test(txt)) {
+                    if (/[\s]*$/.test(txt)) {
+                        expectBracket = 1;
+                    } else {
+                        error(parenthCount + '  ' + line);
+                    }
+                }
+            }
+        }
+    }
+    return output;
+};
+
+var checkFile = function (file, callback) {
+    if (!(/.*(\.c|\.h)$/.test(file))) {
+        callback('');
+        return;
+    }
+    Fs.readFile(file, function (err, ret) {
+        if (err) { throw err; }
+        callback(parseFile(file, ret.toString()));
+    });
+};
+
+var main = function (dir, runInFork, callback) {
+
+    var gitIgnoreLines;
+
+    if (runInFork) {
+        var err = '';
+        var out = '';
+        var proc = Child.spawn(process.execPath, [__filename]);
+        proc.stdout.on('data', function (data) { err += data.toString('utf8') });
+        proc.stderr.on('data', function (data) { err += data.toString('utf8') });
+        proc.on('close', function (ret) {
+            out += err;
+            var error;
+            if (ret !== 0) { error = new Error(out); }
+            callback(error, out);
+        });
+        return;
+    }
+
+    var output = '';
+    nThen(function (waitFor) {
+
+        Fs.readFile(__filename, waitFor(function (err, ret) {
+            if (err) { throw err; }
+            var lines = ret.toString('utf8').split('\n');
+            headerLines = lines.slice(0, lines.indexOf(' */') + 1);
+        }));
+
+        Fs.readFile('.gitignore', waitFor(function (err, ret) {
+            if (err) { throw err; }
+            gitIgnoreLines = ret.toString('utf8').split('\n');
+        }))
+
+    }).nThen(function (waitFor) {
+
+        var addDir = function (dir) {
+            Fs.readdir(dir, waitFor(function (err, files) {
+                if (err) { throw err; }
+                files.forEach(function (file) {
+                    Fs.stat(dir + '/' + file, waitFor(function (err, stat) {
+                        if (err) { throw err; }
+                        if (file === '.git') {
+                        } else if (file === 'contrib') {
+                        } else if (gitIgnoreLines.indexOf(file) !== -1) {
+                        } else {
+                            if (stat.isDirectory()) {
+                                addDir(dir + '/' + file);
+                            } else {
+                                checkFile(dir + '/' + file, waitFor(function (ret) {
+                                    output += ret;
+                                }));
+                            }
+                        }
+                    }));
+                });
+            }));
+        };
+        addDir(dir);
+
+    }).nThen(function (waitFor) {
+
+        callback(output);
+
+    });
+};
+
+if (module.parent !== null) {
+    module.exports.checkDir = main;
+    module.exports.checkFile = checkFile;
+} else {
+    main('.', false, function(output) {
+        if (output !== '') {
+            console.log(output);
+            process.exit(1);
+        }
+    });
+}

+ 14 - 0
node_build/GitVersion.js

@@ -0,0 +1,14 @@
+var Fs = require('fs');
+
+module.exports.get = function (callback) {
+    Fs.readFile('.git/logs/HEAD', function (err, ret) {
+        if (err) { throw err; }
+        var lines = ret.toString('utf8').split('\n');
+        var hashes = lines[lines.length-2].split(' ');
+        var head = hashes[1];
+        if (!(/^[a-f0-9]{40}$/.test(head))) {
+            throw new Error(head + ' does not look like a git hash');
+        }
+        callback(head);
+    });
+};

+ 232 - 149
node_build/builder.js

@@ -16,6 +16,7 @@ var Os = require('os');
 var Fs = require('fs');
 var Spawn = require('child_process').spawn;
 var nThen = require('nthen');
+var Extend = require('node.extend');
 var Crypto = require('crypto');
 
 /*
@@ -53,8 +54,7 @@ var error = function (message)
 
 var toCompile = [];
 var compilers = 0;
-var cc = function (args, callback, noArg) {
-    if (noArg) { throw new Error(); }
+var cc = function (args, callback, content) {
     toCompile.push(function() {
         compilers++;
         var gcc = Spawn('gcc', args);
@@ -65,7 +65,7 @@ var cc = function (args, callback, noArg) {
         gcc.on('close', function(ret) {
             compilers--;
             if (ret) {
-                callback(error("\n" + err));
+                callback(error("gcc " + args.join(' ') + "\n\n" + err));
             }
             while (compilers < WORKERS && toCompile.length > 0) {
                 toCompile.shift()();
@@ -75,6 +75,12 @@ var cc = function (args, callback, noArg) {
             }
             callback(undefined, out);
         });
+        if (content) {
+            gcc.stdin.write(content, function (err) {
+                if (err) { throw err; }
+                gcc.stdin.end();
+            });
+        }
     });
     while (compilers < WORKERS && toCompile.length > 0) {
         toCompile.shift()();
@@ -82,45 +88,56 @@ var cc = function (args, callback, noArg) {
 };
 
 // You Were Warned
-var execJs = function (js, state, fileObj, callback) {
+var execJs = function (js, state, file, callback) {
     var x;
     var err;
-    try {
-        var func = eval('func = function(file, state) { ' + js + ' };');
-        x = func(fileObj, state) || '';
-    } catch (e) {
-        err = e;
-        err.message += "Content: [" + js + "]";
-    }
-    process.nextTick(function() { callback(err, x); });
+    // # 74 "./wire/Message.h"
+    js = js.replace(/\n#.*\n/g, '');
+    var to = setTimeout(function () {
+        throw new Error("Inline JS did not return after 10 seconds [" + js + "]");
+    }, 10000);
+    nThen(function (waitFor) {
+        try {
+            var func = new Function('file','state','require',js);
+            func.async = function () {
+                return waitFor(function (result) {
+                    x = result || '';
+                });
+            };
+            x = func.call(func,file,state,require) || '';
+        } catch (e) {
+            err = e;
+            err.message += "\nContent: [" + js + "]";
+        }
+    }).nThen(function (waitFor) {
+        clearTimeout(to);
+        process.nextTick(function() { callback(err, x); });
+    });
 };
 
 var debug = console.log;
 
 var preprocess = function (content, state, fileObj, callback) {
-    var captures = [];
+    var elems;
     nThen(function (waitFor) {
-        content = content.replace(/<\?js(.*)\?>/g, function (x, capture) {
-            captures.push(capture);
-            return '<?js?>';
-        });
-        captures.forEach(function (capture, i) {
+        elems = content.split('<?js');
+        elems.forEach(function (elem, i) {
+            if (!i) { return; }
+            var capture = elem.substring(0,elem.indexOf('?>'));
+            var remainder = elem.substring(capture.length+2);
             execJs(capture, state, fileObj, waitFor(function (err, ret) {
                 if (err) {
                     callback(err);
                     callback = function() {};
                     return;
                 }
-                //debug('[' + capture + '] --> [' + ret + ']');
-                captures[i] = ret;
+                //debug('[' + capture + '] --> [' + ret + '] [' + remainder.substring(0,100) + ']');
+                elems[i] = ret + remainder;
+                //if (elems[i].indexOf('?>') !== -1) { throw new Error(); }
             }));
         });
     }).nThen(function (waitFor) {
-        content = content.replace(/<\?js\?>/g, function (x) {
-            return captures.shift();
-        });
-
-        callback(undefined, content);
+        callback(undefined, elems.join(''));
     });
 };
 
@@ -153,33 +170,16 @@ var compileFile = function (fileName, state, tempDir, callback)
     currentlyCompiling[fileName].push(callback);
 
     //debug('\033[2;32mCompiling ' + fileName + '\033[0m');
-    var processedOne = tempDir + '/' + getObjectFile(fileName) + '.c';
-    var processedTwo = tempDir + '/' + getObjectFile(fileName) + '.i';
+    var preprocessed = tempDir + '/' + getObjectFile(fileName) + '.i';
     var outFile = state.buildDir+'/'+getObjectFile(fileName);
     var fileContent;
     var fileObj = getFile();
     nThen(function (waitFor) {
-
-        //debug("Load file");
-        Fs.readFile(fileName, waitFor(function (err, ret) {
-            if (err) { throw err; }
-            fileContent = ret.toString('utf8');
-        }));
-
-    }).nThen(function (waitFor) {
-
-        //debug("Preprocess 1");
-        preprocess(fileContent, state, fileObj, waitFor(function (err, output) {
-            if (err) { throw err; }
-            Fs.writeFile(processedOne, output, waitFor());
-        }));        
-
-    }).nThen(function (waitFor) {
         (function() {
             //debug("CPP -MM");
             var flags = ['-E', '-MM'];
             flags.push.apply(flags, state.cflags);
-            flags.push(processedOne);
+            flags.push(fileName);
             cc(flags, waitFor(function (err, output) {
                 if (err) { throw err; }
                 // replace the escapes and newlines
@@ -194,7 +194,7 @@ var compileFile = function (fileName, state, tempDir, callback)
             //debug("CPP");
             var flags = ['-E'];
             flags.push.apply(flags, state.cflags);
-            flags.push(processedOne);
+            flags.push(fileName);
             cc(flags, waitFor(function (err, output) {
                 if (err) { throw err; }
                 fileContent = output;
@@ -202,12 +202,19 @@ var compileFile = function (fileName, state, tempDir, callback)
         })();
 
     }).nThen(function (waitFor) {
-        //debug("Preprocess 2");
+
+        //debug("Preprocess");
         preprocess(fileContent, state, fileObj, waitFor(function (err, output) {
             if (err) { throw err; }
-            Fs.writeFile(processedTwo, output, waitFor(function (err) {
-                if (err) { throw err; }
-            }));
+            if (state.useTempFiles) {
+                Fs.writeFile(preprocessed, output, waitFor(function (err) {
+                    if (err) { throw err; }
+                }));
+                // important, this will prevent the file from also being piped to gcc.
+                fileContent = undefined;
+            } else {
+                fileContent = output;
+            }
         }));
 
         Fs.exists(outFile, waitFor(function (exists) {
@@ -221,13 +228,17 @@ var compileFile = function (fileName, state, tempDir, callback)
     }).nThen(function (waitFor) {
 
         //debug("CC");
-        var flags = ['-c','-o',outFile];
+        var flags = ['-c','-x','cpp-output','-o',outFile];
         flags.push.apply(flags, state.cflags);
-        flags.push(processedTwo);
+        if (state.useTempFiles) {
+            flags.push(preprocessed);
+        } else {
+            flags.push('-');
+        }
         cc(flags, waitFor(function (err) {
             if (err) { throw err; }
             fileObj.obj = outFile;
-        }));
+        }), fileContent);
 
     }).nThen(function (waitFor) {
         debug('\033[2;32mBuilding C object ' + fileName + ' complete\033[0m');
@@ -274,6 +285,8 @@ var removeFile = function (state, fileName, callback)
     nThen(function (waitFor) {
         // And every file which includes it
         Object.keys(state.files).forEach(function (file) {
+            // recursion could remove it
+            if (typeof(state.files[file]) === 'undefined') { return; }
             if (state.files[file].includes.indexOf(fileName) !== -1) {
                 removeFile(state, file, waitFor());
             }
@@ -345,25 +358,136 @@ var getLinkOrder = function (fileName, files) {
     return completeFiles;
 };
 
-var setUp = function (config, callback) {
-    var configStr = JSON.stringify(config);
-    var state = JSON.parse(configStr);
-    var configHash = Crypto.createHash('sha256').update(configStr).digest('hex');
-    state.includeDirs = state.includeDirs || [];
-    state.files = state.files || {};
-    state.includeDirs.unshift('.');
-    state.mtimes = state.mtimes || {};
-
-    for (var i = 0; i < state.includeDirs.length; i++) {
-        state.cflags.push('-I');
-        state.cflags.push(state.includeDirs[i]);
+var needsToLink = function (fileName, state) {
+    if (typeof(state.oldmtimes[fileName]) !== 'number') {
+        return true;
+    }
+    if (state.oldmtimes[fileName] !== state.mtimes[fileName]) {
+        return true;
+    }
+    var links = state.files[fileName].links;
+    for (var i = 0; i < links.length; i++) {
+        if (links[i] !== fileName && needsToLink(links[i], state)) {
+            return true;
+        }
+    }
+    return false;
+};
+
+var makeTime = function () {
+    return function () {
+        var oldTime = this.time || 0;
+        var newTime = this.time = new Date().getTime();
+        return newTime - oldTime;
+    };
+};
+
+var compile = function (file, outputFile, state, callback) {
+
+    var tempDir;
+    if (!needsToLink(file, state)) {
+        callback();
+        return;
+    }
+
+    nThen(function(waitFor) {
+
+        if (!state.useTempFiles) { return; }
+        tempDir = state.tempDir+'/jsmake-' + Crypto.pseudoRandomBytes(10).toString('hex');
+        Fs.mkdir(tempDir, waitFor(function (err) {
+            if (err) { throw err; }
+        }));
+
+    }).nThen(function(waitFor) {
+
+        recursiveCompile(file, state, tempDir, waitFor());
+
+    }).nThen(function(waitFor) {
+
+        var linkOrder = getLinkOrder(file, state.files);
+        for (var i = 0; i < linkOrder.length; i++) {
+            linkOrder[i] = state.buildDir + '/' + getObjectFile(linkOrder[i]);
+        }
+        var ldArgs = [];
+        ldArgs.push.apply(ldArgs, state.ldflags);
+        ldArgs.push.apply(ldArgs, ['-o', outputFile]);
+        ldArgs.push.apply(ldArgs, linkOrder);
+        ldArgs.push.apply(ldArgs, state.libs);
+        debug('\033[1;31mLinking C executable ' + outputFile + '\033[0m');
+
+        cc(ldArgs, waitFor(function (err, ret) {
+            if (err) { throw err; }
+        }));
+
+    }).nThen(function(waitFor) {
+
+        if (!state.useTempFiles) { return; }
+        Fs.readdir(tempDir, waitFor(function(err, files) {
+            if (err) { throw err; }
+            files.forEach(function(file) {
+                Fs.unlink(tempDir + '/' + file, waitFor(function(err) {
+                    if (err) { throw err; }
+                }));
+            });
+        }));
+
+    }).nThen(function(waitFor) {
+
+        if (!state.useTempFiles) { return; }
+        Fs.rmdir(tempDir, waitFor(function(err) {
+            if (err) { throw err; }
+        }));
+
+    }).nThen(function(waitFor) {
+
+        if (callback) { callback(); }
+
+    });
+};
+
+var getStatePrototype = function () {
+    return {
+        includeDirs: ['.'],
+        files: {},
+        mtimes: {},
+
+        cflags: [],
+        ldflags: [],
+        libs: [],
+
+        // Using temp files instead of pipes shaves about 400ms off a clean build.
+        // TODO: Understand why our use of pipes is not good.
+        tempDir: '/tmp',
+        useTempFiles: true,
+
+        systemName: 'Linux'
+    };
+};
+
+module.exports.configure = function (params, configure) {
+
+    // Track time taken for various steps
+    var time = makeTime();
+    time();
+
+    if (typeof(params.buildDir) !== 'string') {
+        throw new Error("buildDir not specified");
     }
 
+    var rebuildIfChangesHash = '';
+    if (typeof(params.rebuildIfChanges) !== 'undefined') {
+        rebuildIfChangesHash =
+            Crypto.createHash('sha256').update(params.rebuildIfChanges).digest('hex');
+    }
+
+    var state;
+    var buildStage;
+
     nThen(function(waitFor) {
         // make the build directory
-        Fs.exists(state.buildDir, waitFor(function (exists) {
+        Fs.exists(params.buildDir, waitFor(function (exists) {
             if (exists) { return; }
-            Fs.mkdir(state.buildDir, waitFor(function (err) {
+            Fs.mkdir(params.buildDir, waitFor(function (err) {
                 if (err) { throw err; }
             }));
         }));
@@ -371,22 +495,44 @@ var setUp = function (config, callback) {
     }).nThen(function(waitFor) {
 
         // read out the state if it exists
-        Fs.exists(state.buildDir + '/state.json', waitFor(function (exists) {
+        Fs.exists(params.buildDir + '/state.json', waitFor(function (exists) {
             if (!exists) { return; }
-            Fs.readFile(state.buildDir + '/state.json', waitFor(function (err, ret) {
+            Fs.readFile(params.buildDir + '/state.json', waitFor(function (err, ret) {
                 if (err) { throw err; }
                 var storedState = JSON.parse(ret);
-                if (configHash === storedState.configHash) {
+                if (storedState.rebuildIfChangesHash === rebuildIfChangesHash) {
                     state = storedState;
                 } else {
-                    debug("Config file changed, rebuilding");
+                    debug("rebuildIfChanges changed, rebuilding");
                 }
             }));
         }));
 
     }).nThen(function(waitFor) {
 
-        state.configHash = configHash;
+        debug("Initialize " + time() + "ms");
+
+        // Do the configuration step
+        if (state) { return; }
+        state = getStatePrototype();
+        configure({
+            config: state
+        }, waitFor);
+
+    }).nThen(function(waitFor) {
+
+        state.buildDir = params.buildDir;
+        for (var i = 0; i < state.includeDirs.length; i++) {
+            state.cflags.push('-I');
+            state.cflags.push(state.includeDirs[i]);
+        }
+        
+
+        debug("Configure " + time() + "ms");
+
+    }).nThen(function(waitFor) {
+
+        state.rebuildIfChangesHash = rebuildIfChangesHash;
         state.oldmtimes = state.mtimes;
         state.mtimes = {};
 
@@ -402,62 +548,20 @@ var setUp = function (config, callback) {
         });
 
     }).nThen(function(waitFor) {
-        callback(state);
-    });
-};
 
-var needsToLink = function (fileName, state) {
-    if (typeof(state.oldmtimes[fileName]) !== 'number') {
-        return true;
-    }
-    if (state.oldmtimes[fileName] !== state.mtimes[fileName]) {
-        return true;
-    }
-    var links = state.files[fileName].links;
-    for (var i = 0; i < links.length; i++) {
-        if (links[i] !== fileName && needsToLink(links[i], state)) {
-            return true;
-        }
-    }
-    return false;
-};
-
-var compile = function (file, outputFile, state) {
-
-    var tempDir = '/tmp/jsmake-' + Crypto.pseudoRandomBytes(10).toString('hex');
-
-    if (typeof(state.files[file]) !== 'undefined') {
-    //    return;
-    }
-
-    nThen(function(waitFor) {
-
-        Fs.mkdir(tempDir, waitFor(function (err) {
-            if (err) { throw err; }
-        }));
+        debug("Scan for out of date files " + time() + "ms");
 
     }).nThen(function(waitFor) {
 
-        recursiveCompile(file, state, tempDir, waitFor());
+        buildStage({
+            compile: function (cFile, outputFile) {
+                compile(cFile, outputFile, state, waitFor());
+            }
+        }, waitFor);
 
     }).nThen(function(waitFor) {
 
-        if (needsToLink(file, state)) {
-            var linkOrder = getLinkOrder(file, state.files);
-            for (var i = 0; i < linkOrder.length; i++) {
-                linkOrder[i] = state.buildDir + '/' + getObjectFile(linkOrder[i]);
-            }
-            var ldArgs = [];
-            ldArgs.push.apply(ldArgs, state.ldflags);
-            ldArgs.push.apply(ldArgs, ['-o', outputFile]);
-            ldArgs.push.apply(ldArgs, linkOrder);
-            ldArgs.push.apply(ldArgs, state.libs);
-            debug('\033[1;31mLinking C executable ' + outputFile + '\033[0m');
-
-            cc(ldArgs, waitFor(function (err, ret) {
-                if (err) { throw err; }
-            }));
-        }
+        debug("Compile " + time() + "ms");
 
     }).nThen(function(waitFor) {
 
@@ -469,38 +573,17 @@ var compile = function (file, outputFile, state) {
     }).nThen(function(waitFor) {
 
         // save state
-        Fs.writeFile(state.buildDir+'/state.json', JSON.stringify(state, null, '  '), waitFor(function(err) {
-            if (err) { throw err; }
-        }));
-
-    }).nThen(function(waitFor) {
-
-        // clear the temp dir
-        Fs.readdir(tempDir, waitFor(function(err, files) {
-            if (err) { throw err; }
-            files.forEach(function(file) {
-                Fs.unlink(tempDir + '/' + file, waitFor(function(err) {
-                    if (err) { throw err; }
-                }));
-            });
-        }));
-
-    }).nThen(function(waitFor) {
-
-        // remove the temp dir
-        Fs.rmdir(tempDir, waitFor(function(err) {
+        debug("Saving state");
+        var stateJson = JSON.stringify(state, null, '  ');
+        Fs.writeFile(state.buildDir+'/state.json', stateJson, waitFor(function(err) {
             if (err) { throw err; }
         }));
 
     });
-};
 
-module.exports.setUp = function (config, callback) {
-    var state;
-    setUp(config, function (s) {
-        state = s;
-        callback({
-            makeExecutable: function (cFile, outputFile) { compile(cFile, outputFile, state); }
-        });
-    });
+    return {
+        build: function (build) {
+            buildStage = build;
+        }
+    };
 };

+ 37 - 20
node_build/make.js

@@ -12,12 +12,18 @@
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
-var Builder = require('./builder');
+var Fs = require('fs');
+var Codestyle = require('./Codestyle');
 
-var CONFIG = {
-    systemName: 'Linux',
-    buildDir: 'buildjs',
-    cflags: [
+require('./builder').configure({
+    rebuildIfChanges: Fs.readFileSync(__filename).toString('utf8'),
+    buildDir: 'buildjs'
+}, function(builder, waitFor) {
+
+    builder.config.systemName = 'Linux';
+    builder.config.tempDir = '/tmp';
+    builder.config.useTempFiles = true;
+    builder.config.cflags.push(
         '-std=c99',
         '-Wall',
         '-Wextra',
@@ -28,9 +34,14 @@ var CONFIG = {
         '-D','HAS_ETH_INTERFACE=1',
         '-Wno-unused-parameter',
         '-Wno-unused-result',
+
+        // Broken GCC patch makes -fstack-protector-all not work
+        // workaround is to give -fno-stack-protector first.
+        // see: https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/691722
         '-fno-stack-protector',
         '-fstack-protector-all',
         '-Wstack-protector',
+
         '-D','HAS_BUILTIN_CONSTANT_P',
         '-fPIE',
         '-g',
@@ -38,29 +49,35 @@ var CONFIG = {
         '-D','CJDNS_MAX_PEERS=256',
         '-D','Identity_CHECK=1',
         '-D','PARANOIA=1',
-        '-D','HAS_JS_PREPROCESSOR',
-        '-D','GIT_VERSION="0000000000000000000000000000000000000000"'
-    ],
-    ldflags: [
+        '-D','HAS_JS_PREPROCESSOR'
+    );
+    builder.config.ldflags.push(
         '-pie',
         '-Wl,-z,relro,-z,now,-z,noexecstack'
-    ],
-    libs: [
+    );
+    builder.config.libs.push(
         './build/libuv/libuv.a',
         '-lpthread',
         './build/nacl_build/libnacl.a'
-    ],
-    includeDirs: [
+    );
+    builder.config.includeDirs.push(
         'build/nacl_build/include/',
         'build/libuv/include/'
-    ]
-};
+    );
+/*
+    var GitVersion = require('./GitVersion');
+    GitVersion.get(waitFor(function (version) {
+        builder.config.cflags.push('-D','GIT_VERSION="'+version+'"');
+    }));
+*/
+}).build(function (builder, waitFor) {
 
-Builder.setUp(CONFIG, function (builder) {
+    builder.compile('admin/angel/cjdroute2.c', 'cjdroutejs');
+    builder.compile('publictoip6.c', 'publictoip6');
+    builder.compile('privatetopublic.c', 'privatetopublic');
 
-    builder.makeExecutable('admin/angel/cjdroute2.c', 'cjdroutejs');
-    builder.makeExecutable('publictoip6.c', 'publictoip6');
-    builder.makeExecutable('privatetopublic.c', 'privatetopublic');
+    Codestyle.checkDir('.', true, waitFor(function (err) {
+        if (err) { console.log("Codestyle error"); throw err; }
+    }));
 
 });
-

+ 4 - 4
util/Assert.h

@@ -36,10 +36,10 @@ void Assert_failure(const char* format, ...);
 
 /** Runtime assertion which is always applied. */
 #define Assert_always(expr) do { \
-        if (!(expr)) {                                                                \
-            Assert_failure("Assertion failure [%s:%d] [%s]\n", __FILE__, __LINE__,    \
-                           #expr);                                                    \
-        }                                                                             \
+        if (!(expr)) {                                                                   \
+            Assert_failure("Assertion failure [%s:%d] [%s]\n", Gcc_SHORT_FILE, Gcc_LINE, \
+                           #expr);                                                       \
+        }                                                                                \
     } while (0)
 /* CHECKFILES_IGNORE a ; is expected after the while(0) but it will be supplied by the caller */
 

+ 2 - 1
util/Bits.h

@@ -18,6 +18,7 @@
 #include "util/Assert.h"
 #include "util/Endian.h"
 #include "util/log/Log.h"
+#include "util/Gcc.h"
 
 #include <stdint.h>
 #include <stddef.h>
@@ -182,7 +183,7 @@ static inline void* Bits_memcpyDebug(void* out,
  * @param length the number of bytes to copy.
  */
 #ifdef Log_DEBUG
-    #define Bits_memcpy(a, b, c) Bits_memcpyDebug(a, b, c, __FILE__, __LINE__)
+    #define Bits_memcpy(a, b, c) Bits_memcpyDebug(a, b, c, Gcc_SHORT_FILE, Gcc_LINE)
 #else
     #define Bits_memcpy(a,b,c) Bits_memcpyNoDebug(a,b,c)
 #endif

+ 11 - 0
util/Gcc.h

@@ -29,6 +29,17 @@
 
 #endif
 
+#ifdef HAS_JS_PREPROCESSOR
+#define Gcc_SHORT_FILE <?\
+js                                                                    \
+    return '"'+__FILE__.substring(__FILE__.lastIndexOf('/')+1)+'"';   \
+?>
+#else
+    #define Gcc_SHORT_FILE __FILE__
+#endif
+
+#define Gcc_LINE __LINE__
+
 Gcc_PRINTF(1,2)
 static inline void Gcc_checkPrintf(const char* format, ...)
 {

+ 5 - 1
util/log/Log.c

@@ -46,7 +46,11 @@ void Log_print(struct Log* log,
     inLogger--;
 
     if (droppedMessages && !inLogger) {
-        Log_print(log, Log_Level_INFO, __FILE__, __LINE__, "There were [%d] dropped log messages.",
+        Log_print(log,
+                  Log_Level_ERROR,
+                  Gcc_SHORT_FILE,
+                  Gcc_LINE,
+                  "There were [%d] dropped log messages.",
                   droppedMessages);
         droppedMessages = 0;
     }

+ 4 - 4
util/log/Log.h

@@ -69,10 +69,10 @@ void Log_print(struct Log* log,
                ...);
 
 #define Log_printf(log, level, ...) \
-    do {                                                                \
-        if (log) {                                                      \
-            Log_print(log, level, __FILE__, __LINE__, __VA_ARGS__);     \
-        }                                                               \
+    do {                                                                   \
+        if (log) {                                                         \
+            Log_print(log, level, Gcc_SHORT_FILE, Gcc_LINE, __VA_ARGS__);  \
+        }                                                                  \
     } while (0)
 // CHECKFILES_IGNORE missing ;
 

+ 2 - 2
util/log/WriterLog.c

@@ -47,8 +47,8 @@ static void print(struct Log* genericLog,
     Writer_write(log->writer, timeAndLevelBuff, strlen(timeAndLevelBuff));
 
     // Strip the path to make log lines shorter.
-    char* lastSlash = strrchr(file, '/');
-    Writer_write(log->writer, lastSlash + 1, strlen(lastSlash + 1));
+    //char* lastSlash = strrchr(file, '/');
+    Writer_write(log->writer, file, strlen(file));
 
     #define Log_BUFFER_SZ 1024
     char buff[Log_BUFFER_SZ];

+ 19 - 1
util/version/Version.c

@@ -16,5 +16,23 @@
 
 const uint8_t* Version_gitVersion()
 {
-    return (uint8_t*) GIT_VERSION;
+    return (uint8_t*)
+    #ifdef HAS_JS_PREPROCESSOR
+        <?js
+            var done = this.async();
+            require('fs').readFile('.git/logs/HEAD', function (err, ret) {
+                if (err) { throw err; }
+                var lines = ret.toString('utf8').split('\n');
+                var hashes = lines[lines.length-2].split(' ');
+                var head = hashes[1];
+                if (!(/^[a-f0-9]{40}$/.test(head))) {
+                    throw new Error(head + ' does not look like a git hash');
+                }
+                done('"'+head+'"');
+            });
+        ?>
+    #else
+        GIT_VERSION
+    #endif
+    ;
 }