make.js 12 KB

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