make.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  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 <https://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 Os = require('os');
  21. var FindPython = require('./FindPython');
  22. var CanCompile = require('./CanCompile');
  23. var Builder = require('./builder');
  24. var TestRunner = require('./TestRunner');
  25. // ['linux','darwin','sunos','win32','freebsd','openbsd','netbsd']
  26. var SYSTEM = process.env['SYSTEM'] || process.platform;
  27. var GCC = process.env['CC'];
  28. var CFLAGS = process.env['CFLAGS'];
  29. var LDFLAGS = process.env['LDFLAGS'];
  30. var NO_MARCH_FLAG = ['arm', 'ppc', 'ppc64'];
  31. if (GCC) {
  32. // Already specified.
  33. } else if (SYSTEM === 'openbsd') {
  34. GCC = 'egcc';
  35. } else if (SYSTEM === 'freebsd') {
  36. GCC = 'clang';
  37. } else {
  38. GCC = 'gcc';
  39. }
  40. Builder.configure({
  41. systemName: SYSTEM,
  42. crossCompiling: process.env['CROSS'] !== undefined,
  43. gcc: GCC,
  44. tempDir: process.env['CJDNS_BUILD_TMPDIR'] || '/tmp',
  45. optimizeLevel: '-O3',
  46. logLevel: process.env['Log_LEVEL'] || 'DEBUG'
  47. }, function (builder, waitFor) {
  48. builder.config.cflags.push(
  49. '-std=c99',
  50. '-Wall',
  51. '-Wextra',
  52. '-Werror',
  53. '-Wno-pointer-sign',
  54. '-Wmissing-prototypes',
  55. '-pedantic',
  56. '-D', builder.config.systemName + '=1',
  57. '-D', 'CJD_PACKAGE_VERSION="' + builder.config.version + '"',
  58. '-Wno-unused-parameter',
  59. '-fomit-frame-pointer',
  60. '-D', 'Log_' + builder.config.logLevel,
  61. '-g',
  62. // f4 = 16 peers max, fixed width 4 bit
  63. // f8 = 241 peers max, fixed width 8 bit
  64. // v3x5x8 = 256 peers max, variable width, 3, 5 or 8 bits plus 1 or 2 bits of prefix
  65. // v4x8 = 256 peers max, variable width, 4, or 8 bits plus 1 bit prefix
  66. '-D', 'NumberCompress_TYPE=v3x5x8',
  67. // enable for safety (don't worry about speed, profiling shows they add ~nothing)
  68. '-D', 'Identity_CHECK=1',
  69. '-D', 'Allocator_USE_CANARIES=1',
  70. '-D', 'PARANOIA=1'
  71. );
  72. if (process.env['SUBNODE']) { builder.config.cflags.push('-DSUBNODE=1'); }
  73. if (process.env['GCOV']) {
  74. builder.config.cflags.push('-fprofile-arcs', '-ftest-coverage');
  75. builder.config.ldflags.push('-fprofile-arcs', '-ftest-coverage');
  76. }
  77. var android = /android/i.test(builder.config.gcc);
  78. if (process.env['TESTING']) {
  79. builder.config.cflags.push('-D', 'TESTING=1');
  80. }
  81. if (process.env['ADDRESS_PREFIX'] !== undefined) {
  82. builder.config.cflags.push('-D', 'ADDRESS_PREFIX=' + process.env['ADDRESS_PREFIX']);
  83. }
  84. if (process.env['ADDRESS_PREFIX_BITS'] !== undefined) {
  85. builder.config.cflags.push('-D', 'ADDRESS_PREFIX_BITS=' + process.env['ADDRESS_PREFIX_BITS']);
  86. }
  87. if (!builder.config.crossCompiling) {
  88. if (NO_MARCH_FLAG.indexOf(process.arch) == -1) {
  89. builder.config.cflags.push('-march=native');
  90. }
  91. }
  92. if (builder.config.systemName === 'win32') {
  93. builder.config.cflags.push('-Wno-format');
  94. } else if (builder.config.systemName === 'linux') {
  95. builder.config.ldflags.push('-Wl,-z,relro,-z,now,-z,noexecstack');
  96. builder.config.cflags.push('-DHAS_ETH_INTERFACE=1');
  97. } else if (builder.config.systemName === 'darwin') {
  98. builder.config.cflags.push('-DHAS_ETH_INTERFACE=1');
  99. }
  100. if (process.env['NO_PIE'] === undefined && builder.config.systemName !== 'freebsd'
  101. && builder.config.systemName !== 'win32')
  102. {
  103. builder.config.cflags.push('-fPIE');
  104. // just using `-pie` on OS X >= 10.10 results in this warning:
  105. // clang: warning: argument unused during compilation: '-pie'
  106. if (builder.config.systemName !== "darwin")
  107. {
  108. builder.config.ldflags.push('-pie');
  109. } else {
  110. builder.config.ldflags.push('-Wl,-pie');
  111. }
  112. }
  113. if (builder.config.compilerType.isClang) {
  114. // blows up when preprocessing before js preprocessor
  115. builder.config.cflags.push(
  116. '-Wno-invalid-pp-token',
  117. '-Wno-dollar-in-identifier-extension',
  118. '-Wno-newline-eof',
  119. '-Wno-unused-value',
  120. // lots of places where depending on preprocessor conditions, a statement might be
  121. // a case of if (1 == 1)
  122. '-Wno-tautological-compare',
  123. '-Wno-error'
  124. );
  125. builder.config.cflags.slice(builder.config.cflags.indexOf('-Werror'), 1);
  126. } else {
  127. builder.config.cflags.push(
  128. '-fdiagnostics-color=always'
  129. )
  130. }
  131. // Install any user-defined CFLAGS. Necessary if you are messing about with building cnacl
  132. // with NEON on the BBB, or want to set -Os (OpenWrt)
  133. // Allow -O0 so while debugging all variables are present.
  134. if (CFLAGS) {
  135. var cflags = CFLAGS.split(' ');
  136. cflags.forEach(function(flag) {
  137. if (/^\-O[^02s]$/.test(flag)) {
  138. console.log("Skipping " + flag + ", assuming " +
  139. builder.config.optimizeLevel + " instead.");
  140. } else if (/^\-O[02s]$/.test(flag)) {
  141. builder.config.optimizeLevel = flag;
  142. } else {
  143. [].push.apply(builder.config.cflags, cflags);
  144. }
  145. });
  146. }
  147. builder.config.cflags.push(builder.config.optimizeLevel);
  148. if (!/^\-O0$/.test(builder.config.optimizeLevel)) {
  149. builder.config.cflags.push('-D_FORTIFY_SOURCE=2');
  150. }
  151. // We also need to pass various architecture/floating point flags to GCC when invoked as
  152. // a linker.
  153. if (LDFLAGS) {
  154. [].push.apply(builder.config.ldflags, LDFLAGS.split(' '));
  155. }
  156. if (android) {
  157. builder.config.cflags.push('-Dandroid=1');
  158. }
  159. if (process.env.NO_LTO) {
  160. console.log("Link time optimization disabled");
  161. } else {
  162. CanCompile.check(builder,
  163. 'int main() { return 0; }',
  164. [ builder.config.cflags, '-flto', '-x', 'c' ],
  165. function (err, can) {
  166. if (can) {
  167. console.log("Compiler supports link time optimization");
  168. builder.config.ldflags.push(
  169. '-flto',
  170. builder.config.optimizeLevel
  171. );
  172. } else {
  173. console.log("Link time optimization not supported [" + err + "]");
  174. }
  175. });
  176. }
  177. var uclibc = process.env['UCLIBC'] == '1';
  178. var libssp;
  179. switch (process.env['SSP_SUPPORT']) {
  180. case 'y':
  181. case '1': libssp = true; break;
  182. case 'n':
  183. case '' :
  184. case '0': libssp = false; break;
  185. case undefined: break;
  186. default: throw new Error();
  187. }
  188. if (libssp === false) {
  189. console.log("Stack Smashing Protection (security feature) is disabled");
  190. } else if (builder.config.systemName == 'win32') {
  191. builder.config.libs.push('-lssp');
  192. } else if ((!uclibc && builder.config.systemName !== 'sunos') || libssp === true) {
  193. builder.config.cflags.push(
  194. // Broken GCC patch makes -fstack-protector-all not work
  195. // workaround is to give -fno-stack-protector first.
  196. // see: https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/691722
  197. '-fno-stack-protector',
  198. '-fstack-protector-all',
  199. '-Wstack-protector'
  200. );
  201. // Static libssp provides __stack_chk_fail_local, which x86 needs in
  202. // order to avoid expensively looking up the location of __stack_chk_fail.
  203. var x86 = process.env['TARGET_ARCH'] == 'i386';
  204. if (uclibc) {
  205. if (x86) {
  206. builder.config.libs.push('-Wl,-Bstatic', '-lssp', '-Wl,-Bdynamic');
  207. } else {
  208. builder.config.libs.push('-lssp');
  209. }
  210. }
  211. } else {
  212. console.log("Stack Smashing Protection (security feature) is disabled");
  213. }
  214. if (process.env['Pipe_PREFIX'] !== undefined) {
  215. builder.config.cflags.push(
  216. '-D', 'Pipe_PREFIX="' + process.env['Pipe_PREFIX'] + '"'
  217. );
  218. }
  219. var dependencyDir = builder.config.buildDir + '/dependencies';
  220. var libuvLib = dependencyDir + '/libuv/out/Release/libuv.a';
  221. if (['win32', 'netbsd'].indexOf(builder.config.systemName) >= 0) {//this might be needed for other BSDs
  222. libuvLib = dependencyDir + '/libuv/out/Release/obj.target/libuv.a';
  223. }
  224. // Build dependencies
  225. nThen(function (waitFor) {
  226. Fs.exists(dependencyDir, waitFor(function (exists) {
  227. if (exists) { return; }
  228. console.log("Copy dependencies");
  229. Cp('./node_build/dependencies', dependencyDir, waitFor());
  230. }));
  231. }).nThen(function (waitFor) {
  232. builder.config.libs.push(dependencyDir + '/cnacl/jsbuild/libnacl.a');
  233. builder.config.includeDirs.push(dependencyDir + '/cnacl/jsbuild/include/');
  234. // needed for Sign.c which pulls in crypto_int32.h
  235. builder.config.includeDirs.push(dependencyDir + '/cnacl/jsbuild/include_internal/');
  236. Fs.exists(dependencyDir + '/cnacl/jsbuild/libnacl.a', waitFor(function (exists) {
  237. if (exists) { return; }
  238. console.log("Build NaCl");
  239. var cwd = process.cwd();
  240. process.chdir(dependencyDir + '/cnacl/');
  241. var NaCl = require(process.cwd() + '/node_build/make.js');
  242. NaCl.build(function (args, callback) {
  243. if (builder.config.systemName !== 'win32') {
  244. args.unshift('-fPIC');
  245. }
  246. args.unshift(builder.config.optimizeLevel, '-fomit-frame-pointer');
  247. if (!/^\-O0$/.test(builder.config.optimizeLevel)) {
  248. args.unshift('-D_FORTIFY_SOURCE=2');
  249. }
  250. if (CFLAGS) {
  251. [].push.apply(args, CFLAGS.split(' '));
  252. }
  253. if (!builder.config.crossCompiling) {
  254. if (NO_MARCH_FLAG.indexOf(process.arch) == -1) {
  255. args.unshift('-march=native');
  256. }
  257. }
  258. builder.cc(args, callback);
  259. },
  260. builder.config,
  261. waitFor(function () {
  262. process.chdir(cwd);
  263. }));
  264. }));
  265. }).nThen(function (waitFor) {
  266. builder.config.libs.push(libuvLib);
  267. if (!android) {
  268. builder.config.libs.push('-lpthread');
  269. }
  270. if (builder.config.systemName === 'win32') {
  271. builder.config.libs.push(
  272. '-lws2_32',
  273. '-lpsapi', // GetProcessMemoryInfo()
  274. '-liphlpapi' // GetAdapterAddresses()
  275. );
  276. } else if (builder.config.systemName === 'linux' && !android) {
  277. builder.config.libs.push('-lrt'); // clock_gettime()
  278. } else if (builder.config.systemName === 'darwin') {
  279. builder.config.libs.push('-framework', 'CoreServices');
  280. } else if (['freebsd', 'openbsd', 'netbsd'].indexOf(builder.config.systemName) >= 0) {
  281. builder.config.cflags.push('-Wno-overlength-strings');
  282. builder.config.libs.push('-lkvm');
  283. } else if (builder.config.systemName === 'sunos') {
  284. builder.config.libs.push(
  285. '-lsocket',
  286. '-lsendfile',
  287. '-lkstat',
  288. '-lnsl'
  289. );
  290. }
  291. builder.config.includeDirs.push(dependencyDir + '/libuv/include/');
  292. var libuvBuilt;
  293. var python;
  294. nThen(function (waitFor) {
  295. Fs.exists(libuvLib, waitFor(function (exists) {
  296. if (exists) { libuvBuilt = true; }
  297. }));
  298. }).nThen(function (waitFor) {
  299. if (libuvBuilt) { return; }
  300. FindPython.find(builder.tmpFile(), waitFor(function (err, pythonExec) {
  301. if (err) { throw err; }
  302. python = pythonExec;
  303. }));
  304. }).nThen(function (waitFor) {
  305. if (libuvBuilt) { return; }
  306. console.log("Build Libuv");
  307. var cwd = process.cwd();
  308. process.chdir(dependencyDir + '/libuv/');
  309. var args = ['./gyp_uv.py'];
  310. var env = process.env;
  311. env.CC = builder.config.gcc;
  312. if (env.TARGET_ARCH) {
  313. args.push('-Dtarget_arch=' + env.TARGET_ARCH);
  314. }
  315. //args.push('--root-target=libuv');
  316. if (android) {
  317. args.push('-DOS=android');
  318. args.push('--format=make-linux')
  319. }
  320. if (builder.config.systemName === 'win32') {
  321. args.push('-DOS=win');
  322. }
  323. if (env.GYP_ADDITIONAL_ARGS) {
  324. args.push.apply(args, env.GYP_ADDITIONAL_ARGS.split(' '));
  325. }
  326. if (['freebsd', 'openbsd', 'netbsd'].indexOf(builder.config.systemName) !== -1) {
  327. // This platform lacks a functioning sem_open implementation, therefore...
  328. args.push('--no-parallel');
  329. args.push('-DOS=' + builder.config.systemName);
  330. }
  331. var gyp = Spawn(python, args, {env:env, stdio:'inherit'});
  332. gyp.on('error', function () {
  333. console.error("couldn't launch gyp [" + python + "]");
  334. });
  335. gyp.on('close', waitFor(function () {
  336. var args = [
  337. '-j', builder.processors,
  338. '-C', 'out',
  339. 'BUILDTYPE=Release',
  340. 'CC=' + builder.config.gcc,
  341. 'CXX=' + builder.config.gcc,
  342. 'V=1'
  343. ];
  344. var cflags = [builder.config.optimizeLevel, '-DNO_EMFILE_TRICK=1'];
  345. if (!/^\-O0$/.test(builder.config.optimizeLevel)) {
  346. cflags.push('-D_FORTIFY_SOURCE=2');
  347. }
  348. if (!(/darwin|win32/i.test(builder.config.systemName))) {
  349. cflags.push('-fPIC');
  350. }
  351. args.push('CFLAGS=' + cflags.join(' '));
  352. var makeCommand = ['freebsd', 'openbsd', 'netbsd'].indexOf(builder.config.systemName) >= 0 ? 'gmake' : 'make';
  353. var make = Spawn(makeCommand, args, {stdio: 'inherit'});
  354. make.on('error', function (err) {
  355. if (err.code === 'ENOENT') {
  356. console.error('\033[1;31mError: ' + makeCommand + ' is required!\033[0m');
  357. } else {
  358. console.error(
  359. '\033[1;31mFail run ' + process.cwd() + ': ' + makeCommand + ' '
  360. + args.join(' ') + '\033[0m'
  361. );
  362. console.error('Message:', err);
  363. }
  364. waitFor.abort();
  365. });
  366. make.on('close', waitFor(function () {
  367. process.chdir(cwd);
  368. }));
  369. }));
  370. }).nThen(waitFor());
  371. }).nThen(waitFor());
  372. }).build(function (builder, waitFor) {
  373. builder.buildExecutable('client/cjdroute2.c', 'cjdroute');
  374. builder.buildExecutable('contrib/c/publictoip6.c');
  375. builder.buildExecutable('contrib/c/privatetopublic.c');
  376. builder.buildExecutable('contrib/c/sybilsim.c');
  377. builder.buildExecutable('contrib/c/makekeys.c');
  378. builder.buildExecutable('contrib/c/mkpasswd.c');
  379. builder.buildExecutable('crypto/random/randombytes.c');
  380. builder.lintFiles(function (fileName, file, callback) {
  381. if (/dependencies/.test(fileName)) {
  382. callback('', false);
  383. return;
  384. }
  385. Codestyle.lint(fileName, file, callback);
  386. });
  387. var testcjdroute = builder.buildTest('test/testcjdroute.c');
  388. if (builder.config.crossCompiling) {
  389. console.log("Cross compiling. Building, but not running tests.");
  390. return;
  391. }
  392. var testRunner = TestRunner.local(['all']);
  393. if (process.env['REMOTE_TEST']) {
  394. testRunner = TestRunner.remote(process.env['REMOTE_TEST'], ['all']);
  395. }
  396. if (!process.env['NO_TEST']) {
  397. builder.runTest(testcjdroute, testRunner);
  398. }
  399. }).success(function (builder, waitFor) {
  400. console.log('\033[1;32mBuild completed successfully, type ./cjdroute to begin setup.\033[0m');
  401. }).failure(function (builder, waitFor) {
  402. console.log('\033[1;31mFailed to build cjdns.\033[0m');
  403. process.exit(1);
  404. }).complete(function (builder, waitFor) {
  405. if (builder.failure) {
  406. process.exit(1);
  407. }
  408. });