make.js 16 KB

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