make.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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 Cp = require('./Cp');
  20. var Builder = require('./builder');
  21. const CjdnsTest = require('./CjdnsTest');
  22. const GetVersion = require('./GetVersion');
  23. var CFLAGS = process.env['CFLAGS'];
  24. var LDFLAGS = process.env['LDFLAGS'];
  25. // march=native really only makes a lot of sense on x86/amd64 where the available features
  26. // are a hodgepodge per-CPU. On arm (32) you may or may not have NEON available but in any
  27. // case clang doesn't reliably support march except on x86/amd64.
  28. var NO_MARCH_FLAG = ['arm', 'ppc', 'ppc64', 'arm64'];
  29. if (process.version.replace('v','').split('.').map(Number)[0] >= 12) {
  30. // OK
  31. } else if ('OLD_NODE_VERSION_I_EXPECT_ERRORS' in process.env) {
  32. console.log('OLD_NODE_VERSION_I_EXPECT_ERRORS is set, ignoring old version');
  33. } else {
  34. throw new Error("Your version of nodejs is old/untested. " +
  35. "Old enough versions (pre-es6) do not work correctly and give weird build failures. " +
  36. "If you want to force building anyway, try: " +
  37. "OLD_NODE_VERSION_I_EXPECT_ERRORS=1 ./do");
  38. }
  39. Builder.configure({
  40. buildDir: process.env['OUT_DIR'], // set by cargo
  41. systemName: process.env['SYSTEM'] || process.platform,
  42. gcc: process.env['CC'],
  43. }, function (builder, waitFor) {
  44. builder.config.crossCompiling = process.env['CROSS'] !== undefined;
  45. let optimizeLevel = '-O2';
  46. builder.config.cflags.push(
  47. '-std=c11',
  48. '-Wall',
  49. '-Wextra',
  50. //'-Werror',
  51. '-Wno-pointer-sign',
  52. '-Wno-strict-prototypes',
  53. '-Wmissing-prototypes',
  54. '-pedantic',
  55. '-D', builder.config.systemName + '=1',
  56. '-Wno-unused-parameter',
  57. '-fomit-frame-pointer',
  58. '-ffunction-sections',
  59. '-fdata-sections',
  60. '-D', 'Log_' + (process.env['Log_LEVEL'] || 'DEBUG'),
  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. // Noise protocol causes huge problems for beacon session setup
  72. '-D', 'NOISE_NO=1'
  73. );
  74. if (process.env["CJDNS_RELEASE_VERSION"]) {
  75. builder.config.version = '' + process.env["CJDNS_RELEASE_VERSION"];
  76. }
  77. if (process.env['SUBNODE']) { builder.config.cflags.push('-DSUBNODE=1'); }
  78. if (process.env['GCOV']) {
  79. builder.config.cflags.push('-fprofile-arcs', '-ftest-coverage');
  80. builder.config.ldflags.push('-fprofile-arcs', '-ftest-coverage');
  81. }
  82. var android = /android/i.test(builder.config.gcc);
  83. if (process.env['TESTING']) {
  84. builder.config.cflags.push('-D', 'TESTING=1');
  85. }
  86. if (process.env['ADDRESS_PREFIX']) {
  87. builder.config.cflags.push('-D', 'ADDRESS_PREFIX=' + process.env['ADDRESS_PREFIX']);
  88. }
  89. if (process.env['ADDRESS_PREFIX_BITS']) {
  90. builder.config.cflags.push('-D', 'ADDRESS_PREFIX_BITS=' + process.env['ADDRESS_PREFIX_BITS']);
  91. }
  92. if (!builder.config.crossCompiling) {
  93. if (NO_MARCH_FLAG.indexOf(process.arch) == -1) {
  94. builder.config.cflags.push('-march=native');
  95. }
  96. }
  97. if (builder.config.systemName === 'win32') {
  98. builder.config.cflags.push('-Wno-format');
  99. } else if (builder.config.systemName === 'linux') {
  100. builder.config.ldflags.push('-Wl,-z,relro,-z,now,-z,noexecstack');
  101. builder.config.cflags.push('-DHAS_ETH_INTERFACE=1');
  102. } else if (builder.config.systemName === 'darwin') {
  103. builder.config.cflags.push('-DHAS_ETH_INTERFACE=1');
  104. }
  105. if (process.env['NO_PIE'] === undefined && builder.config.systemName !== 'freebsd'
  106. && builder.config.systemName !== 'win32') {
  107. builder.config.cflags.push('-fPIE');
  108. // just using `-pie` on OS X >= 10.10 results in this warning:
  109. // clang: warning: argument unused during compilation: '-pie'
  110. if (builder.config.systemName !== "darwin") {
  111. builder.config.ldflags.push('-pie');
  112. } else {
  113. builder.config.ldflags.push('-Wl,-pie');
  114. }
  115. }
  116. if (builder.compilerType().isClang) {
  117. // blows up when preprocessing before js preprocessor
  118. builder.config.cflags.push(
  119. '-Wno-invalid-pp-token',
  120. '-Wno-dollar-in-identifier-extension',
  121. '-Wno-newline-eof',
  122. '-Wno-unused-value',
  123. // lots of places where depending on preprocessor conditions, a statement might be
  124. // a case of if (1 == 1)
  125. '-Wno-tautological-compare',
  126. //'-Wno-error'
  127. '-Wno-gnu-line-marker'
  128. );
  129. } else {
  130. builder.config.cflags.push(
  131. '-fdiagnostics-color=always'
  132. );
  133. }
  134. // Install any user-defined CFLAGS. Necessary if you are messing about with building cnacl
  135. // with NEON on the BBB, or want to set -Os (OpenWrt)
  136. // Allow -O0 so while debugging all variables are present.
  137. if (CFLAGS) {
  138. var cflags = CFLAGS.split(' ');
  139. cflags.forEach(function (flag) {
  140. if (/^\-O[^02s]$/.test(flag)) {
  141. console.log("Skipping " + flag + ", assuming " + optimizeLevel + " instead.");
  142. } else if (/^\-O[02s]$/.test(flag)) {
  143. optimizeLevel = flag;
  144. } else {
  145. builder.config.cflags.push(flag);
  146. }
  147. });
  148. }
  149. builder.config.cflags.push(optimizeLevel);
  150. if (!/^\-O0$/.test(optimizeLevel)) {
  151. builder.config.cflags.push('-D_FORTIFY_SOURCE=2');
  152. }
  153. // We also need to pass various architecture/floating point flags to GCC when invoked as
  154. // a linker.
  155. if (LDFLAGS) {
  156. [].push.apply(builder.config.ldflags, LDFLAGS.split(' '));
  157. }
  158. if (android) {
  159. // NDK uses the word `android` in places
  160. builder.config.cflags.push('-DCjdns_android=1');
  161. }
  162. var uclibc = process.env['UCLIBC'] == '1';
  163. var libssp;
  164. switch (process.env['SSP_SUPPORT']) {
  165. case 'y':
  166. case '1': libssp = true; break;
  167. case 'n':
  168. case '':
  169. case '0': libssp = false; break;
  170. case undefined: break;
  171. default: throw new Error();
  172. }
  173. if (libssp === false) {
  174. console.log("Stack Smashing Protection (security feature) is disabled");
  175. } else if (builder.config.systemName == 'win32') {
  176. builder.config.libs.push('-lssp');
  177. } else if ((!uclibc && builder.config.systemName !== 'sunos') || libssp === true) {
  178. builder.config.cflags.push(
  179. // Broken GCC patch makes -fstack-protector-all not work
  180. // workaround is to give -fno-stack-protector first.
  181. // see: https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/691722
  182. '-fno-stack-protector',
  183. '-fstack-protector-all',
  184. '-Wstack-protector'
  185. );
  186. // Static libssp provides __stack_chk_fail_local, which x86 needs in
  187. // order to avoid expensively looking up the location of __stack_chk_fail.
  188. var x86 = process.env['TARGET_ARCH'] == 'i386';
  189. if (uclibc) {
  190. if (x86) {
  191. builder.config.libs.push('-Wl,-Bstatic', '-lssp', '-Wl,-Bdynamic');
  192. } else {
  193. builder.config.libs.push('-lssp');
  194. }
  195. }
  196. } else {
  197. console.log("Stack Smashing Protection (security feature) is disabled");
  198. }
  199. if (process.env['Pipe_PREFIX']) {
  200. builder.config.cflags.push(
  201. '-D', 'Pipe_PREFIX="' + process.env['Pipe_PREFIX'] + '"'
  202. );
  203. }
  204. if (typeof (builder.config.cjdnsTest_files) === 'undefined') {
  205. CjdnsTest.generate(builder, process.env['SUBNODE'] !== '', waitFor());
  206. }
  207. nThen((w) => {
  208. if (builder.config.version) { return; }
  209. GetVersion(w(function (err, data) {
  210. if (!err) {
  211. builder.config.version = ('' + data).replace(/(\r\n|\n|\r)/gm, "");
  212. } else {
  213. builder.config.version = 'unknown';
  214. }
  215. }));
  216. }).nThen((w) => {
  217. builder.config.cflags.push('-D', 'CJD_PACKAGE_VERSION="' + builder.config.version + '"');
  218. }).nThen(waitFor());
  219. // Build dependencies
  220. let foundSodium = false;
  221. nThen(function (waitFor) {
  222. const dir = `${builder.config.buildDir}/../..`;
  223. Fs.readdir(dir, waitFor((err, ret) => {
  224. if (err) { throw err; }
  225. ret.forEach((f) => {
  226. if (!/^libsodium-sys-/.test(f)) { return; }
  227. const inclPath = `${dir}/${f}/out/source/libsodium/src/libsodium/include`;
  228. Fs.readdir(inclPath, waitFor((err, ret) => {
  229. if (foundSodium) { return; }
  230. if (err && err.code === 'ENOENT') { return; }
  231. if (err) { throw err; }
  232. builder.config.includeDirs.push(inclPath);
  233. foundSodium = true;
  234. }));
  235. });
  236. }));
  237. }).nThen(function (waitFor) {
  238. if (!foundSodium) {
  239. throw new Error("Unable to find a path to libsodium headers");
  240. }
  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('node_build/dependencies/libuv/include/');
  266. builder.config.includeDirs.push('node_build/dependencies/libuv/src/');
  267. }).nThen(waitFor());
  268. }).build(function (builder, waitFor) {
  269. builder.buildLibrary('client/cjdroute2.c');
  270. builder.buildLibrary('contrib/c/publictoip6.c');
  271. builder.buildLibrary('contrib/c/privatetopublic.c');
  272. builder.buildLibrary('contrib/c/makekeys.c');
  273. builder.buildLibrary('contrib/c/mkpasswd.c');
  274. builder.buildLibrary('crypto/random/randombytes.c');
  275. builder.buildLibrary('rust/cjdns_sys/cffi.h');
  276. builder.buildLibrary('test/testcjdroute.c');
  277. }).failure(function (builder, waitFor) {
  278. console.log('\x1b[1;31mFailed to build cjdns.\x1b[0m');
  279. process.exit(1);
  280. });