BrickUp API Service for Docker version.

make.js 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. var crypto = require('crypto');
  2. var fs = require('fs');
  3. var fse = require('fs-extra');
  4. var path = require('path');
  5. var child_process = require('child_process');
  6. var co = require('co');
  7. var S = require('string');
  8. var filewalker = require('filewalker');
  9. var dependencies = require('../data/Dependencies');
  10. var Builder = module.exports = function(basePath, sources) {
  11. this.avrconfig = {
  12. Path:'/usr/share/arduino/hardware/tools/avr/bin',
  13. BOARD_TAG: 'uno',
  14. Tools: {
  15. CC_NAME: 'avr-gcc',
  16. CXX_NAME: 'avr-g++',
  17. OBJCOPY_NAME: 'avr-objcopy',
  18. AR_NAME: 'avr-ar',
  19. SIZE_NAME: 'avr-size',
  20. NM_NAME: 'avr-nm'
  21. }
  22. };
  23. this.id = null;
  24. this.filename = 'main.ino';
  25. this.lib = {
  26. Path: {
  27. core: path.join(__dirname, '..', 'libraries/core'),
  28. external: path.join(__dirname, '..', 'libraries/external'),
  29. thirdparty: path.join(__dirname, '..', 'libraries/thirdparty')
  30. },
  31. libs: {
  32. core: [],
  33. external: [],
  34. thirdparty: []
  35. },
  36. dirs: {
  37. external: [],
  38. thirdparty: []
  39. }
  40. };
  41. this.basePath = basePath;
  42. this.sources = sources || {};
  43. this.workingPath = '';
  44. };
  45. Builder.prototype.init = function(callback) {
  46. var self = this;
  47. self.id = crypto.randomBytes(16).toString('hex').substr(0, 8) + Date.now();
  48. self.workingPath = path.join(self.basePath, self.id);
  49. fse.mkdirs(self.workingPath, function(err) {
  50. if (callback)
  51. callback(err);
  52. });
  53. };
  54. Builder.prototype.scanLibraries = function(callback) {
  55. var self = this;
  56. co(function *() {
  57. try {
  58. // Scanning core libraries
  59. self.lib.libs.core = yield function(done) {
  60. fs.readdir(self.lib.Path.core, done);
  61. };
  62. } catch(e) {}
  63. yield function(done) {
  64. filewalker(self.lib.Path.thirdparty)
  65. .on('dir', function(p) {
  66. if(!S(p).contains('/')){
  67. //console.log('dir: %s', p);
  68. self.lib.dirs.thirdparty.push(p);
  69. }
  70. })
  71. .on('file', function(p, s) {
  72. if(S(p).contains('.o')){
  73. //console.log('file: %s, %d bytes', p, s.size);
  74. self.lib.libs.thirdparty.push(p);
  75. }
  76. })
  77. .on('error', function(err) {
  78. console.error(err);
  79. })
  80. .on('done', function() {
  81. //console.log('%d dirs, %d files, %d bytes', this.dirs, this.files, this.bytes);
  82. done();
  83. })
  84. .walk();
  85. };
  86. yield function(done) {
  87. filewalker(self.lib.Path.external)
  88. .on('dir', function(p) {
  89. if(!S(p).contains('/')){
  90. //console.log('dir: %s', p);
  91. self.lib.dirs.external.push(p);
  92. }
  93. })
  94. .on('file', function(p, s) {
  95. if(S(p).contains('.o')){
  96. //console.log('file: %s, %d bytes', p, s.size);
  97. self.lib.libs.external.push(p);
  98. }
  99. })
  100. .on('error', function(err) {
  101. console.error(err);
  102. })
  103. .on('done', function() {
  104. //console.log('%d dirs, %d files, %d bytes', this.dirs, this.files, this.bytes);
  105. done();
  106. })
  107. .walk();
  108. };
  109. if (callback)
  110. callback();
  111. });
  112. };
  113. Builder.prototype.scanSources = function(callback) {
  114. var self = this;
  115. var content = '';
  116. var tmplist = [];
  117. var filepath = path.join(self.workingPath, self.filename);
  118. co(function *() {
  119. try {
  120. content = yield function(done) {
  121. fs.readFile(filepath, done);
  122. };
  123. } catch(e) {}
  124. var lines = S(content.toString()).lines();
  125. lines.forEach(function(line, index, array) {
  126. if(S(line).contains('#include')){
  127. if(!S(line).contains('stdio')){
  128. tmplist.push(S(line).between('#include <', '.h>').s);
  129. }
  130. }
  131. else if (S(line).contains('Serial.begin')) {
  132. tmplist.push('SoftwareSerial');
  133. }
  134. else{
  135. }
  136. });
  137. if (callback)
  138. callback(null, tmplist);
  139. });
  140. };
  141. Builder.prototype.parseOps = function(liblist, callback) {
  142. var self = this;
  143. var prelinkOps = [];
  144. var current = '';
  145. function checklib(lib) {
  146. return S(lib).contains(current+'.o');
  147. }
  148. function checkutilitylib(lib, index, array) {
  149. if (S(lib).contains(current+'/utility/')){
  150. prelinkOps.push( path.join(self.lib.Path.external, lib) );
  151. }
  152. return true;
  153. }
  154. liblist.forEach(function(lib, index, array) {
  155. current = lib;
  156. var externaltmp = self.lib.libs.external.findIndex(checklib);
  157. var thirdpartytmp = self.lib.libs.thirdparty.findIndex(checklib);
  158. if(externaltmp != -1){
  159. prelinkOps.push( path.join(self.lib.Path.external, self.lib.libs.external[externaltmp]) );
  160. if ( lib == 'Ethernet' ||
  161. lib == 'SD' ||
  162. lib == 'TFT' ||
  163. lib == 'Wire' ){
  164. self.lib.libs.external.every(checkutilitylib);
  165. }
  166. }
  167. else if(thirdpartytmp != -1){
  168. prelinkOps.push(path.join(self.lib.Path.thirdparty, self.lib.libs.thirdparty[thirdpartytmp]));
  169. }
  170. else{
  171. console.log('[parseOps]none.');
  172. }
  173. });
  174. if (callback)
  175. callback(null, prelinkOps);
  176. };
  177. Builder.prototype.parseDeps = function(liblist, prelinkOps, callback) {
  178. var self = this;
  179. var linkOps = prelinkOps;
  180. liblist.forEach(function(lib, index, array) {
  181. for (var prop in dependencies) {
  182. if (prop == lib){
  183. var checkDeps = dependencies[prop];
  184. if(checkDeps.external){
  185. checkDeps.external.forEach(function(dep, index, array) {
  186. linkOps.push( path.join(self.lib.Path.external, dep) );
  187. });
  188. }
  189. if(checkDeps.thirdparty){
  190. checkDeps.thirdparty.forEach(function(dep, index, array) {
  191. linkOps.push( path.join(self.lib.Path.thirdparty, dep) );
  192. });
  193. }
  194. }
  195. }
  196. });
  197. if (callback)
  198. callback(null, linkOps);
  199. };
  200. Builder.prototype.generateSources = function(callback) {
  201. var self = this;
  202. co(function *() {
  203. // Generating all source files
  204. for (var filename in self.sources) {
  205. var filepath = path.join(self.workingPath, self.filename); // Need to be fixed.
  206. yield function(done) {
  207. fse.outputFile(filepath, self.sources[filename], done);
  208. };
  209. }
  210. if (callback)
  211. callback();
  212. });
  213. };
  214. Builder.prototype.generateCompileOps = function(linkOps, callback) {
  215. var self = this;
  216. var Ops = {
  217. CXX: [],
  218. AR: [],
  219. CC: [],
  220. OBJCOPY_eep: [],
  221. OBJCOPY_hex: []
  222. }
  223. var preCXX = [path.join(self.avrconfig.Path, self.avrconfig.Tools.CXX_NAME),
  224. '-x c++',
  225. '-include /usr/share/arduino/hardware/arduino/cores/arduino/Arduino.h',
  226. '-MMD -c -mmcu=atmega328p',
  227. '-DF_CPU=16000000L',
  228. '-DARDUINO=105',
  229. '-D__PROG_TYPES_COMPAT__',
  230. '-I. -I/usr/share/arduino/hardware/arduino/cores/arduino -I/usr/share/arduino/hardware/arduino/variants/standard'
  231. ];
  232. self.lib.dirs.external.forEach(function(lib, index, array) {
  233. preCXX.push('-I/usr/share/arduino/libraries/' + lib);
  234. });
  235. self.lib.dirs.thirdparty.forEach(function(lib, index, array) {
  236. preCXX.push('-I' + path.join(__dirname, '../libraries/thirdparty', lib));
  237. });
  238. preCXX.push('-Wall -ffunction-sections -fdata-sections -Os -fno-exceptions ',
  239. path.join(self.workingPath, self.filename),
  240. '-o ' + path.join(self.workingPath, self.id + '.o'));
  241. Ops.CXX = preCXX.join(' ');
  242. var preAR = [path.join(self.avrconfig.Path, self.avrconfig.Tools.AR_NAME),
  243. 'rcs',
  244. path.join(self.workingPath, 'libcore.a')
  245. ];
  246. self.lib.libs.core.forEach(function(lib, index, array) {
  247. preAR.push(path.join(__dirname, '../libraries/core', lib));
  248. });
  249. linkOps.forEach(function(lib, index, array) {
  250. preAR.push(lib);
  251. });
  252. Ops.AR = preAR.join(' ');
  253. Ops.CC = [path.join(self.avrconfig.Path, self.avrconfig.Tools.CC_NAME),
  254. '-mmcu=atmega328p',
  255. '-Wl,--gc-sections -Os',
  256. '-o ' + path.join(self.workingPath, self.id + '.elf'),
  257. path.join(self.workingPath, self.id + '.o'),
  258. path.join(self.workingPath, 'libcore.a'),
  259. '-lc -lm'
  260. ].join(' ');
  261. Ops.OBJCOPY_eep = [path.join(self.avrconfig.Path, self.avrconfig.Tools.OBJCOPY_NAME),
  262. '-j .eeprom --set-section-flags=.eeprom="alloc,load"',
  263. '--change-section-lma .eeprom=0 -O ihex',
  264. path.join(self.workingPath, self.id + '.elf'),
  265. path.join(self.workingPath, self.id + '.eep')
  266. ].join(' ');
  267. Ops.OBJCOPY_hex = [path.join(self.avrconfig.Path, self.avrconfig.Tools.OBJCOPY_NAME),
  268. '-O ihex -R .eeprom',
  269. path.join(self.workingPath, self.id + '.elf'),
  270. path.join(self.workingPath, self.id + '.hex')
  271. ].join(' ');
  272. if (callback)
  273. callback(null, Ops);
  274. };
  275. Builder.prototype.compile = function(CompileOps, callback) {
  276. var self = this;
  277. co(function *() {
  278. try {
  279. yield function(done) {
  280. child_process.exec(CompileOps.CXX, done);
  281. };
  282. } catch(e) {}
  283. try {
  284. yield function(done) {
  285. child_process.exec(CompileOps.AR, done);
  286. };
  287. } catch(e) {}
  288. try {
  289. yield function(done) {
  290. child_process.exec(CompileOps.CC, done);
  291. };
  292. } catch(e) {}
  293. try {
  294. yield function(done) {
  295. child_process.exec(CompileOps.OBJCOPY_eep, done);
  296. };
  297. } catch(e) {}
  298. child_process.exec(CompileOps.OBJCOPY_hex, function(err, cmdout, cmderr) {
  299. if (err) {
  300. callback(err);
  301. } else if (callback) {
  302. return callback(null, path.join(self.workingPath, self.id + '.hex'));
  303. }
  304. });
  305. });
  306. };