Here are the relevant scripts of Stockfish.js project, relating to emscripten building, joined with this message.
Thanks in advance, regards -- You received this message because you are subscribed to the Google Groups "emscripten-discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/emscripten-discuss/15301329-8466-4ba7-92e8-510a9a00ed26%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Makefile
Description: Binary data
///NOTE: Without the new line above, it may be joined to a line comment above. /// Make Stockfish use setImmediate() (rather than setTimeout() or requestAnimationFrame()) if possible. /// /// Based on setImmediate polyfill: https://github.com/YuzuJS/setImmediate /// Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, and Domenic Denicola /// MIT var ourSetImmediate = (function (global, undefined) { "use strict"; if (global.setImmediate) { try { return global.setImmediate.bind(global); } catch (e) { return global.setImmediate; } } var nextHandle = 1; // Spec says greater than zero var tasksByHandle = {}; var currentlyRunningATask = false; var doc = global.document; var setImmediate; function addFromSetImmediateArguments(args) { tasksByHandle[nextHandle] = partiallyApplied.apply(undefined, args); return nextHandle++; } // This function accepts the same arguments as setImmediate, but // returns a function that requires no arguments. function partiallyApplied(handler) { var args = [].slice.call(arguments, 1); return function() { if (typeof handler === "function") { handler.apply(undefined, args); } else { (new Function("" + handler))(); } }; } function runIfPresent(handle) { // From the spec: "Wait until any invocations of this algorithm started before this one have completed." // So if we're currently running a task, we'll need to delay this invocation. if (currentlyRunningATask) { // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a // "too much recursion" error. setTimeout(partiallyApplied(runIfPresent, handle), 0); } else { var task = tasksByHandle[handle]; if (task) { currentlyRunningATask = true; try { task(); } finally { clearImmediate(handle); currentlyRunningATask = false; } } } } function clearImmediate(handle) { delete tasksByHandle[handle]; } function installNextTickImplementation() { setImmediate = function() { var handle = addFromSetImmediateArguments(arguments); process.nextTick(partiallyApplied(runIfPresent, handle)); return handle; }; } function canUsePostMessage() { // The test against `importScripts` prevents this implementation from being installed inside a web worker, // where `global.postMessage` means something completely different and can't be used for this purpose. if (global.postMessage && !global.importScripts) { var postMessageIsAsynchronous = true; var oldOnMessage = global.onmessage; global.onmessage = function() { postMessageIsAsynchronous = false; }; global.postMessage("", "*"); global.onmessage = oldOnMessage; return postMessageIsAsynchronous; } } function installPostMessageImplementation() { // Installs an event handler on `global` for the `message` event: see // * https://developer.mozilla.org/en/DOM/window.postMessage // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages var messagePrefix = "setImmediate$" + Math.random() + "$"; var onGlobalMessage = function(event) { if (event.source === global && typeof event.data === "string" && event.data.indexOf(messagePrefix) === 0) { runIfPresent(+event.data.slice(messagePrefix.length)); } }; if (global.addEventListener) { global.addEventListener("message", onGlobalMessage, false); } else { global.attachEvent("onmessage", onGlobalMessage); } setImmediate = function() { var handle = addFromSetImmediateArguments(arguments); global.postMessage(messagePrefix + handle, "*"); return handle; }; } function installMessageChannelImplementation() { var channel = new MessageChannel(); channel.port1.onmessage = function(event) { var handle = event.data; runIfPresent(handle); }; setImmediate = function() { var handle = addFromSetImmediateArguments(arguments); channel.port2.postMessage(handle); return handle; }; } function installReadyStateChangeImplementation() { var html = doc.documentElement; setImmediate = function() { var handle = addFromSetImmediateArguments(arguments); // Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called. var script = doc.createElement("script"); script.onreadystatechange = function () { runIfPresent(handle); script.onreadystatechange = null; html.removeChild(script); script = null; }; html.appendChild(script); return handle; }; } function installSetTimeoutImplementation() { setImmediate = function() { var handle = addFromSetImmediateArguments(arguments); setTimeout(partiallyApplied(runIfPresent, handle), 0); return handle; }; } // Don't get fooled by e.g. browserify environments. if ({}.toString.call(global.process) === "[object process]") { // For Node.js before 0.9 installNextTickImplementation(); } else if (canUsePostMessage()) { // For non-IE10 modern browsers installPostMessageImplementation(); } else if (global.MessageChannel) { // For web workers, where supported installMessageChannelImplementation(); } else if (doc && "onreadystatechange" in doc.createElement("script")) { // For IE 6–8 installReadyStateChangeImplementation(); } else { // For older browsers installSetTimeoutImplementation(); } return setImmediate; }(typeof self === "undefined" ? typeof global === "undefined" ? this : global : self)); ///NOTE: Emscripten does not use cancelAnimationFrame() or clearTimeout(). Browser.requestAnimationFrame = ourSetImmediate; return Module; } /// End of load_stockfish() from pre.js /// This is returned to STOCKFISH() in pre.js. return function (WasmPath) { var myConsole, Module, workerObj, cmds = [], wait = typeof setImmediate === "function" ? setImmediate : setTimeout; myConsole = { log: function log(line) { if (workerObj.onmessage) { /// Match Web Workers. workerObj.onmessage(line) } else { console.error("You must set onmessage"); console.info(line); } }, time: function time(s) { if (typeof console !== "undefined" && console.time) console.time(s); }, timeEnd: function timeEnd(s) { if (typeof console !== "undefined" && console.timeEnd) console.timeEnd(s); } }; myConsole.warn = myConsole.log; workerObj = { postMessage: function sendMessage(str, sync) { function ccall() { if (Module) { Module.ccall("uci_command", "number", ["string"], [cmds.shift()]); } else { setTimeout(ccall, 100); } } cmds.push(str); if (sync) { ccall(); } else { wait(ccall, 1); } } }; /// We need to give them a chance to set postMessage wait(function () { Module = load_stockfish(myConsole, WasmPath); if (Module.print) { Module.print = myConsole.log; } if (Module.printErr) { Module.printErr = myConsole.log; } /// Initialize. Module.ccall("init", "number", [], []); }, 1); return workerObj; }; }()); /// End of STOCKFISH() closeure from pre.js. (function () { var isNode, stockfish; function completer(line) { var completions = [ "d", "eval", "exit", "flip", "go", "isready", "ponderhit", "position fen ", "position startpos", "position startpos moves", "quit", "setoption name Clear Hash value ", "setoption name Contempt value ", "setoption name Hash value ", "setoption name Minimum Thinking Time value ", "setoption name Move Overhead value ", "setoption name MultiPV value ", "setoption name Ponder value ", "setoption name Skill Level Maximum Error value ", "setoption name Skill Level Probability value ", "setoption name Skill Level value ", "setoption name Slow Mover value ", "setoption name Threads value ", "setoption name UCI_Chess960 value false", "setoption name UCI_Chess960 value true", "setoption name UCI_Variant value chess", "setoption name UCI_Variant value atomic", "setoption name UCI_Variant value crazyhouse", "setoption name UCI_Variant value giveaway", "setoption name UCI_Variant value horde", "setoption name UCI_Variant value kingofthehill", "setoption name UCI_Variant value racingkings", "setoption name UCI_Variant value relay", "setoption name UCI_Variant value threecheck", "setoption name nodestime value ", "stop", "uci", "ucinewgame" ]; var completionsMid = [ "binc ", "btime ", "confidence ", "depth ", "infinite ", "mate ", "maxdepth ", "maxtime ", "mindepth ", "mintime ", "moves ", /// for position fen ... moves "movestogo ", "movetime ", "ponder ", "searchmoves ", "shallow ", "winc ", "wtime " ]; function filter(c) { return c.indexOf(line) === 0; } /// This looks for completions starting at the very beginning of the line. /// If the user has typed nothing, it will match everything. var hits = completions.filter(filter); if (!hits.length) { /// Just get the last word. line = line.replace(/^.*\s/, ""); if (line) { /// Find completion mid line too. hits = completionsMid.filter(filter); } else { /// If no word has been typed, show all options. hits = completionsMid; } } return [hits, line]; } isNode = typeof global !== "undefined" && Object.prototype.toString.call(global.process) === "[object process]"; if (isNode) { /// Was it called directly? if (require.main === module) { stockfish = STOCKFISH(require("path").join(__dirname, "stockfish.wasm")); stockfish.onmessage = function onlog(line) { console.log(line); }; require("readline").createInterface({ input: process.stdin, output: process.stdout, completer: completer, historySize: 100, }).on("line", function online(line) { if (line) { if (line === "quit" || line === "exit") { process.exit(); } stockfish.postMessage(line, true); } }).setPrompt(""); process.stdin.on("end", function onend() { process.exit(); }); /// Is this a node module? } else { module.exports = STOCKFISH; } /// Is it a web worker? } else if (typeof onmessage !== "undefined" && (typeof window === "undefined" || typeof window.document === "undefined")) { if (self && self.location && self.location.hash) { /// Use .substr() to trim off the hash (#). stockfish = STOCKFISH(self.location.hash.substr(1)); } else { stockfish = STOCKFISH(); } onmessage = function(event) { stockfish.postMessage(event.data, true); }; stockfish.onmessage = function onlog(line) { postMessage(line); }; } ///NOTE: If it's a normal browser, we don't need to do anything. The client can use the STOCKFISH() function directly. }());
/** * Copyright (C) Tord Romstad (Glaurung author) * Copyright (C) Marco Costalba, Joona Kiiski, Tord Romstad (Stockfish authors) * Copyright (C) Chess.com * Copyright (C) Nathan Rugg (Stockfish.js) * Copyright (C) Phillip Albanese - https://github.com/philososaur * * Stockfish is free, and distributed under the GNU General Public License * (GPL). Essentially, this means that you are free to do almost exactly * what you want with the program, including distributing it among your * friends, making it available for download from your web site, selling * it (either by itself or as part of some bigger software package), or * using it as the starting point for a software project of your own. * * The only real limitation is that whenever you distribute Stockfish in * some way, you must always include the full source code, or a pointer * to where the source code can be found. If you make any changes to the * source code, these changes must also be made available under the GPL. * * The source code for this emscripten port of stockfish can be found * at http://github.com/nmrugg/stockfish.js. */ var STOCKFISH = (function () { function load_stockfish(console, WasmPath) { /// Fake timer for Safari and IE/Edge. ///NOTE: Both Chrome and Edge have "Safari" in it. if (typeof navigator !== "undefined" && (/MSIE|Trident|Edge/i.test(navigator.userAgent) || (/Safari/i.test(navigator.userAgent) && !/Chrome|CriOS/i.test(navigator.userAgent)))) { var dateNow = Date.now; } var Module = { wasmBinaryFile: WasmPath };
#!/usr/bin/env node
//! Chess.com (c) 2018
"use strict";
var spawnSync = require("child_process").spawnSync;
var execFileSync = require("child_process").execFileSync;
var params = get_params({booleans: ["no-chesscom", "debug-js", "h", "help",
"help-all", "f", "force", "force-linking", "b", "bin", "colors"]});
var args = ["build", "-j", require("os").cpus().length];
var fs = require("fs");
var p = require("path");
var stockfishPath = p.join(__dirname, "src", "stockfish");
var stockfishJSPath = p.join(__dirname, "src", "stockfish.asm.js");
var stockfishWASMPath = p.join(__dirname, "src", "stockfish.wasm");
var stockfishWASMLoaderPath = p.join(__dirname, "src", "stockfish.js");
var data;
var license = fs.readFileSync(p.join(__dirname, "src", "license.js"), "utf8");
var buildToWASM;
var buildToASMJS;
var buildToAnyJS;
var child;
var stockfishVersion = "10";
var postFilePath;
var postFile;
var fistRun;
function get_params(options, argv)
{
var i,
params = {_: []},
last,
len,
match;
if (Array.isArray(options)) {
args = options;
options = {};
}
options = options || {};
if (!options.booleans) {
options.booleans = [];
}
argv = argv || process.argv;
len = argv.length;
for (i = 2; i < len; i += 1) {
if (argv[i][0] === "-") {
if (argv[i][1] === "-") {
last = argv[i].substr(2);
match = last.match(/([^=]*)=(.*)/);
if (match) {
last = match[1];
params[last] = match[2];
last = "";
} else {
params[last] = true;
}
} else {
/// E.g., -hav should indicate h, a, and v as TRUE.
argv[i].split("").slice(1).forEach(function oneach(letter)
{
params[letter] = true;
last = letter;
});
}
} else if (last) {
params[last] = argv[i];
last = "";
} else {
params._.push(argv[i]);
last = "";
}
/// Handle booleans.
if (last && options.booleans.indexOf(last) > -1) {
last = "";
}
}
return params;
}
function color(color_code, str)
{
if (process.stdout.isTTY || params.colors) {
str = "\u001B[" + color_code + "m" + str + "\u001B[0m";
}
return str;
}
function warn(str)
{
console.warn(color(33, "WARN: " + str));
}
function highlight(str)
{
return color(33, str);
}
function note(str)
{
return color(36, str);
}
function bold(str)
{
return color(1, str);
}
function changeVersion(version)
{
var filePath = p.join(__dirname, "src", "misc.cpp");
var data = fs.readFileSync(filePath, "utf8");
data = data.replace(/(const string Version = ")[^\"]*(";)/, "$1" + version
+ "$2");
try {
fs.writeFileSync(filePath, data);
} catch (e) {
console.error(e);
}
}
function determineBestArch()
{
var cpuData = "";
var cpuArch = "";
var arch;
try {
cpuArch = execFileSync("uname", ["-m"], {encoding: "utf8", env:
process.env, cwd: __dirname}).trim();
} catch (e) {}
if (cpuArch === "i686" || cpuArch === "i386") {
arch = "general-32";
} else {
if (cpuArch !== "x86_64" || cpuArch === "amd64") {
warn("Unrecognized cpu architechure. Defaulting to x86_64.");
}
try {
cpuData = execFileSync("cat", ["/proc/cpuinfo"], {encoding: "utf8",
env: process.env, cwd: __dirname}).trim();
} catch (e) {}
if (!cpuData) {
try {
cpuData = execFileSync("lscpu", {encoding: "utf8", env:
process.env, cwd: __dirname}).trim();
} catch (e) {}
}
if (!cpuData) {
try {
cpuData = execFileSync("lshw", ["-C", "cpu"], {encoding:
"utf8", env: process.env, cwd: __dirname}).trim();
} catch (e) {}
}
if (!cpuData) {
try {
/// FreeBSD & macOS?
cpuData = execFileSync("sysctl", ["-a"], {encoding: "utf8",
env: process.env, cwd: __dirname}).trim();
} catch (e) {}
}
if (/\bbmi2\b/i.test(cpuData)) {
arch = "x86-64-bmi2";
} else if (/\bpopcnt\b/i.test(cpuData)) {
arch = "x86-64-modern";
} else {
arch = "general-64";
}
}
console.log(note("Building " + arch));
args.push("ARCH=" + arch);
}
if (!params.make) {
params.make = "make";
}
if (params.arch) {
if (params.b || params.bin) {
warn("Cannot user --bin (or -b) with --arch");
process.exit(1);
}
if (params.arch === "js") {
buildToWASM = true;
buildToASMJS = true;
} else {
args.push("ARCH=" + params.arch);
if (params.arch === "asmjs") {
buildToASMJS = true;
} else if (params.arch === "wasm") {
buildToWASM = true;
}
}
} else if (params.b || params.bin) {
determineBestArch()
} else {
buildToWASM = true;
buildToASMJS = true;
}
buildToAnyJS = buildToWASM || buildToASMJS;
if (params.help || params["help-all"] || params.h) {
console.log("");
console.log(bold("Build the Stockfish Chess Engine"));
console.log("Usage: ./build.js [" + highlight("options") + "]");
console.log("");
console.log(" " + highlight("-f --force") + " Always rebuild the
entire project");
console.log(" " + highlight("--force-linking") + " Always preforming the
final linking step");
console.log(" " + highlight("--variants") + " Comma separated list of
variants to include (default: " + note("none") + ")");
console.log( " Possible values are " +
note("all") + ", " + note("none") + " (no variants, except for Chess960),");
console.log( " " + note("anti") + ", "
+ note("atomic") + ", " + note("crazyhouse") + ", " + note("horde") + ", " +
note("kingofthehill") + ", " + note("race") + ", " + note("relay") + ", or " +
note("3check"));
console.log(" " + highlight("--no-chesscom") + " Disable changes made
specifically for chess.com;");
console.log( " this includes showing
SAN moves, fixing three-fold repetition,");
console.log( " addition of mindepth,
maxdepth, and shallow options to the go command,");
console.log( " and Skill Level Maximum
Error and Skill Level Probability uci options");
console.log(" " + highlight("--static") + " Link libaries
statically (not JS)");
console.log(" " + highlight("--debug-js") + " Compile JS in debug
mode (adds ASSERTIONS=2 and SAFE_HEAP=1)");
console.log(" " + highlight("--arch") + " Architecture to build
to (default: " + note("js") + ")");
console.log( " If the arch is set to "
+ note("js") + ", it will compile both an asm.js version");
console.log( " and a WASM version. Set
to " + note("asmjs") + " or " + note("wasm") + " for just one.");
console.log( " " + note("x86-64-bmi2")
+ " is likely the fastest binary version");
console.log( " See " +
highlight("--help-all") + " for more options, or use " + highlight("--bin") + "
instead");
console.log(" " + highlight("--basename") + " The filename for the
engine (default: " + note ("stockfish") + ")");
console.log( " This will not only
rename the files, it will also rewrite the base JS file");
console.log( " to load the correct
WASM and ASM engines");
console.log(" " + highlight("-b --bin") + " Attempt to build a
binary engine that is the most suitable for this system");
console.log(" " + highlight("--make") + " Path to program used to
make Stockfish (default: " + note("make") + ")");
console.log(" " + highlight("--comp") + " Compiler to build C
code with");
console.log(" " + highlight("--compcxx") + " Compiler to build C++
code with");
console.log(" " + highlight("--version") + " Specify Stockfish
version number (default: " + note(stockfishVersion) + ")");
console.log( " Use " + note("date") +
" to use the current date");
console.log( " Use " +
note("timestamp") + " to use the current Unix timestamp");
console.log( " Use " + note("hash") +
" to use the current git commit hash");
console.log(" " + highlight("--colors") + " Always colorize the
output, even through a pipe");
console.log(" " + highlight("-h --help") + " Show build.js's help");
console.log(" " + highlight("--help-all") + " Show Stockfish's
Makefile help as well");
console.log("");
console.log("Examples:");
console.log("");
console.log(" Default: include all modifications and variants, compile to
ASM.js and WASM");
console.log(" ./build.js");
console.log("");
console.log(" Vanilla Stockfish: no modifications, no variants, 64-bit
native binary");
console.log(" ./build.js " + highlight("--no-chesscom") + " " +
highlight("--variants=") + note("none") + " " + highlight("--arch=") +
note("x86-64-bmi2"));
console.log("");
console.log(" Build Chess.com engine");
console.log(" ./build.js " + highlight("-f") + " " +
highlight("--variants") + " " + note("crazyhouse,3check,koth"));
console.log("");
if (params["help-all"]) {
console.log("");
console.log(bold("******** Makefile Help ********"));
console.log("");
spawnSync(params.make, {stdio: [0,1,2], env: process.env, cwd:
p.join(__dirname, "src")});
}
process.exit();
} else if (params.force || params.f) {
args.push("--always-make");
} else if (params["force-linking"]) {
///NOTE: --force will also link as well, so both are not needed.
try {
if (buildToAnyJS) {
if (buildToASMJS) {
fs.unlinkSync(stockfishJSPath);
} else {
fs.unlinkSync(stockfishJSWASMPath);
fs.unlinkSync(stockfishJSWASMLoaderPath);
}
} else {
fs.unlinkSync(stockfishPath);
}
} catch (e) {
/// Don't throw if there is no file to delete.
if (e.code !== "ENOENT") {
throw e;
}
}
}
if (params.variants && params.variants.toLowerCase() !== "all") {
args.push("VARIANTS=" + params.variants.toUpperCase());
} else if (!params.variants) {
args.push("VARIANTS=NONE");
}
if (!params["no-chesscom"]) {
args.push("CHESSCOM=1");
}
if (params["debug-js"]) {
if (buildToAnyJS) {
args.push("DEBUGJS=1");
} else {
warn("Ignoring --debug-js");
}
}
if (params.static) {
if (buildToJs) {
warn("Ignoring --static");
} else {
args.push("STATIC=1");
}
}
if (params.comp) {
args.push("COMP=" + params.comp);
}
if (params.compcxx) {
args.push("COMPCXX=" + params.compcxx);
}
if (String(params.version).toLowerCase() === "timestamp") {
params.version = Date.now();
}
if (String(params.version).toLowerCase() === "hash") {
params.version = execFileSync("git", ["rev-parse", "--short=0", "HEAD"],
{encoding: "utf8", env: process.env, cwd: __dirname}).trim();
}
///NOTE: Stockfish will insert the date automatically if no version number is
given.
if (String(params.version).toLowerCase() !== "date") {
changeVersion(params.version === true || !params.version ? stockfishVersion
: params.version);
}
if (buildToWASM && buildToASMJS) {
console.log("\n" + note("Building ASM.js") + "\n");
args.push("ARCH=asmjs");
child = spawnSync(params.make, args, {stdio: [0,1,2], env: process.env,
cwd: p.join(__dirname, "src")});
args.pop();
if (Number(child.status) !== 0) {
process.exit(Number(child.status));
}
console.log("\n" + note("Building WASM") + "\n");
args.push("ARCH=wasm");
child = spawnSync(params.make, args, {stdio: [0,1,2], env: process.env,
cwd: p.join(__dirname, "src")});
} else {
child = spawnSync(params.make, args, {stdio: [0,1,2], env: process.env,
cwd: p.join(__dirname, "src")});
}
/// Reset version string.
if (String(params.version).toLowerCase() !== "date") {
changeVersion("");
}
/// `make` does not throw an error when encountering errors, so we need to do
that manually.
if (Number(child.status) !== 0) {
process.exit(Number(child.status));
}
if (!buildToAnyJS && params.basename) {
fs.renameSync(stockfishPath, p.join(__dirname, "src", params.basename));
}
if (buildToASMJS) {
data = fs.readFileSync(stockfishJSPath, "utf8");
/// Add the license if it's not there (emscripten removes all comments).
if (data.indexOf(license) !== 0) {
fs.writeFileSync(stockfishJSPath, license + data);
}
if (params.basename) {
fs.renameSync(stockfishJSPath, p.join(__dirname, "src", params.basename
+ ".asm.js"));
}
}
if (buildToWASM) {
data = fs.readFileSync(stockfishWASMLoaderPath, "utf8");
/// Remove "var Module" so that it does not overwrite our custom module.
data = data.replace("var Module;", "");
if (params.basename) {
data = data.replace(/stockfish\.wasm/g, params.basename + ".wasm");
}
/// Add the license if it's not there (emscripten removes all comments).
if (data.indexOf(license) !== 0) {
fs.writeFileSync(stockfishWASMLoaderPath, license + data);
}
if (params.basename) {
fs.renameSync(stockfishWASMLoaderPath, p.join(__dirname, "src",
params.basename + ".js"));
fs.renameSync(stockfishWASMPath, p.join(__dirname, "src",
params.basename + ".wasm"));
}
}
