make.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. var Fs = require('fs');
  16. var nThen = require('nthen');
  17. var Codestyle = require('./Codestyle');
  18. var Cp = require('./Cp');
  19. var Spawn = require('child_process').spawn;
  20. var Extend = require('node.extend');
  21. var Os = require('os');
  22. var FindPython2 = require('./FindPython2');
  23. var CanCompile = require('./CanCompile');
  24. // ['linux','darwin','sunos','win32','freebsd']
  25. var SYSTEM = process.platform;
  26. var CROSS = process.env['CROSS'] || '';
  27. var GCC = process.env['CC'] || 'gcc';
  28. var BUILDDIR = process.env['BUILDDIR'];
  29. if (BUILDDIR === undefined) {
  30. BUILDDIR = 'build_'+SYSTEM;
  31. }
  32. var OPTIMIZE = '-O2';
  33. // on BSD and iphone systems, os.cpus() is not reliable so if it
  34. // returns undefined, let's just assume 1
  35. var WORKERS = Math.floor((typeof Os.cpus() == 'undefined' ? 1 : Os.cpus().length) * 1.25);
  36. process.on('exit', function () {
  37. console.log("Total build time: " + Math.floor(process.uptime() * 1000) + "ms.");
  38. });
  39. var Builder = require('./builder');
  40. Builder.configure({
  41. rebuildIfChanges: Fs.readFileSync(__filename).toString('utf8') + JSON.stringify(process.env),
  42. buildDir: BUILDDIR
  43. }, function(builder, waitFor) {
  44. builder.config.systemName = SYSTEM;
  45. builder.config.gcc = GCC;
  46. builder.config.tempDir = '/tmp';
  47. builder.config.useTempFiles = true;
  48. builder.config.cflags.push.apply(builder.config.cflags, [
  49. '-std=c99',
  50. '-Wall',
  51. '-Wextra',
  52. '-Werror',
  53. '-Wno-pointer-sign',
  54. '-pedantic',
  55. '-D',builder.config.systemName + '=1',
  56. '-Wno-unused-parameter',
  57. '-Wno-unused-result',
  58. '-D','HAS_BUILTIN_CONSTANT_P',
  59. '-g',
  60. // f4 = 16 peers max, fixed width 4 bit
  61. // f8 = 241 peers max, fixed width 8 bit
  62. // v3x5x8 = 256 peers max, variable width, 3, 5 or 8 bits plus 1 or 2 bits of prefix
  63. // v4x8 = 256 peers max, variable width, 4, or 8 bits plus 1 bit prefix
  64. '-D','NumberCompress_TYPE=v3x5x8',
  65. // disable for speed, enable for safety
  66. '-D','Identity_CHECK=1',
  67. '-D','Allocator_USE_CANARIES=1',
  68. '-D','PARANOIA=1'
  69. ]);
  70. var logLevel = process.env['Log_LEVEL'] || 'DEBUG';
  71. builder.config.cflags.push('-D','Log_'+logLevel);
  72. if (process.env['NO_PIE'] === undefined) {
  73. builder.config.cflags.push('-fPIE');
  74. }
  75. if (process.env['TESTING']) { builder.config.cflags.push('-D', 'TESTING=1'); }
  76. if (SYSTEM === 'win32') {
  77. builder.config.cflags.push(
  78. '!-fPIE',
  79. '!-pie',
  80. '-Wno-format'
  81. );
  82. builder.config.libs.push(
  83. '-lssp'
  84. );
  85. } else if (SYSTEM === 'linux') {
  86. builder.config.ldflags.push(
  87. '-Wl,-z,relro,-z,now,-z,noexecstack'
  88. );
  89. builder.config.cflags.push(
  90. '-DHAS_ETH_INTERFACE=1'
  91. );
  92. }
  93. if (process.env['NO_PIE'] === undefined) {
  94. builder.config.ldflags.push(
  95. '-pie'
  96. );
  97. }
  98. if (/.*clang.*/.test(GCC) || SYSTEM === 'darwin') {
  99. // blows up when preprocessing before js preprocessor
  100. builder.config.cflags.push(
  101. '-Wno-invalid-pp-token',
  102. '-Wno-dollar-in-identifier-extension',
  103. '-Wno-newline-eof',
  104. '-Wno-unused-value',
  105. // lots of places where depending on preprocessor conditions, a statement might be
  106. // a case of if (1 == 1)
  107. '-Wno-tautological-compare'
  108. );
  109. }
  110. // Install any user-defined CFLAGS. Necessary if you are messing about with building cnacl
  111. // with NEON on the BBB
  112. cflags = process.env['CFLAGS'];
  113. if (cflags) {
  114. flags = cflags.split(' ');
  115. flags.forEach(function(flag) {
  116. builder.config.cflags.push(flag);
  117. });
  118. }
  119. // We also need to pass various architecture/floating point flags to GCC when invoked as
  120. // a linker.
  121. ldflags = process.env['LDFLAGS'];
  122. if (ldflags) {
  123. flags = ldflags.split(' ');
  124. flags.forEach(function(flag) {
  125. builder.config.ldflags.push(flag);
  126. });
  127. }
  128. if (/.*android.*/.test(GCC)) {
  129. builder.config.cflags.push(
  130. '-Dandroid=1'
  131. );
  132. }
  133. CanCompile.check(builder,
  134. 'int main() { return 0; }',
  135. [ builder.config.cflags, '-flto', '-x', 'c' ],
  136. function (err, can) {
  137. if (can) {
  138. console.log("Compiler supports link time optimization");
  139. builder.config.ldflags.push(
  140. '-flto',
  141. OPTIMIZE
  142. );
  143. // No optimization while building since actual compile happens during linking.
  144. builder.config.cflags.push('-O0');
  145. } else {
  146. console.log("Link time optimization not supported [" + err + "]");
  147. builder.config.cflags.push(OPTIMIZE);
  148. }
  149. });
  150. var uclibc = /uclibc/i.test(GCC);
  151. var libssp = process.env['SSP_SUPPORT'] == 'y';
  152. if (!uclibc || libssp) {
  153. builder.config.cflags.push(
  154. // Broken GCC patch makes -fstack-protector-all not work
  155. // workaround is to give -fno-stack-protector first.
  156. // see: https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/691722
  157. '-fno-stack-protector',
  158. '-fstack-protector-all',
  159. '-Wstack-protector'
  160. );
  161. if (uclibc) { builder.config.libs.push('-lssp'); }
  162. } else {
  163. console.log("Stack Smashing Protection (security feature) is disabled");
  164. }
  165. // Build dependencies
  166. nThen(function (waitFor) {
  167. Fs.exists(BUILDDIR+'/dependencies', waitFor(function (exists) {
  168. if (exists) { return; }
  169. console.log("Copy dependencies");
  170. Cp('./node_build/dependencies', BUILDDIR+'/dependencies', waitFor());
  171. }));
  172. }).nThen(function (waitFor) {
  173. builder.config.libs.push(
  174. BUILDDIR+'/dependencies/cnacl/jsbuild/libnacl.a'
  175. );
  176. builder.config.includeDirs.push(
  177. BUILDDIR+'/dependencies/cnacl/jsbuild/include/'
  178. );
  179. Fs.exists(BUILDDIR+'/dependencies/cnacl/jsbuild/libnacl.a', waitFor(function (exists) {
  180. if (exists) { return; }
  181. console.log("Build NaCl");
  182. var cwd = process.cwd();
  183. process.chdir(BUILDDIR+'/dependencies/cnacl/');
  184. var NaCl = require(process.cwd() + '/node_build/make.js');
  185. NaCl.build(function (args, callback) {
  186. if (builder.config.systemName !== 'win32') { args.unshift('-fPIC'); }
  187. args.unshift('-O2', '-fomit-frame-pointer');
  188. cflags = process.env['CFLAGS'];
  189. if (cflags) {
  190. flags = cflags.split(' ');
  191. flags.forEach(function(flag) {
  192. args.push(flag);
  193. });
  194. }
  195. builder.cc(args, callback);
  196. }, waitFor(function () {
  197. process.chdir(cwd);
  198. }));
  199. }));
  200. }).nThen(function (waitFor) {
  201. builder.config.libs.push(
  202. BUILDDIR+'/dependencies/libuv/out/Release/libuv.a'
  203. );
  204. if (!/.*android.*/.test(GCC)) {
  205. builder.config.libs.push(
  206. '-lpthread'
  207. );
  208. }
  209. if (builder.config.systemName === 'win32') {
  210. builder.config.libs.push(
  211. '-lws2_32',
  212. '-lpsapi', // GetProcessMemoryInfo()
  213. '-liphlpapi' // GetAdapterAddresses()
  214. );
  215. } else if (builder.config.systemName === 'linux' && !/.*android.*/.test(GCC)) {
  216. builder.config.libs.push(
  217. '-lrt' // clock_gettime()
  218. );
  219. } else if (builder.config.systemName === 'darwin') {
  220. builder.config.libs.push(
  221. '-framework', 'CoreServices'
  222. );
  223. } else if (builder.config.systemName === 'freebsd') {
  224. builder.config.libs.push(
  225. '-lkvm'
  226. );
  227. }
  228. builder.config.includeDirs.push(
  229. BUILDDIR+'/dependencies/libuv/include/'
  230. );
  231. var libuvBuilt;
  232. var python;
  233. nThen(function (waitFor) {
  234. Fs.exists(BUILDDIR+'/dependencies/libuv/out/Release/libuv.a', waitFor(function (exists) {
  235. if (exists) { libuvBuilt = true; }
  236. }));
  237. }).nThen(function (waitFor) {
  238. if (libuvBuilt) { return; }
  239. FindPython2.find(builder.tmpFile(), waitFor(function (err, pythonExec) {
  240. if (err) { throw err; }
  241. python = pythonExec;
  242. }));
  243. }).nThen(function (waitFor) {
  244. if (libuvBuilt) { return; }
  245. console.log("Build Libuv");
  246. var cwd = process.cwd();
  247. process.chdir(BUILDDIR+'/dependencies/libuv/');
  248. var args = ['./gyp_uv.py'];
  249. var env = Extend({}, process.env);
  250. env.CC = builder.config.gcc;
  251. if (env.TARGET_ARCH) {
  252. args.push('-Dtarget_arch='+env.TARGET_ARCH);
  253. }
  254. if (/.*android.*/.test(GCC)) { args.push('-Dtarget_arch=arm', '-DOS=android'); }
  255. var gyp = Spawn(python, args, {env:env});
  256. gyp.stdout.on('data', function(dat) { process.stdout.write(dat.toString()); });
  257. gyp.stderr.on('data', function(dat) { process.stderr.write(dat.toString()); });
  258. gyp.on('close', waitFor(function () {
  259. var args = ['-j', WORKERS, '-C', 'out', 'BUILDTYPE=Release', 'CC='+builder.config.gcc];
  260. if (builder.config.systemName === 'win32') { args.push('PLATFORM=mingw32'); }
  261. if (builder.config.systemName !== 'darwin') { args.push('CFLAGS=-fPIC'); }
  262. var make;
  263. if (builder.config.systemName == 'freebsd') {
  264. make = Spawn('gmake', args);
  265. } else {
  266. make = Spawn('make', args);
  267. }
  268. make.stdout.on('data', function(dat) { process.stdout.write(dat.toString()); });
  269. make.stderr.on('data', function(dat) { process.stderr.write(dat.toString()); });
  270. make.on('close', waitFor(function () {
  271. process.chdir(cwd);
  272. }));
  273. }));
  274. }).nThen(waitFor());
  275. }).nThen(waitFor());
  276. }).build(function (builder, waitFor) {
  277. builder.buildExecutable('admin/angel/cjdroute2.c', BUILDDIR+'/cjdroute', waitFor());
  278. builder.buildExecutable('test/testcjdroute.c', BUILDDIR+'/testcjdroute', waitFor());
  279. builder.buildExecutable('contrib/c/publictoip6.c', './publictoip6', waitFor());
  280. builder.buildExecutable('contrib/c/privatetopublic.c', './privatetopublic', waitFor());
  281. builder.buildExecutable('contrib/c/sybilsim.c', './sybilsim', waitFor());
  282. builder.buildExecutable('contrib/c/makekeys.c', './makekeys', waitFor());
  283. builder.buildExecutable('crypto/random/randombytes.c', './randombytes', waitFor());
  284. }).test(function (builder, waitFor) {
  285. nThen(function (waitFor) {
  286. if (CROSS) { console.log("Cross compiling. Test disabled."); return; }
  287. var out = '';
  288. var err = '';
  289. var test = Spawn(BUILDDIR+'/testcjdroute', ['all']);
  290. test.stdout.on('data', function(dat) { out += dat.toString(); });
  291. test.stderr.on('data', function(dat) { err += dat.toString(); });
  292. test.on('close', waitFor(function (ret) {
  293. if (ret !== 0) {
  294. console.log(out);
  295. console.log(err);
  296. console.log('\033[1;31mFailed to build cjdns.\033[0m');
  297. waitFor.abort();
  298. } else {
  299. console.log(err);
  300. }
  301. }));
  302. }).nThen(function (waitFor) {
  303. console.log("Checking codestyle");
  304. var files = [];
  305. builder.rebuiltFiles.forEach(function (fileName) {
  306. if (fileName.indexOf('/dependencies/') !== -1) { return; }
  307. console.log("Checking " + fileName);
  308. files.push(fileName);
  309. });
  310. Codestyle.checkFiles(files, waitFor(function (output) {
  311. if (output !== '') {
  312. throw new Error("Codestyle failure\n" + output);
  313. }
  314. }));
  315. }).nThen(waitFor());
  316. }).pack(function (builder, waitFor) {
  317. Fs.exists(BUILDDIR+'/cjdroute', waitFor(function (exists) {
  318. if (!exists) { return; }
  319. Fs.rename(BUILDDIR+'/cjdroute', './cjdroute', waitFor(function (err) {
  320. if (err) { throw err; }
  321. }));
  322. }));
  323. console.log('\033[1;32mBuild completed successfully, type ./cjdroute to begin setup.\033[0m');
  324. });