make.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  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 Os = require('os');
  21. var FindPython2 = require('./FindPython2');
  22. var CanCompile = require('./CanCompile');
  23. var Builder = require('./builder');
  24. var TestRunner = require('./TestRunner');
  25. // ['linux','darwin','sunos','win32','freebsd','openbsd']
  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. if (!GCC) {
  31. if (SYSTEM === 'freebsd') {
  32. GCC = 'gcc47';
  33. } else if (SYSTEM === 'openbsd') {
  34. GCC = 'egcc';
  35. } else {
  36. GCC = 'gcc';
  37. }
  38. }
  39. Builder.configure({
  40. systemName: SYSTEM,
  41. crossCompiling: process.env['CROSS'] !== undefined,
  42. gcc: GCC,
  43. tempDir: '/tmp',
  44. optimizeLevel: '-O2',
  45. logLevel: process.env['Log_LEVEL'] || 'DEBUG'
  46. }, function (builder, waitFor) {
  47. builder.config.cflags.push(
  48. '-std=c99',
  49. '-Wall',
  50. '-Wextra',
  51. '-Werror',
  52. '-Wno-pointer-sign',
  53. '-pedantic',
  54. '-D', builder.config.systemName + '=1',
  55. '-Wno-unused-parameter',
  56. '-Wno-unused-result',
  57. '-D', 'HAS_BUILTIN_CONSTANT_P',
  58. '-D', 'Log_' + builder.config.logLevel,
  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. if (process.env['TESTING']) {
  71. builder.config.cflags.push('-D', 'TESTING=1');
  72. }
  73. if (builder.config.systemName === 'win32') {
  74. builder.config.cflags.push('-Wno-format');
  75. } else if (builder.config.systemName === 'linux') {
  76. builder.config.ldflags.push('-Wl,-z,relro,-z,now,-z,noexecstack');
  77. builder.config.cflags.push('-DHAS_ETH_INTERFACE=1');
  78. }
  79. if (process.env['NO_PIE'] === undefined && builder.config.systemName !== 'freebsd'
  80. && builder.config.systemName !== 'win32')
  81. {
  82. builder.config.cflags.push('-fPIE');
  83. builder.config.ldflags.push('-pie');
  84. }
  85. if (/clang/i.test(builder.config.gcc) || builder.config.systemName === 'darwin') {
  86. // blows up when preprocessing before js preprocessor
  87. builder.config.cflags.push(
  88. '-Wno-invalid-pp-token',
  89. '-Wno-dollar-in-identifier-extension',
  90. '-Wno-newline-eof',
  91. '-Wno-unused-value',
  92. // lots of places where depending on preprocessor conditions, a statement might be
  93. // a case of if (1 == 1)
  94. '-Wno-tautological-compare'
  95. );
  96. }
  97. // Install any user-defined CFLAGS. Necessary if you are messing about with building cnacl
  98. // with NEON on the BBB
  99. if (CFLAGS) {
  100. [].push.apply(builder.config.cflags, CFLAGS.split(' '));
  101. }
  102. // We also need to pass various architecture/floating point flags to GCC when invoked as
  103. // a linker.
  104. if (LDFLAGS) {
  105. [].push.apply(builder.config.ldflags, LDFLAGS.split(' '));
  106. }
  107. if (/android/i.test(builder.config.gcc)) {
  108. builder.config.cflags.push('-Dandroid=1');
  109. }
  110. CanCompile.check(builder,
  111. 'int main() { return 0; }',
  112. [ builder.config.cflags, '-flto', '-x', 'c' ],
  113. function (err, can) {
  114. if (can) {
  115. console.log("Compiler supports link time optimization");
  116. builder.config.ldflags.push(
  117. '-flto',
  118. builder.config.optimizeLevel
  119. );
  120. // No optimization while building since actual compile happens during linking.
  121. builder.config.cflags.push('-O0');
  122. } else {
  123. console.log("Link time optimization not supported [" + err + "]");
  124. builder.config.cflags.push(builder.config.optimizeLevel);
  125. }
  126. });
  127. var uclibc = process.env['UCLIBC'] == '1';
  128. var libssp = process.env['SSP_SUPPORT'] == 'y';
  129. if (builder.config.systemName == 'win32') {
  130. builder.config.libs.push('-lssp');
  131. } else if ((!uclibc && builder.config.systemName !== 'sunos') || libssp) {
  132. builder.config.cflags.push(
  133. // Broken GCC patch makes -fstack-protector-all not work
  134. // workaround is to give -fno-stack-protector first.
  135. // see: https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/691722
  136. '-fno-stack-protector',
  137. '-fstack-protector-all',
  138. '-Wstack-protector'
  139. );
  140. // Static libssp provides __stack_chk_fail_local, which x86 needs in
  141. // order to avoid expensively looking up the location of __stack_chk_fail.
  142. var x86 = process.env['TARGET_ARCH'] == 'i386';
  143. if (uclibc) {
  144. if (x86) {
  145. builder.config.libs.push('-Wl,-Bstatic', '-lssp', '-Wl,-Bdynamic');
  146. } else {
  147. builder.config.libs.push('-lssp');
  148. }
  149. }
  150. } else {
  151. console.log("Stack Smashing Protection (security feature) is disabled");
  152. }
  153. var dependencyDir = builder.config.buildDir + '/dependencies';
  154. var libuvLib = dependencyDir + '/libuv/out/Release/libuv.a';
  155. if (builder.config.systemName === 'win32') {
  156. libuvLib = dependencyDir + '/libuv/out/Release/obj.target/libuv.a';
  157. }
  158. // Build dependencies
  159. nThen(function (waitFor) {
  160. Fs.exists(dependencyDir, waitFor(function (exists) {
  161. if (exists) { return; }
  162. console.log("Copy dependencies");
  163. Cp('./node_build/dependencies', dependencyDir, waitFor());
  164. }));
  165. }).nThen(function (waitFor) {
  166. builder.config.libs.push(dependencyDir + '/cnacl/jsbuild/libnacl.a');
  167. builder.config.includeDirs.push(dependencyDir + '/cnacl/jsbuild/include/');
  168. Fs.exists(dependencyDir + '/cnacl/jsbuild/libnacl.a', waitFor(function (exists) {
  169. if (exists) { return; }
  170. console.log("Build NaCl");
  171. var cwd = process.cwd();
  172. process.chdir(dependencyDir + '/cnacl/');
  173. var NaCl = require(process.cwd() + '/node_build/make.js');
  174. NaCl.build(function (args, callback) {
  175. if (builder.config.systemName !== 'win32') {
  176. args.unshift('-fPIC');
  177. }
  178. args.unshift('-O2', '-fomit-frame-pointer');
  179. if (CFLAGS) {
  180. [].push.apply(args, CFLAGS.split(' '));
  181. }
  182. builder.cc(args, callback);
  183. }, waitFor(function () {
  184. process.chdir(cwd);
  185. }));
  186. }));
  187. }).nThen(function (waitFor) {
  188. builder.config.libs.push(libuvLib);
  189. if (!(/android/i.test(builder.config.gcc))) {
  190. builder.config.libs.push('-lpthread');
  191. }
  192. if (builder.config.systemName === 'win32') {
  193. builder.config.libs.push(
  194. '-lws2_32',
  195. '-lpsapi', // GetProcessMemoryInfo()
  196. '-liphlpapi' // GetAdapterAddresses()
  197. );
  198. } else if (builder.config.systemName === 'linux'
  199. && !(/android/i).test(builder.config.gcc))
  200. {
  201. builder.config.libs.push('-lrt'); // clock_gettime()
  202. } else if (builder.config.systemName === 'darwin') {
  203. builder.config.libs.push('-framework', 'CoreServices');
  204. } else if (['freebsd', 'openbsd'].indexOf(builder.config.systemName) >= 0) {
  205. builder.config.cflags.push('-Wno-overlength-strings');
  206. builder.config.libs.push('-lkvm');
  207. } else if (builder.config.systemName === 'sunos') {
  208. builder.config.libs.push(
  209. '-lsocket',
  210. '-lsendfile',
  211. '-lkstat',
  212. '-lnsl'
  213. );
  214. }
  215. builder.config.includeDirs.push(dependencyDir + '/libuv/include/');
  216. var libuvBuilt;
  217. var python;
  218. nThen(function (waitFor) {
  219. Fs.exists(libuvLib, waitFor(function (exists) {
  220. if (exists) { libuvBuilt = true; }
  221. }));
  222. }).nThen(function (waitFor) {
  223. if (libuvBuilt) { return; }
  224. FindPython2.find(builder.tmpFile(), waitFor(function (err, pythonExec) {
  225. if (err) { throw err; }
  226. python = pythonExec;
  227. }));
  228. }).nThen(function (waitFor) {
  229. if (libuvBuilt) { return; }
  230. console.log("Build Libuv");
  231. var cwd = process.cwd();
  232. process.chdir(dependencyDir + '/libuv/');
  233. var args = ['./gyp_uv.py'];
  234. var env = process.env;
  235. env.CC = builder.config.gcc;
  236. if (env.TARGET_ARCH) {
  237. args.push('-Dtarget_arch=' + env.TARGET_ARCH);
  238. }
  239. //args.push('--root-target=libuv');
  240. if (/.*android.*/.test(builder.config.gcc)) {
  241. args.push('-DOS=android');
  242. }
  243. if (builder.config.systemName === 'win32') {
  244. args.push('-DOS=win');
  245. }
  246. var gyp = Spawn(python, args, {env:env, stdio:'inherit'});
  247. gyp.on('error', function () {
  248. console.error("couldn't launch gyp [" + python + "]");
  249. });
  250. gyp.on('close', waitFor(function () {
  251. var args = [
  252. '-j', builder.processors,
  253. '-C', 'out',
  254. 'BUILDTYPE=Release',
  255. 'CC=' + builder.config.gcc,
  256. 'CXX=' + builder.config.gcc,
  257. 'V=1'
  258. ];
  259. if (!(/darwin|win32/i.test(builder.config.systemName))) {
  260. args.push('CFLAGS=-fPIC');
  261. }
  262. var makeCommand = ['freebsd', 'openbsd'].indexOf(builder.config.systemName) >= 0 ? 'gmake' : 'make';
  263. var make = Spawn(makeCommand, args, {stdio: 'inherit'});
  264. make.on('error', function (err) {
  265. if (err.code === 'ENOENT') {
  266. console.error('\033[1;31mError: ' + makeCommand + ' is required!\033[0m');
  267. } else {
  268. console.error(
  269. '\033[1;31mFail run ' + process.cwd() + ': ' + makeCommand + ' '
  270. + args.join(' ') + '\033[0m'
  271. );
  272. console.error('Message:', err);
  273. }
  274. waitFor.abort();
  275. });
  276. make.on('close', waitFor(function () {
  277. process.chdir(cwd);
  278. }));
  279. }));
  280. }).nThen(waitFor());
  281. }).nThen(waitFor());
  282. }).build(function (builder, waitFor) {
  283. builder.buildExecutable('admin/angel/cjdroute2.c', 'cjdroute');
  284. builder.buildExecutable('contrib/c/publictoip6.c');
  285. builder.buildExecutable('contrib/c/privatetopublic.c');
  286. builder.buildExecutable('contrib/c/sybilsim.c');
  287. builder.buildExecutable('contrib/c/makekeys.c');
  288. builder.buildExecutable('crypto/random/randombytes.c');
  289. builder.lintFiles(function (fileName, file, callback) {
  290. if (/dependencies/.test(fileName)) {
  291. callback('', false);
  292. return;
  293. }
  294. Codestyle.lint(fileName, file, callback);
  295. });
  296. var testcjdroute = builder.buildTest('test/testcjdroute.c');
  297. if (builder.config.crossCompiling) {
  298. console.log("Cross compiling. Building, but not running tests.");
  299. return;
  300. }
  301. var testRunner = TestRunner.local(['all']);
  302. if (process.env['REMOTE_TEST']) {
  303. testRunner = TestRunner.remote(process.env['REMOTE_TEST'], ['all']);
  304. }
  305. builder.runTest(testcjdroute, testRunner);
  306. }).success(function (builder, waitFor) {
  307. console.log('\033[1;32mBuild completed successfully, type ./cjdroute to begin setup.\033[0m');
  308. }).failure(function (builder, waitFor) {
  309. console.log('\033[1;31mFailed to build cjdns.\033[0m');
  310. process.exit(1);
  311. }).complete(function (builder, waitFor) {
  312. if (builder.failure) {
  313. process.exit(1);
  314. }
  315. });