/* 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 . */ var Fs = require('fs'); var nThen = require('nthen'); var Codestyle = require('./Codestyle'); var Cp = require('./Cp'); var Spawn = require('child_process').spawn; var Os = require('os'); var FindPython = require('./FindPython'); var CanCompile = require('./CanCompile'); var Builder = require('./builder'); var TestRunner = require('./TestRunner'); // ['linux','darwin','sunos','win32','freebsd','openbsd','netbsd'] var SYSTEM = process.env['SYSTEM'] || process.platform; var GCC = process.env['CC']; var CFLAGS = process.env['CFLAGS']; var LDFLAGS = process.env['LDFLAGS']; var NO_MARCH_FLAG = ['arm', 'ppc', 'ppc64']; if (GCC) { // Already specified. } else if (SYSTEM === 'openbsd') { GCC = 'egcc'; } else if (SYSTEM === 'freebsd') { GCC = 'clang'; } else { GCC = 'gcc'; } Builder.configure({ systemName: SYSTEM, crossCompiling: process.env['CROSS'] !== undefined, gcc: GCC, tempDir: process.env['CJDNS_BUILD_TMPDIR'] || '/tmp', optimizeLevel: '-O3', logLevel: process.env['Log_LEVEL'] || 'DEBUG' }, function (builder, waitFor) { builder.config.cflags.push( '-std=c99', '-Wall', '-Wextra', '-Werror', '-Wno-pointer-sign', '-Wmissing-prototypes', '-pedantic', '-D', builder.config.systemName + '=1', '-D', 'CJD_PACKAGE_VERSION="' + builder.config.version + '"', '-Wno-unused-parameter', '-fomit-frame-pointer', '-D', 'Log_' + builder.config.logLevel, '-g', // f4 = 16 peers max, fixed width 4 bit // f8 = 241 peers max, fixed width 8 bit // v3x5x8 = 256 peers max, variable width, 3, 5 or 8 bits plus 1 or 2 bits of prefix // v4x8 = 256 peers max, variable width, 4, or 8 bits plus 1 bit prefix '-D', 'NumberCompress_TYPE=v3x5x8', // enable for safety (don't worry about speed, profiling shows they add ~nothing) '-D', 'Identity_CHECK=1', '-D', 'Allocator_USE_CANARIES=1', '-D', 'PARANOIA=1' ); if (process.env['SUBNODE']) { builder.config.cflags.push('-DSUBNODE=1'); } if (process.env['GCOV']) { builder.config.cflags.push('-fprofile-arcs', '-ftest-coverage'); builder.config.ldflags.push('-fprofile-arcs', '-ftest-coverage'); } var android = /android/i.test(builder.config.gcc); if (process.env['TESTING']) { builder.config.cflags.push('-D', 'TESTING=1'); } if (process.env['ADDRESS_PREFIX'] !== undefined) { builder.config.cflags.push('-D', 'ADDRESS_PREFIX=' + process.env['ADDRESS_PREFIX']); } if (process.env['ADDRESS_PREFIX_BITS'] !== undefined) { builder.config.cflags.push('-D', 'ADDRESS_PREFIX_BITS=' + process.env['ADDRESS_PREFIX_BITS']); } if (!builder.config.crossCompiling) { if (NO_MARCH_FLAG.indexOf(process.arch) == -1) { builder.config.cflags.push('-march=native'); } } if (builder.config.systemName === 'win32') { builder.config.cflags.push('-Wno-format'); } else if (builder.config.systemName === 'linux') { builder.config.ldflags.push('-Wl,-z,relro,-z,now,-z,noexecstack'); builder.config.cflags.push('-DHAS_ETH_INTERFACE=1'); } else if (builder.config.systemName === 'darwin') { builder.config.cflags.push('-DHAS_ETH_INTERFACE=1'); } if (process.env['NO_PIE'] === undefined && builder.config.systemName !== 'freebsd' && builder.config.systemName !== 'win32') { builder.config.cflags.push('-fPIE'); // just using `-pie` on OS X >= 10.10 results in this warning: // clang: warning: argument unused during compilation: '-pie' if (builder.config.systemName !== "darwin") { builder.config.ldflags.push('-pie'); } else { builder.config.ldflags.push('-Wl,-pie'); } } if (builder.config.compilerType.isClang) { // blows up when preprocessing before js preprocessor builder.config.cflags.push( '-Wno-invalid-pp-token', '-Wno-dollar-in-identifier-extension', '-Wno-newline-eof', '-Wno-unused-value', // lots of places where depending on preprocessor conditions, a statement might be // a case of if (1 == 1) '-Wno-tautological-compare', '-Wno-error' ); builder.config.cflags.slice(builder.config.cflags.indexOf('-Werror'), 1); } else { builder.config.cflags.push( '-fdiagnostics-color=always' ) } // Install any user-defined CFLAGS. Necessary if you are messing about with building cnacl // with NEON on the BBB, or want to set -Os (OpenWrt) // Allow -O0 so while debugging all variables are present. if (CFLAGS) { var cflags = CFLAGS.split(' '); cflags.forEach(function(flag) { if (/^\-O[^02s]$/.test(flag)) { console.log("Skipping " + flag + ", assuming " + builder.config.optimizeLevel + " instead."); } else if (/^\-O[02s]$/.test(flag)) { builder.config.optimizeLevel = flag; } else { [].push.apply(builder.config.cflags, cflags); } }); } builder.config.cflags.push(builder.config.optimizeLevel); if (!/^\-O0$/.test(builder.config.optimizeLevel)) { builder.config.cflags.push('-D_FORTIFY_SOURCE=2'); } // We also need to pass various architecture/floating point flags to GCC when invoked as // a linker. if (LDFLAGS) { [].push.apply(builder.config.ldflags, LDFLAGS.split(' ')); } if (android) { builder.config.cflags.push('-Dandroid=1'); } if (process.env.NO_LTO) { console.log("Link time optimization disabled"); } else { CanCompile.check(builder, 'int main() { return 0; }', [ builder.config.cflags, '-flto', '-x', 'c' ], function (err, can) { if (can) { console.log("Compiler supports link time optimization"); builder.config.ldflags.push( '-flto', builder.config.optimizeLevel ); } else { console.log("Link time optimization not supported [" + err + "]"); } }); } var uclibc = process.env['UCLIBC'] == '1'; var libssp; switch (process.env['SSP_SUPPORT']) { case 'y': case '1': libssp = true; break; case 'n': case '' : case '0': libssp = false; break; case undefined: break; default: throw new Error(); } if (libssp === false) { console.log("Stack Smashing Protection (security feature) is disabled"); } else if (builder.config.systemName == 'win32') { builder.config.libs.push('-lssp'); } else if ((!uclibc && builder.config.systemName !== 'sunos') || libssp === true) { builder.config.cflags.push( // 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' ); // Static libssp provides __stack_chk_fail_local, which x86 needs in // order to avoid expensively looking up the location of __stack_chk_fail. var x86 = process.env['TARGET_ARCH'] == 'i386'; if (uclibc) { if (x86) { builder.config.libs.push('-Wl,-Bstatic', '-lssp', '-Wl,-Bdynamic'); } else { builder.config.libs.push('-lssp'); } } } else { console.log("Stack Smashing Protection (security feature) is disabled"); } if (process.env['Pipe_PREFIX'] !== undefined) { builder.config.cflags.push( '-D', 'Pipe_PREFIX="' + process.env['Pipe_PREFIX'] + '"' ); } var dependencyDir = builder.config.buildDir + '/dependencies'; var libuvLib = dependencyDir + '/libuv/out/Release/libuv.a'; if (['win32', 'netbsd'].indexOf(builder.config.systemName) >= 0) {//this might be needed for other BSDs libuvLib = dependencyDir + '/libuv/out/Release/obj.target/libuv.a'; } // Build dependencies nThen(function (waitFor) { Fs.exists(dependencyDir, waitFor(function (exists) { if (exists) { return; } console.log("Copy dependencies"); Cp('./node_build/dependencies', dependencyDir, waitFor()); })); }).nThen(function (waitFor) { builder.config.libs.push(dependencyDir + '/cnacl/jsbuild/libnacl.a'); builder.config.includeDirs.push(dependencyDir + '/cnacl/jsbuild/include/'); // needed for Sign.c which pulls in crypto_int32.h builder.config.includeDirs.push(dependencyDir + '/cnacl/jsbuild/include_internal/'); Fs.exists(dependencyDir + '/cnacl/jsbuild/libnacl.a', waitFor(function (exists) { if (exists) { return; } console.log("Build NaCl"); var cwd = process.cwd(); process.chdir(dependencyDir + '/cnacl/'); var NaCl = require(process.cwd() + '/node_build/make.js'); NaCl.build(function (args, callback) { if (builder.config.systemName !== 'win32') { args.unshift('-fPIC'); } args.unshift(builder.config.optimizeLevel, '-fomit-frame-pointer'); if (!/^\-O0$/.test(builder.config.optimizeLevel)) { args.unshift('-D_FORTIFY_SOURCE=2'); } if (CFLAGS) { [].push.apply(args, CFLAGS.split(' ')); } if (!builder.config.crossCompiling) { if (NO_MARCH_FLAG.indexOf(process.arch) == -1) { args.unshift('-march=native'); } } builder.cc(args, callback); }, builder.config, waitFor(function () { process.chdir(cwd); })); })); }).nThen(function (waitFor) { builder.config.libs.push(libuvLib); if (!android) { builder.config.libs.push('-lpthread'); } if (builder.config.systemName === 'win32') { builder.config.libs.push( '-lws2_32', '-lpsapi', // GetProcessMemoryInfo() '-liphlpapi' // GetAdapterAddresses() ); } else if (builder.config.systemName === 'linux' && !android) { builder.config.libs.push('-lrt'); // clock_gettime() } else if (builder.config.systemName === 'darwin') { builder.config.libs.push('-framework', 'CoreServices'); } else if (['freebsd', 'openbsd', 'netbsd'].indexOf(builder.config.systemName) >= 0) { builder.config.cflags.push('-Wno-overlength-strings'); builder.config.libs.push('-lkvm'); } else if (builder.config.systemName === 'sunos') { builder.config.libs.push( '-lsocket', '-lsendfile', '-lkstat', '-lnsl' ); } builder.config.includeDirs.push(dependencyDir + '/libuv/include/'); var libuvBuilt; var python; nThen(function (waitFor) { Fs.exists(libuvLib, waitFor(function (exists) { if (exists) { libuvBuilt = true; } })); }).nThen(function (waitFor) { if (libuvBuilt) { return; } FindPython.find(builder.tmpFile(), waitFor(function (err, pythonExec) { if (err) { throw err; } python = pythonExec; })); }).nThen(function (waitFor) { if (libuvBuilt) { return; } console.log("Build Libuv"); var cwd = process.cwd(); process.chdir(dependencyDir + '/libuv/'); var args = ['./gyp_uv.py']; var env = process.env; env.CC = builder.config.gcc; if (env.TARGET_ARCH) { args.push('-Dtarget_arch=' + env.TARGET_ARCH); } //args.push('--root-target=libuv'); if (android) { args.push('-DOS=android'); args.push('--format=make-linux') } if (builder.config.systemName === 'win32') { args.push('-DOS=win'); } if (env.GYP_ADDITIONAL_ARGS) { args.push.apply(args, env.GYP_ADDITIONAL_ARGS.split(' ')); } if (['freebsd', 'openbsd', 'netbsd'].indexOf(builder.config.systemName) !== -1) { // This platform lacks a functioning sem_open implementation, therefore... args.push('--no-parallel'); args.push('-DOS=' + builder.config.systemName); } var gyp = Spawn(python, args, {env:env, stdio:'inherit'}); gyp.on('error', function () { console.error("couldn't launch gyp [" + python + "]"); }); gyp.on('close', waitFor(function () { var args = [ '-j', builder.processors, '-C', 'out', 'BUILDTYPE=Release', 'CC=' + builder.config.gcc, 'CXX=' + builder.config.gcc, 'V=1' ]; var cflags = [builder.config.optimizeLevel, '-DNO_EMFILE_TRICK=1']; if (!/^\-O0$/.test(builder.config.optimizeLevel)) { cflags.push('-D_FORTIFY_SOURCE=2'); } if (!(/darwin|win32/i.test(builder.config.systemName))) { cflags.push('-fPIC'); } args.push('CFLAGS=' + cflags.join(' ')); var makeCommand = ['freebsd', 'openbsd', 'netbsd'].indexOf(builder.config.systemName) >= 0 ? 'gmake' : 'make'; var make = Spawn(makeCommand, args, {stdio: 'inherit'}); make.on('error', function (err) { if (err.code === 'ENOENT') { console.error('\033[1;31mError: ' + makeCommand + ' is required!\033[0m'); } else { console.error( '\033[1;31mFail run ' + process.cwd() + ': ' + makeCommand + ' ' + args.join(' ') + '\033[0m' ); console.error('Message:', err); } waitFor.abort(); }); make.on('close', waitFor(function () { process.chdir(cwd); })); })); }).nThen(waitFor()); }).nThen(waitFor()); }).build(function (builder, waitFor) { builder.buildExecutable('client/cjdroute2.c', 'cjdroute'); builder.buildExecutable('contrib/c/publictoip6.c'); builder.buildExecutable('contrib/c/privatetopublic.c'); builder.buildExecutable('contrib/c/sybilsim.c'); builder.buildExecutable('contrib/c/makekeys.c'); builder.buildExecutable('contrib/c/mkpasswd.c'); builder.buildExecutable('crypto/random/randombytes.c'); builder.lintFiles(function (fileName, file, callback) { if (/dependencies/.test(fileName)) { callback('', false); return; } Codestyle.lint(fileName, file, callback); }); var testcjdroute = builder.buildTest('test/testcjdroute.c'); if (builder.config.crossCompiling) { console.log("Cross compiling. Building, but not running tests."); return; } var testRunner = TestRunner.local(['all']); if (process.env['REMOTE_TEST']) { testRunner = TestRunner.remote(process.env['REMOTE_TEST'], ['all']); } if (!process.env['NO_TEST']) { builder.runTest(testcjdroute, testRunner); } }).success(function (builder, waitFor) { console.log('\033[1;32mBuild completed successfully, type ./cjdroute to begin setup.\033[0m'); }).failure(function (builder, waitFor) { console.log('\033[1;31mFailed to build cjdns.\033[0m'); process.exit(1); }).complete(function (builder, waitFor) { if (builder.failure) { process.exit(1); } });