_build.inc.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601
  1. /* ----- header.c ----- */
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <ctype.h>
  6. #include <errno.h>
  7. #include <stdarg.h>
  8. #include <signal.h>
  9. #include <unistd.h>
  10. #include <sys/prctl.h>
  11. #include <pty.h>
  12. #include <fcntl.h>
  13. #include <fnmatch.h>
  14. #include <dirent.h>
  15. #include <libgen.h>
  16. #include <sys/stat.h>
  17. #include <sys/types.h>
  18. #include <sys/wait.h>
  19. #include <sys/sysinfo.h>
  20. // link with -lutil
  21. // list all <header> files in use
  22. //egrep -ro '^\s*#\s*include\s+<(.*)>' src/ | sed -e 's/^.*<\(.*\)>.*$/\1/'
  23. #define PP_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, N, ...) N
  24. #define PP_RSEQ_N() 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
  25. #define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
  26. #define PP_NARG(...) PP_NARG_(__VA_ARGS__, PP_RSEQ_N())
  27. #define check_alloc(x) \
  28. if((x)->len + 1 >= (x)->alloc) { \
  29. (x)->alloc *= 2; \
  30. (x)->entries = realloc((x)->entries, (x)->alloc * sizeof(*(x)->entries)); \
  31. }
  32. char** g_gcc_opts_list;
  33. char* g_gcc_opts_flat;
  34. char* g_gcc_include;
  35. char* g_gcc_libs;
  36. int g_nprocs;
  37. typedef struct {
  38. // user config
  39. char** sources;
  40. char** debug_cflags;
  41. char** release_cflags;
  42. char** profiling_cflags;
  43. char** common_cflags;
  44. char** libs_needed;
  45. char** lib_headers_needed;
  46. char** ld_add;
  47. char* source_dir;// "src"
  48. char* exe_path; // the executable name
  49. char* base_build_dir; // = "build";
  50. char mode_debug;
  51. char mode_profiling;
  52. char mode_release;
  53. char clean_first;
  54. char verbose;
  55. // internally calculated
  56. char** gcc_opts_list;
  57. char* gcc_opts_flat;
  58. char* gcc_include;
  59. char* gcc_libs;
  60. char* build_dir; // full build path, including debug/release options
  61. char* build_subdir;
  62. } objfile;
  63. /* -END- header.c ----- */
  64. /* ----- string.c ----- */
  65. #define strjoin(j, ...) strjoin_(j, PP_NARG(__VA_ARGS__), __VA_ARGS__)
  66. char* strjoin_(char* joiner, size_t nargs, ...);
  67. #define strcatdup(...) strcatdup_(PP_NARG(__VA_ARGS__), __VA_ARGS__)
  68. char* strcatdup_(size_t nargs, ...);
  69. size_t list_len(char** list);
  70. char* join_str_list(char* list[], char* joiner);
  71. char* sprintfdup(char* fmt, ...);
  72. #define path_join(...) path_join_(PP_NARG(__VA_ARGS__), __VA_ARGS__)
  73. char* path_join_(size_t nargs, ...);
  74. #define concat_lists(...) concat_lists_(PP_NARG(__VA_ARGS__), __VA_ARGS__)
  75. char** concat_lists_(int nargs, ...);
  76. size_t span_path(char* s) {
  77. size_t n = 0;
  78. for(; *s; s++, n++) {
  79. if(isspace(*s)) break;
  80. if(*s == '\\') {
  81. s++;
  82. n++;
  83. }
  84. }
  85. return n;
  86. }
  87. // splits on whitespace
  88. char** strsplit(char* splitters, char* in) {
  89. char* e;
  90. int alloc = 32;
  91. int len = 0;
  92. char** list = malloc(alloc * sizeof(*list));
  93. for(char* s = in; *s;) {
  94. e = strpbrk(s, splitters);
  95. if(!e) e = s + strlen(s);
  96. if(len >= alloc - 1) {
  97. alloc *= 2;
  98. list = realloc(list, alloc* sizeof(*list));
  99. }
  100. list[len++] = strndup(s, e - s);
  101. e += strspn(e, splitters);
  102. s = e;
  103. }
  104. list[len] = NULL;
  105. return list;
  106. }
  107. static inline char* strskip(char* s, char* skip) {
  108. return s + strspn(s, skip);
  109. }
  110. // concatenate all argument strings together in a new buffer
  111. char* strcatdup_(size_t nargs, ...) {
  112. size_t total = 0;
  113. char* out, *end;
  114. if(nargs == 0) return NULL;
  115. // calculate total buffer len
  116. va_list va;
  117. va_start(va, nargs);
  118. for(size_t i = 0; i < nargs; i++) {
  119. char* s = va_arg(va, char*);
  120. if(s) total += strlen(s);
  121. }
  122. va_end(va);
  123. out = malloc((total + 1) * sizeof(char*));
  124. end = out;
  125. va_start(va, nargs);
  126. for(size_t i = 0; i < nargs; i++) {
  127. char* s = va_arg(va, char*);
  128. if(s) {
  129. strcpy(end, s); // not exactly the ost efficient, but maybe faster than
  130. end += strlen(s); // a C version. TODO: test the speed
  131. };
  132. }
  133. va_end(va);
  134. *end = 0;
  135. return out;
  136. }
  137. // concatenate all argument strings together in a new buffer,
  138. // with the given joining string between them
  139. char* strjoin_(char* joiner, size_t nargs, ...) {
  140. size_t total = 0;
  141. char* out, *end;
  142. size_t j_len;
  143. if(nargs == 0) return NULL;
  144. // calculate total buffer len
  145. va_list va;
  146. va_start(va, nargs);
  147. for(size_t i = 0; i < nargs; i++) {
  148. char* s = va_arg(va, char*);
  149. if(s) total += strlen(s);
  150. }
  151. va_end(va);
  152. j_len = strlen(joiner);
  153. total += j_len * (nargs - 1);
  154. out = malloc((total + 1) * sizeof(char*));
  155. end = out;
  156. va_start(va, nargs);
  157. for(size_t i = 0; i < nargs; i++) {
  158. char* s = va_arg(va, char*);
  159. if(s) {
  160. if(i > 0) {
  161. strcpy(end, joiner);
  162. end += j_len;
  163. }
  164. strcpy(end, s); // not exactly the ost efficient, but maybe faster than
  165. end += strlen(s); // a C version. TODO: test the speed
  166. };
  167. }
  168. va_end(va);
  169. *end = 0;
  170. return out;
  171. }
  172. // allocates a new buffer and calls sprintf with it
  173. // why isn't this a standard function?
  174. char* sprintfdup(char* fmt, ...) {
  175. va_list va;
  176. va_start(va, fmt);
  177. size_t n = vsnprintf(NULL, 0, fmt, va);
  178. char* buf = malloc(n + 1);
  179. va_end(va);
  180. va_start(va, fmt);
  181. vsnprintf(buf, n + 1, fmt, va);
  182. va_end(va);
  183. return buf;
  184. }
  185. void free_strpp(char** l) {
  186. for(char** s = l; *s; s++) free(*s);
  187. free(l);
  188. }
  189. size_t list_len(char** list) {
  190. size_t total = 0;
  191. for(; *list; list++) total++;
  192. return total;
  193. }
  194. char** concat_lists_(int nargs, ...) {
  195. size_t total = 0;
  196. char** out, **end;
  197. if(nargs == 0) return NULL;
  198. // calculate total list length
  199. va_list va;
  200. va_start(va, nargs);
  201. for(size_t i = 0; i < nargs; i++) {
  202. char** s = va_arg(va, char**);
  203. if(s) total += list_len(s);
  204. }
  205. va_end(va);
  206. out = malloc((total + 1) * sizeof(char**));
  207. end = out;
  208. va_start(va, nargs);
  209. // concat lists
  210. for(size_t i = 0; i < nargs; i++) {
  211. char** s = va_arg(va, char**);
  212. size_t l = list_len(s);
  213. if(s) {
  214. memcpy(end, s, l * sizeof(*s));
  215. end += l;
  216. }
  217. }
  218. va_end(va);
  219. *end = 0;
  220. return out;
  221. }
  222. char* join_str_list(char* list[], char* joiner) {
  223. size_t list_len = 0;
  224. size_t total = 0;
  225. size_t jlen = strlen(joiner);
  226. // calculate total length
  227. for(int i = 0; list[i]; i++) {
  228. list_len++;
  229. total += strlen(list[i]);
  230. }
  231. if(total == 0) return strdup("");
  232. total += (list_len - 1) * jlen;
  233. char* out = malloc((total + 1) * sizeof(*out));
  234. char* end = out;
  235. for(int i = 0; list[i]; i++) {
  236. char* s = list[i];
  237. size_t l = strlen(s);
  238. if(i > 0) {
  239. memcpy(end, joiner, jlen);
  240. end += jlen;
  241. }
  242. if(s) {
  243. memcpy(end, s, l);
  244. end += l;
  245. }
  246. total += strlen(list[i]);
  247. }
  248. *end = 0;
  249. return out;
  250. }
  251. char* path_join_(size_t nargs, ...) {
  252. size_t total = 0;
  253. char* out, *end;
  254. size_t j_len;
  255. char* joiner = "/";
  256. int escape;
  257. if(nargs == 0) return NULL;
  258. // calculate total buffer length
  259. va_list va;
  260. va_start(va, nargs);
  261. for(size_t i = 0; i < nargs; i++) {
  262. char* s = va_arg(va, char*);
  263. if(s) total += strlen(s);
  264. }
  265. va_end(va);
  266. j_len = strlen(joiner);
  267. total += j_len * (nargs - 1);
  268. out = malloc((total + 1) * sizeof(char*));
  269. end = out;
  270. va_start(va, nargs);
  271. for(size_t i = 0; i < nargs; i++) {
  272. char* s = va_arg(va, char*);
  273. size_t l = strlen(s);
  274. if(s) {
  275. if(l > 1) {
  276. escape = s[l-2] == '\\' ? 1 : 0;
  277. }
  278. if(i > 0 && (s[0] == joiner[0])) {
  279. s++;
  280. l--;
  281. }
  282. if(i > 0 && i != nargs-1 && !escape && (s[l-1] == joiner[0])) {
  283. l--;
  284. }
  285. if(i > 0) {
  286. strcpy(end, joiner);
  287. end += j_len;
  288. }
  289. // should be strncpy, but GCC is so fucking stupid that it
  290. // has a warning about using strncpy to do exactly what
  291. // strncpy does if you read the fucking man page.
  292. // fortunately, we are already terminating our strings
  293. // manually so memcpy is a drop-in replacement here.
  294. memcpy(end, s, l);
  295. end += l;
  296. }
  297. }
  298. va_end(va);
  299. *end = 0;
  300. return out;
  301. }
  302. /* -END- string.c ----- */
  303. /* ----- strcache.c ----- */
  304. typedef unsigned long hash_t;
  305. hash_t strhash(char* str) {
  306. unsigned long h = 0;
  307. int c;
  308. while(c = *str++) {
  309. h = c + (h << 6) + (h << 16) - h;
  310. }
  311. return h;
  312. }
  313. hash_t strnhash(char* str, size_t n) {
  314. unsigned long h = 0;
  315. int c;
  316. while((c = *str++) && n--) {
  317. h = c + (h << 6) + (h << 16) - h;
  318. }
  319. return h;
  320. }
  321. typedef struct {
  322. hash_t hash;
  323. char* str;
  324. unsigned int len;
  325. int refs;
  326. } string_cache_bucket;
  327. typedef struct {
  328. int fill;
  329. int alloc;
  330. string_cache_bucket* buckets;
  331. } string_cache_t;
  332. string_cache_t string_cache;
  333. void string_cache_init(int alloc) {
  334. string_cache.fill = 0;
  335. string_cache.alloc = alloc ? alloc : 1024;
  336. string_cache.buckets = calloc(1, string_cache.alloc * sizeof(*string_cache.buckets));
  337. }
  338. int string_cache_find_bucket(string_cache_t* ht, hash_t hash, char* key) {
  339. int b = hash % ht->alloc;
  340. for(int i = 0; i < ht->alloc; i++) {
  341. // empty bucket
  342. if(ht->buckets[b].str == NULL) return b;
  343. // full bucket
  344. if(ht->buckets[b].hash == hash) {
  345. if(0 == strcmp(key, ht->buckets[b].str)) {
  346. return b;
  347. }
  348. }
  349. // probe forward on collisions
  350. b = (b + 1) % ht->alloc;
  351. }
  352. // should never reach here
  353. printf("oops. -1 bucket \n");
  354. return -1;
  355. }
  356. void string_cache_expand(string_cache_t* ht) {
  357. int old_alloc = ht->alloc;
  358. ht->alloc *= 2;
  359. string_cache_bucket* old = ht->buckets;
  360. ht->buckets = calloc(1, ht->alloc * sizeof(*ht->buckets));
  361. for(int i = 0, f = 0; i < old_alloc && f < ht->fill; i++) {
  362. if(!old[i].str) continue;
  363. int b = string_cache_find_bucket(ht, old[i].hash, old[i].str);
  364. ht->buckets[b] = old[i];
  365. f++;
  366. }
  367. free(old);
  368. }
  369. char* strcache(char* in) {
  370. hash_t hash = strhash(in);
  371. int b = string_cache_find_bucket(&string_cache, hash, in);
  372. if(!string_cache.buckets[b].str) {
  373. if(string_cache.fill > string_cache.alloc * .80) {
  374. string_cache_expand(&string_cache);
  375. // the bucket location has changed
  376. b = string_cache_find_bucket(&string_cache, hash, in);
  377. }
  378. string_cache.fill++;
  379. string_cache.buckets[b].str = strdup(in);
  380. string_cache.buckets[b].hash = hash;
  381. string_cache.buckets[b].refs = 1;
  382. string_cache.buckets[b].len = strlen(in);
  383. }
  384. else {
  385. string_cache.buckets[b].refs++;
  386. }
  387. return string_cache.buckets[b].str;
  388. }
  389. char* strncache(char* in, size_t n) {
  390. hash_t hash = strnhash(in, n);
  391. int b = string_cache_find_bucket(&string_cache, hash, in);
  392. if(!string_cache.buckets[b].str) {
  393. if(string_cache.fill > string_cache.alloc * .80) {
  394. string_cache_expand(&string_cache);
  395. // the bucket location has changed
  396. b = string_cache_find_bucket(&string_cache, hash, in);
  397. }
  398. string_cache.fill++;
  399. string_cache.buckets[b].str = strndup(in, n);
  400. string_cache.buckets[b].hash = hash;
  401. string_cache.buckets[b].refs = 1;
  402. string_cache.buckets[b].len = n;
  403. }
  404. else {
  405. string_cache.buckets[b].refs++;
  406. }
  407. return string_cache.buckets[b].str;
  408. }
  409. void struncache(char* in) {
  410. hash_t hash = strhash(in);
  411. int b = string_cache_find_bucket(&string_cache, hash, in);
  412. if(!string_cache.buckets[b].str) {
  413. // normal string, free it
  414. free(in);
  415. return;
  416. }
  417. string_cache.buckets[b].refs--;
  418. if(string_cache.buckets[b].refs == 0) {
  419. // just do nothing for now. deletion is a pain.
  420. }
  421. }
  422. /* -END- strcache.c ----- */
  423. /* ----- hash.c ----- */
  424. typedef struct {
  425. hash_t hash;
  426. char* key;
  427. void* value;
  428. } hashbucket;
  429. typedef struct hashtable {
  430. int fill;
  431. int alloc;
  432. hashbucket* buckets;
  433. } hashtable;
  434. void hash_init(hashtable* ht, int alloc) {
  435. ht->fill = 0;
  436. ht->alloc = alloc ? alloc : 128;
  437. ht->buckets = calloc(1, ht->alloc * sizeof(*ht->buckets));
  438. }
  439. hashtable* hash_new(int alloc) {
  440. hashtable* ht = malloc(sizeof(*ht));
  441. hash_init(ht, alloc);
  442. return ht;
  443. }
  444. int hash_find_bucket(hashtable* ht, hash_t hash, char* key) {
  445. int b = hash % ht->alloc;
  446. for(int i = 0; i < ht->alloc; i++) {
  447. // empty bucket
  448. if(ht->buckets[b].key == NULL) return b;
  449. // full bucket
  450. if(ht->buckets[b].hash == hash) {
  451. if(0 == strcmp(key, ht->buckets[b].key)) {
  452. return b;
  453. }
  454. }
  455. // probe forward on collisions
  456. b = (b + 1) % ht->alloc;
  457. }
  458. // should never reach here
  459. printf("oops. -1 bucket \n");
  460. return -1;
  461. }
  462. void hash_expand(hashtable* ht) {
  463. int old_alloc = ht->alloc;
  464. ht->alloc *= 2;
  465. hashbucket* old = ht->buckets;
  466. ht->buckets = calloc(1, ht->alloc * sizeof(*ht->buckets));
  467. for(int i = 0, f = 0; i < old_alloc && f < ht->fill; i++) {
  468. if(!old[i].key) continue;
  469. int b = hash_find_bucket(ht, old[i].hash, old[i].key);
  470. ht->buckets[b] = old[i];
  471. f++;
  472. }
  473. free(old);
  474. }
  475. void hash_insert(hashtable* ht, char* key, void* value) {
  476. hash_t hash = strhash(key);
  477. int b = hash_find_bucket(ht, hash, key);
  478. if(!ht->buckets[b].key) {
  479. if(ht->fill > ht->alloc * .80) {
  480. hash_expand(ht);
  481. // the bucket location has changed
  482. b = hash_find_bucket(ht, hash, key);
  483. }
  484. ht->fill++;
  485. }
  486. ht->buckets[b].key = strcache(key);
  487. ht->buckets[b].hash = hash;
  488. ht->buckets[b].value = value;
  489. }
  490. void* hash_find(hashtable* ht, char* key) {
  491. hash_t hash = strhash(key);
  492. int b = hash_find_bucket(ht, hash, key);
  493. return ht->buckets[b].value;
  494. }
  495. /* -END- hash.c ----- */
  496. /* ----- strlist.c ----- */
  497. typedef struct strlist {
  498. int len;
  499. int alloc;
  500. char** entries;
  501. } strlist;
  502. void strlist_init(strlist* sl) {
  503. sl->len = 0;
  504. sl->alloc = 32;
  505. sl->entries = malloc(sl->alloc * sizeof(*sl->entries));
  506. }
  507. strlist* strlist_new() {
  508. strlist* sl = malloc(sizeof(*sl));
  509. strlist_init(sl);
  510. return sl;
  511. }
  512. void strlist_push(strlist* sl, char* e) {
  513. check_alloc(sl);
  514. sl->entries[sl->len++] = e;
  515. sl->entries[sl->len] = 0;
  516. }
  517. /* -END- strlist.c ----- */
  518. /* ----- fs.c ----- */
  519. typedef struct realname_entry {
  520. char* realname;
  521. time_t mtime;
  522. } realname_entry;
  523. struct {
  524. hashtable names;
  525. int len;
  526. int alloc;
  527. struct realname_entry* entries;
  528. } realname_cache;
  529. hashtable mkdir_cache;
  530. #define FSU_EXCLUDE_HIDDEN (1<<0)
  531. #define FSU_NO_FOLLOW_SYMLINKS (1<<1)
  532. #define FSU_INCLUDE_DIRS (1<<2)
  533. #define FSU_EXCLUDE_FILES (1<<3)
  534. // return 0 to continue, nonzero to stop all directory scanning
  535. typedef int (*readDirCallbackFn)(char* /*fullPath*/, char* /*fileName*/, unsigned char /*type*/, void* /*data*/);
  536. // returns negative on error, nonzero if scanning was halted by the callback
  537. int recurse_dirs(
  538. char* path,
  539. readDirCallbackFn fn,
  540. void* data,
  541. int depth,
  542. unsigned int flags
  543. );
  544. void realname_cache_init();
  545. time_t realname_cache_add(char* fake_name, char* real_name);
  546. realname_entry* realname_cache_search_real(char* real_name);
  547. realname_entry* realname_cache_search(char* fake_name);
  548. char* realname_cache_find(char* fake_name);
  549. char* resolve_path(char* in, time_t* mtime_out);
  550. char* read_whole_file(char* path, size_t* srcLen);
  551. char* dir_name(char* path) {
  552. char* n = strdup(path);
  553. char* o = dirname(n);
  554. return strcache(o);
  555. }
  556. char* base_name(char* path) {
  557. char* n = strdup(path);
  558. char* o = basename(n);
  559. return strcache(o);
  560. }
  561. // does not handle escaped slashes
  562. int mkdirp(char* path, mode_t mode) {
  563. char* clean_path = strdup(path);
  564. // inch along the path creating each directory in line
  565. for(char* p = clean_path; *p; p++) {
  566. if(*p == '/') {
  567. *p = 0;
  568. if(mkdir(clean_path, mode)) {
  569. if(errno != EEXIST) goto FAIL;
  570. }
  571. *p = '/';
  572. }
  573. }
  574. // mop up the last dir
  575. if(mkdir(clean_path, mode)) {
  576. if(errno != EEXIST) goto FAIL;
  577. }
  578. free(clean_path);
  579. return 0;
  580. FAIL:
  581. free(clean_path);
  582. return -1;
  583. }
  584. void mkdirp_cached(char* path, mode_t mode) {
  585. void* there = hash_find(&mkdir_cache, path);
  586. if(!there) {
  587. hash_insert(&mkdir_cache, path, NULL);
  588. mkdirp(path, mode);
  589. }
  590. }
  591. // works like realpath(), except also handles ~/
  592. char* resolve_path(char* in, time_t* mtime_out) {
  593. int tmp_was_malloced = 0;
  594. char* out, *tmp;
  595. if(!in) return NULL;
  596. realname_entry* e = realname_cache_search(in);
  597. if(e) {
  598. if(mtime_out) *mtime_out = e->mtime;
  599. return strcache(e->realname);
  600. }
  601. // skip leading whitespace
  602. while(isspace(*in)) in++;
  603. // handle home dir shorthand
  604. if(in[0] == '~') {
  605. char* home = getenv("HOME");
  606. tmp_was_malloced = 1;
  607. tmp = malloc(sizeof(*tmp) * (strlen(home) + strlen(in) + 2));
  608. strcpy(tmp, home);
  609. strcat(tmp, "/"); // just in case
  610. strcat(tmp, in + 1);
  611. }
  612. else tmp = in;
  613. out = realpath(tmp, NULL);
  614. if(tmp_was_malloced) free(tmp);
  615. time_t t = 0;
  616. if(out) {
  617. // put it in the cache
  618. t = realname_cache_add(in, out);
  619. }
  620. else {
  621. // temporary
  622. struct stat st;
  623. if(!lstat(in, &st))
  624. t = st.st_mtim.tv_sec;
  625. }
  626. if(mtime_out) *mtime_out = t;
  627. return out ? out : in;
  628. }
  629. void realname_cache_init() {
  630. realname_cache.len = 0;
  631. realname_cache.alloc = 1024;
  632. realname_cache.entries = malloc(realname_cache.alloc * sizeof(*realname_cache.entries));
  633. hash_init(&realname_cache.names, 1024);
  634. }
  635. time_t realname_cache_add(char* fake_name, char* real_name) {
  636. realname_entry* e = hash_find(&realname_cache.names, fake_name);
  637. if(e) return e->mtime;
  638. e = hash_find(&realname_cache.names, real_name);
  639. if(!e) {
  640. struct stat st;
  641. lstat(real_name, &st);
  642. e = &realname_cache.entries[realname_cache.len];
  643. e->realname = strcache(real_name);
  644. e->mtime = st.st_mtim.tv_sec;
  645. realname_cache.len++;
  646. hash_insert(&realname_cache.names, real_name, e);
  647. }
  648. hash_insert(&realname_cache.names, fake_name, e);
  649. return e->mtime;
  650. }
  651. realname_entry* realname_cache_search_real(char* real_name) {
  652. for(int i = 0; i < realname_cache.len; i++) {
  653. if(0 == strcmp(real_name, realname_cache.entries[i].realname)) {
  654. return &realname_cache.entries[i];
  655. }
  656. }
  657. return NULL;
  658. }
  659. realname_entry* realname_cache_search(char* fake_name) {
  660. return hash_find(&realname_cache.names, fake_name);
  661. }
  662. char* realname_cache_find(char* fake_name) {
  663. realname_entry* r = realname_cache_search(fake_name);
  664. return r ? r->realname : NULL;
  665. }
  666. // returns negative on error, nonzero if scanning was halted by the callback
  667. int recurse_dirs(
  668. char* path,
  669. readDirCallbackFn fn,
  670. void* data,
  671. int depth,
  672. unsigned int flags
  673. ) {
  674. DIR* derp;
  675. struct dirent* result;
  676. int stop = 0;
  677. if(fn == NULL) {
  678. fprintf(stderr, "Error: readAllDir called with null function pointer.\n");
  679. return -1;
  680. }
  681. derp = opendir(path);
  682. if(derp == NULL) {
  683. fprintf(stderr, "Error opening directory '%s': %s\n", path, strerror(errno));
  684. return -1;
  685. }
  686. while((result = readdir(derp)) && !stop) {
  687. char* n = result->d_name;
  688. unsigned char type = DT_UNKNOWN;
  689. char* fullPath;
  690. // skip self and parent dir entries
  691. if(n[0] == '.') {
  692. if(n[1] == '.' && n[2] == 0) continue;
  693. if(n[1] == 0) continue;
  694. if(flags & FSU_EXCLUDE_HIDDEN) continue;
  695. }
  696. #ifdef _DIRENT_HAVE_D_TYPE
  697. type = result->d_type; // the way life should be
  698. #else
  699. // do some slow extra bullshit to get the type
  700. fullPath = path_join(path, n);
  701. struct stat upgrade_your_fs;
  702. lstat(fullPath, &upgrade_your_fs);
  703. if(S_ISREG(upgrade_your_fs.st_mode)) type = DT_REG;
  704. else if(S_ISDIR(upgrade_your_fs.st_mode)) type = DT_DIR;
  705. else if(S_ISLNK(upgrade_your_fs.st_mode)) type = DT_LNK;
  706. #endif
  707. if(flags & FSU_NO_FOLLOW_SYMLINKS && type == DT_LNK) {
  708. continue;
  709. }
  710. #ifdef _DIRENT_HAVE_D_TYPE
  711. fullPath = path_join(path, n);
  712. #endif
  713. if(type == DT_DIR) {
  714. if(flags & FSU_INCLUDE_DIRS) {
  715. stop = fn(fullPath, n, type, data);
  716. }
  717. if(depth != 0) {
  718. stop |= recurse_dirs(fullPath, fn, data, depth - 1, flags);
  719. }
  720. }
  721. else if(type == DT_REG) {
  722. if(!(flags & FSU_EXCLUDE_FILES)) {
  723. stop = fn(fullPath, n, type, data);
  724. }
  725. }
  726. free(fullPath);
  727. }
  728. closedir(derp);
  729. return stop;
  730. }
  731. char* read_whole_file(char* path, size_t* srcLen) {
  732. size_t fsize, total_read = 0, bytes_read;
  733. char* contents;
  734. FILE* f;
  735. f = fopen(path, "rb");
  736. if(!f) {
  737. fprintf(stderr, "Could not open file \"%s\"\n", path);
  738. return NULL;
  739. }
  740. fseek(f, 0, SEEK_END);
  741. fsize = ftell(f);
  742. rewind(f);
  743. contents = malloc(fsize + 1);
  744. while(total_read < fsize) {
  745. bytes_read = fread(contents + total_read, sizeof(char), fsize - total_read, f);
  746. total_read += bytes_read;
  747. }
  748. contents[fsize] = 0;
  749. fclose(f);
  750. if(srcLen) *srcLen = fsize;
  751. return contents;
  752. }
  753. /* -END- fs.c ----- */
  754. /* ----- pkgconfig.c ----- */
  755. char* pkg_config(char** packages, char* opts) {
  756. char* tmp;
  757. int num_pkgs = list_len(packages);
  758. if(num_pkgs == 0) return strdup("");
  759. char* pkgs = join_str_list(packages, " ");
  760. for(char* c = opts; *c; c++) {
  761. switch(*c) {
  762. case 'c':
  763. case 'C':
  764. case 'i':
  765. case 'I':
  766. tmp = strjoin(" ", "--cflags", pkgs);
  767. free(pkgs);
  768. pkgs = tmp;
  769. break;
  770. case 'l':
  771. case 'L':
  772. tmp = strjoin(" ", "--libs", pkgs);
  773. free(pkgs);
  774. pkgs = tmp;
  775. break;
  776. }
  777. }
  778. tmp = strjoin(" ", "pkg-config", pkgs);
  779. free(pkgs);
  780. FILE* f = popen(tmp, "r");
  781. free(tmp);
  782. if(!f) {
  783. fprintf(stderr, "Could not run command '%s'\n", tmp);
  784. exit(1);
  785. return NULL;
  786. }
  787. int len = 2048;
  788. int fill = 0;
  789. char* buffer = malloc(len * sizeof(*buffer));
  790. while(!feof(f)) {
  791. if(fill + 1 >= len) {
  792. len *= 2;
  793. buffer = realloc(buffer, len * sizeof(*buffer));
  794. }
  795. fill += fread(buffer + fill, 1, len - fill - 1, f);
  796. }
  797. buffer[fill] = 0;
  798. pclose(f);
  799. // strip out newlines and other garbage
  800. for(char* c = buffer; *c; c++) if(isspace(*c)) *c = ' ';
  801. return buffer;
  802. }
  803. /* -END- pkgconfig.c ----- */
  804. void parse_cli_opts(int argc, char** argv, objfile* obj) {
  805. for(int a = 1; a < argc; a++) {
  806. if(argv[a][0] == '-') {
  807. for(int i = 0; argv[a][i]; i++) {
  808. switch(argv[a][i]) {
  809. case 'd': // debug: -ggdb
  810. obj->mode_debug = 1;
  811. if(obj->mode_release == 1) {
  812. fprintf(stderr, "Debug and Release set at the same time.\n");
  813. }
  814. break;
  815. case 'p': // profiling: -pg
  816. obj->mode_profiling = 1;
  817. break;
  818. case 'r': // release: -O3
  819. obj->mode_release = 1;
  820. obj->mode_debug = 0;
  821. break;
  822. case 'c': // clean
  823. obj->clean_first = 1;
  824. break;
  825. case 'v': // verbose
  826. obj->verbose = 1;
  827. break;
  828. }
  829. }
  830. }
  831. }
  832. }
  833. void start_obj(objfile* obj) {
  834. unlink(obj->exe_path);
  835. obj->build_subdir = calloc(1, 20);
  836. if(obj->mode_debug) strcat(obj->build_subdir, "d");
  837. if(obj->mode_profiling) strcat(obj->build_subdir, "p");
  838. if(obj->mode_release) strcat(obj->build_subdir, "r");
  839. obj->build_dir = path_join(obj->base_build_dir, obj->build_subdir);
  840. // delete old build files if needed
  841. if(obj->clean_first) {
  842. printf("Cleaning directory %s/\n", obj->build_dir);
  843. system(sprintfdup("rm -rf %s/*", obj->build_dir));
  844. }
  845. // ensure the build dir exists
  846. mkdirp_cached(obj->build_dir, 0755);
  847. // flatten all the gcc options
  848. obj->gcc_opts_list = concat_lists(obj->ld_add, obj->common_cflags);
  849. if(obj->mode_debug) obj->gcc_opts_list = concat_lists(obj->gcc_opts_list, obj->debug_cflags);
  850. if(obj->mode_profiling) obj->gcc_opts_list = concat_lists(obj->gcc_opts_list, obj->profiling_cflags);
  851. if(obj->mode_release) obj->gcc_opts_list = concat_lists(obj->gcc_opts_list, obj->release_cflags);
  852. obj->gcc_opts_flat = join_str_list(obj->gcc_opts_list, " ");
  853. obj->gcc_include = pkg_config(obj->lib_headers_needed, "I");
  854. obj->gcc_libs = pkg_config(obj->libs_needed, "L");
  855. char* tmp = obj->gcc_opts_flat;
  856. obj->gcc_opts_flat = strjoin(" ", obj->gcc_opts_flat, obj->gcc_include);
  857. free(tmp);
  858. }
  859. /* ----- cprocs.c ----- */
  860. struct child_process_info {
  861. int pid;
  862. char state; // 'q'ueued, 'r'unning, 'd'ead
  863. int exit_status;
  864. int pty;
  865. int child_stdin;
  866. int child_stdout;
  867. int child_stderr;
  868. FILE* f_stdin;
  869. FILE* f_stdout;
  870. FILE* f_stderr;
  871. char* output_buffer;
  872. size_t buf_alloc;
  873. size_t buf_len;
  874. };
  875. struct child_process_info* exec_cmdline_pipe(char* cmdline);
  876. struct child_process_info* exec_process_pipe(char* exec_path, char* args[]);
  877. void read_cpi(struct child_process_info* cpi) {
  878. while(1) {
  879. if(cpi->buf_len > cpi->buf_alloc - 128) {
  880. cpi->buf_alloc *= 2;
  881. cpi->output_buffer = realloc(cpi->output_buffer, cpi->buf_alloc * sizeof(*cpi->output_buffer));
  882. }
  883. int ret = read(cpi->pty, cpi->output_buffer + cpi->buf_len, cpi->buf_alloc - cpi->buf_len - 1);
  884. if(ret > 0) cpi->buf_len += ret;
  885. else return;
  886. }
  887. return ;
  888. }
  889. char* printpct(float f) {
  890. static char buf[32];
  891. if(f != 100) sprintf(buf, "\e[1;33m %2.0f%%\e[0m", f);
  892. else sprintf(buf, "\e[1;32m100%%\e[0m");
  893. return buf;
  894. }
  895. int execute_mt(strlist* cmds, int threads, char* fmt, struct child_process_info*** cpis) {
  896. int ret = 0;
  897. int running = 0;
  898. struct child_process_info** procs = calloc(1, cmds->len * sizeof(*procs));
  899. if(cpis) *cpis = procs;
  900. if(fmt) printf(fmt, printpct(0)), fflush(stdout);
  901. int waiting = cmds->len;
  902. while(waiting > 0) {
  903. for(int i = 0; i < cmds->len; i++) {
  904. // keep the cores full
  905. if(!procs[i] && running < threads) {
  906. procs[i] = exec_cmdline_pipe(cmds->entries[i]);
  907. procs[i]->state = 'r';
  908. running++;
  909. }
  910. if(!procs[i] || procs[i]->state == 'd') continue;
  911. read_cpi(procs[i]);
  912. int status;
  913. // returns 0 if nothing happened, -1 on error, childpid if it exited
  914. int pid = waitpid(procs[i]->pid, &status, WNOHANG);
  915. if(pid != 0) {
  916. procs[i]->state = 'd';
  917. waiting--;
  918. running--;
  919. if(fmt) printf("\r"), printf(fmt, printpct((cmds->len - waiting) * 100.0f / (float)cmds->len)), fflush(stdout);
  920. read_cpi(procs[i]);
  921. procs[i]->output_buffer[procs[i]->buf_len] = 0;
  922. procs[i]->exit_status = WEXITSTATUS(status);
  923. if(!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
  924. // printf("error on pid %d/%d = %d\n", pid, procs[i]->pid, WEXITSTATUS(status));
  925. // printf("%s\n", procs[i]->output_buffer);
  926. ret = 1;
  927. }
  928. }
  929. }
  930. usleep(100);
  931. }
  932. if(fmt) {
  933. printf("\r");
  934. if(ret) printf(fmt, "\e[1;31mFAIL\e[0m");
  935. else printf(fmt, "\e[32mDONE\e[0m");
  936. fflush(stdout);
  937. }
  938. printf("\n");
  939. return ret;
  940. }
  941. struct child_process_info* exec_cmdline_pipe(char* cmdline) {
  942. // kinda janky. it doesn't handle quotes
  943. char** args = strsplit(" ", cmdline);
  944. struct child_process_info* cpi = exec_process_pipe(args[0], args);
  945. // printf("executing '%s'\n", cmdline);
  946. // for(char** s = args; *s; s++) printf("%d - '%s'\n", (s-args), *s);
  947. free_strpp(args);
  948. return cpi;
  949. }
  950. // effectively a better, asynchronous version of system()
  951. // redirects and captures the child process i/o
  952. struct child_process_info* exec_process_pipe(char* exec_path, char* args[]) {
  953. int master, slave; // pty
  954. errno = 0;
  955. if(openpty(&master, &slave, NULL, NULL, NULL) < 0) {
  956. fprintf(stderr, "Error opening new pty for '%s' [errno=%d]\n", exec_path, errno);
  957. return NULL;
  958. }
  959. errno = 0;
  960. int childPID = fork();
  961. if(childPID == -1) {
  962. fprintf(stderr, "failed to fork trying to execute '%s'\n", exec_path);
  963. perror(strerror(errno));
  964. return NULL;
  965. }
  966. else if(childPID == 0) { // child process
  967. setsid();
  968. // redirect standard fd's to the pipe fd's
  969. if(dup2(slave, fileno(stdin)) == -1) {
  970. printf("failed 1\n");
  971. exit(errno);
  972. }
  973. if(dup2(slave, fileno(stdout)) == -1) {
  974. printf("failed 2\n");
  975. exit(errno);
  976. }
  977. if(dup2(slave, fileno(stderr)) == -1) {
  978. printf("failed 3\n");
  979. exit(errno);
  980. }
  981. if(ioctl(slave, TIOCSCTTY, NULL) < 0) {
  982. fprintf(stderr, "ioctl TIOCSCTTY failed: %s, %d\n", exec_path, errno);
  983. }
  984. // close original fd's
  985. close(master);
  986. close(slave);
  987. // die when the parent does (linux only)
  988. prctl(PR_SET_PDEATHSIG, SIGHUP);
  989. // swap for the desired program
  990. execvp(exec_path, args); // never returns if successful
  991. fprintf(stderr, "failed to execute '%s'\n", exec_path);
  992. exit(1); // kill the forked process
  993. }
  994. else { // parent process
  995. // close the child-end of the pipes
  996. struct child_process_info* cpi;
  997. cpi = calloc(1, sizeof(*cpi));
  998. cpi->pid = childPID;
  999. cpi->pty = master;
  1000. cpi->state = 'q';
  1001. cpi->buf_alloc = 4096;
  1002. cpi->output_buffer = malloc(cpi->buf_alloc * sizeof(*cpi->output_buffer));
  1003. // set to non-blocking
  1004. fcntl(master, F_SETFL, fcntl(master, F_GETFL) | FNDELAY | O_NONBLOCK);
  1005. close(slave);
  1006. // tcsetattr(STDIN_FILENO, TCSANOW, &master);
  1007. // fcntl(master, F_SETFL, FNDELAY);
  1008. // int status;
  1009. // returns 0 if nothing happened, -1 on error
  1010. // pid = waitpid(childPID, &status, WNOHANG);
  1011. return cpi;
  1012. }
  1013. return NULL; // shouldn't reach here
  1014. }
  1015. /* -END- cprocs.c ----- */
  1016. /* ----- rglob.c ----- */
  1017. typedef struct rglob_entry {
  1018. char type;
  1019. char* full_path;
  1020. char* file_name;
  1021. // char* dir_name;
  1022. } rglob_entry;
  1023. typedef struct rglob {
  1024. char* pattern;
  1025. int len;
  1026. int alloc;
  1027. rglob_entry* entries;
  1028. } rglob;
  1029. int rglob_fn(char* full_path, char* file_name, unsigned char type, void* _results) {
  1030. rglob* res = (rglob*)_results;
  1031. if(0 == fnmatch(res->pattern, file_name, 0)) {
  1032. check_alloc(res);
  1033. res->entries[res->len].type = type;
  1034. res->entries[res->len].full_path = strcache(full_path);
  1035. res->entries[res->len].file_name = strcache(file_name);
  1036. res->len++;
  1037. }
  1038. return 0;
  1039. }
  1040. void recursive_glob(char* base_path, char* pattern, int flags, rglob* results) {
  1041. // to pass into recurse_dirs()
  1042. results->pattern = pattern;
  1043. results->len = 0;
  1044. results->alloc = 32;
  1045. results->entries = malloc(sizeof(*results->entries) * results->alloc);
  1046. recurse_dirs(base_path, rglob_fn, results, -1, flags);
  1047. }
  1048. /* -END- rglob.c ----- */
  1049. /* ----- gcc.c ----- */
  1050. strlist compile_cache;
  1051. int compile_cache_execute() {
  1052. int ret = 0;
  1053. struct child_process_info** cpis;
  1054. // printf("compile cache length %d", compile_cache.len);
  1055. ret = execute_mt(&compile_cache, g_nprocs, "Compiling... %s", &cpis);
  1056. if(ret) {
  1057. for(int i = 0; i < compile_cache.len; i++ ) {
  1058. if(cpis[i]->exit_status) {
  1059. printf("%.*s\n", (int)cpis[i]->buf_len, cpis[i]->output_buffer);
  1060. }
  1061. }
  1062. }
  1063. // TODO free compile cache
  1064. // TODO free cpis
  1065. return ret;
  1066. }
  1067. strlist* parse_gcc_dep_file(char* dep_file_path, time_t* newest_mtime) {
  1068. size_t dep_src_len = 0;
  1069. strlist* dep_list;
  1070. time_t newest = 0;
  1071. char* dep_src = read_whole_file(dep_file_path, &dep_src_len);
  1072. if(!dep_src) return NULL;
  1073. dep_list = strlist_new();
  1074. // skip the first filename junk
  1075. char* s = strchr(dep_src, ':');
  1076. s++;
  1077. int ret = 0;
  1078. // gather dep strings, ignoring line continuations
  1079. while(*s) {
  1080. do {
  1081. s = strskip(s, " \t\r\n");
  1082. if(*s == '\\') {
  1083. if(s[1] == '\r') s++;
  1084. if(s[1] == '\n') s++;
  1085. }
  1086. } while(isspace(*s));
  1087. int dlen = span_path(s);
  1088. if(dlen == 0) break;
  1089. time_t dep_mtime;
  1090. char* dep_fake = strncache(s, dlen);
  1091. char* dep_real = resolve_path(dep_fake, &dep_mtime);
  1092. if(dep_mtime > newest) newest = dep_mtime;
  1093. strlist_push(dep_list, dep_real);
  1094. struncache(dep_fake);
  1095. struncache(dep_real);
  1096. s += dlen;
  1097. }
  1098. free(dep_src);
  1099. if(newest_mtime) *newest_mtime = newest;
  1100. return dep_list;
  1101. }
  1102. int gen_deps(char* src_path, char* dep_path, time_t src_mtime, time_t obj_mtime, objfile* obj) {
  1103. time_t dep_mtime = 0;
  1104. time_t newest_mtime = 0;
  1105. char* real_dep_path = resolve_path(dep_path, &dep_mtime);
  1106. if(dep_mtime < src_mtime) {
  1107. //gcc -MM -MG -MT $1 -MF "build/$1.d" $1 $CFLAGS $LDADD
  1108. // printf(" generating deps\n");
  1109. char* cmd = sprintfdup("gcc -MM -MG -MT '' -MF %s %s %s", dep_path, src_path, obj->gcc_opts_flat);
  1110. system(cmd);
  1111. free(cmd);
  1112. }
  1113. strlist* deps = parse_gcc_dep_file(real_dep_path, &newest_mtime);
  1114. // free or process deps
  1115. return newest_mtime > obj_mtime;
  1116. FAIL:
  1117. return 0;
  1118. }
  1119. /* -END- gcc.c ----- */