1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * Copyright (C) 2011 Norbert Thiebaud
7 /* define to activate stats reporting on hash usage*/
8 /* #define HASH_STAT */
10 /* ===============================================
11 * Set-up: defines to identify the system and system related properties
12 * ===============================================
17 #undef CORE_BIG_ENDIAN
18 #define CORE_LITTLE_ENDIAN
20 #define CORE_BIG_ENDIAN
21 #undef CORE_LITTLE_ENDIAN
27 #undef CORE_BIG_ENDIAN
28 #define CORE_LITTLE_ENDIAN
29 #endif /* Def _MSC_VER */
31 #if defined(__linux) || defined(__FreeBSD__)
32 #include <sys/param.h>
33 #if __BYTE_ORDER == __LITTLE_ENDIAN
34 #undef CORE_BIG_ENDIAN
35 #define CORE_LITTLE_ENDIAN
36 #else /* !(__BYTE_ORDER == __LITTLE_ENDIAN) */
37 #if __BYTE_ORDER == __BIG_ENDIAN
38 #define CORE_BIG_ENDIAN
39 #undef CORE_LITTLE_ENDIAN
40 #endif /* __BYTE_ORDER == __BIG_ENDIAN */
41 #endif /* !(__BYTE_ORDER == __LITTLE_ENDIAN) */
42 #endif /* Def __linux */
44 #if defined(__OpenBSD__) || defined(__FreeBSD__) || \
45 defined(__NetBSD__) || defined(__DragonFly__)
46 #include <machine/endian.h>
47 #if _BYTE_ORDER == _LITTLE_ENDIAN
48 #undef CORE_BIG_ENDIAN
49 #define CORE_LITTLE_ENDIAN
50 #else /* !(_BYTE_ORDER == _LITTLE_ENDIAN) */
51 #if _BYTE_ORDER == _BIG_ENDIAN
52 #define CORE_BIG_ENDIAN
53 #undef CORE_LITTLE_ENDIAN
54 #endif /* _BYTE_ORDER == _BIG_ENDIAN */
55 #endif /* !(_BYTE_ORDER == _LITTLE_ENDIAN) */
58 #if defined(__HAIKU__)
60 #if __BYTE_ORDER == __LITTLE_ENDIAN
61 #undef CORE_BIG_ENDIAN
62 #define CORE_LITTLE_ENDIAN
63 #else /* !(__BYTE_ORDER == __LITTLE_ENDIAN) */
64 #if __BYTE_ORDER == __BIG_ENDIAN
65 #define CORE_BIG_ENDIAN
66 #undef CORE_LITTLE_ENDIAN
67 #endif /* __BYTE_ORDER == __BIG_ENDIAN */
68 #endif /* !(__BYTE_ORDER == __LITTLE_ENDIAN) */
69 #endif /* Def __HAIKU__ */
73 #define CORE_BIG_ENDIAN
74 #undef CORE_LITTLE_ENDIAN
75 #else /* Ndef __sparc */
76 #undef CORE_BIG_ENDIAN
77 #define CORE_LITTLE_ENDIAN
78 #endif /* Ndef __sparc */
79 #endif /* Def __sun */
84 #include <sys/types.h>
97 #include <config_options.h>
101 #define FILE_O_RDONLY _O_RDONLY
102 #define FILE_O_BINARY _O_BINARY
103 #define PATHNCMP _strnicmp /* MSVC converts paths to lower-case sometimes? */
105 #define S_ISREG(mode) (((mode) & _S_IFMT) == (_S_IFREG)) /* MSVC does not have this macro */
106 #else /* not windaube */
107 #define FILE_O_RDONLY O_RDONLY
108 #define FILE_O_BINARY 0
109 #define PATHNCMP strncmp
110 #endif /* not windaube */
119 static int internal_boost
= 0;
120 static char* base_dir
;
121 static char* work_dir
;
122 static size_t work_dir_len
;
125 #define clz __builtin_clz
127 static int clz(unsigned int value
)
140 static unsigned int get_unaligned_uint(const unsigned char* cursor
)
144 memcpy(&result
, cursor
, sizeof(unsigned int));
148 /* ===============================================
149 * memory pool for fast fix-size allocation (non-thread-safe)
150 * ===============================================
154 void* head_free
; /**< head of a linked list of freed element */
155 char* fresh
; /**< top of a memory block to dig new element */
156 char* tail
; /**< to detect end of extent... when fresh pass tail */
157 void* extent
; /**< pointer to the primary extent block */
158 int size_elem
; /**< size of an element. */
159 int primary
; /**< primary allocation in bytes */
160 int secondary
; /**< secondary allocation in bytes */
162 #define POOL_ALIGN_INCREMENT 8 /**< alignment, must be a power of 2 and of size > to sizeof(void*) */
165 static void* pool_take_extent(struct pool
* pool
, int allocate
)
167 unsigned int size
= 0;
173 /* we already have an extent, so this is a secondary */
176 size
= pool
->secondary
;
181 assert(pool
->primary
);
182 size
= pool
->primary
;
186 extent
= malloc(size
);
189 *(void**)extent
= pool
->extent
;
190 pool
->extent
= extent
;
193 data
= ((char*)extent
) + POOL_ALIGN_INCREMENT
;
194 pool
->fresh
= ((char*)data
) + pool
->size_elem
;
195 pool
->tail
= pool
->fresh
+ (size
- pool
->size_elem
);
199 pool
->fresh
= ((char*)extent
) + POOL_ALIGN_INCREMENT
;
200 pool
->tail
= pool
->fresh
+ (size
- pool
->size_elem
);
207 /* Create a memory pool for fix size objects
208 * this is a simplified implementation that
209 * is _not_ thread safe.
211 static struct pool
* pool_create(int size_elem
, int primary
, int secondary
)
216 assert(secondary
>= 0);
217 assert(size_elem
> 0);
219 pool
= (struct pool
*)calloc(1, sizeof(struct pool
));
220 if(!pool
) return NULL
;
221 /* Adjust the element size so that it be aligned, and so that an element could
222 * at least contain a void*
224 pool
->size_elem
= size_elem
= (size_elem
+ POOL_ALIGN_INCREMENT
- 1) & ~(POOL_ALIGN_INCREMENT
- 1);
226 pool
->primary
= (size_elem
* primary
) + POOL_ALIGN_INCREMENT
;
227 pool
->secondary
= secondary
> 0 ? (size_elem
* secondary
) + POOL_ALIGN_INCREMENT
: 0;
228 pool_take_extent(pool
, FALSE
);
234 static void pool_destroy(struct pool
* pool
)
241 extent
= pool
->extent
;
244 next
= *(void**)extent
;
252 static void* pool_alloc(struct pool
* pool
)
256 data
= pool
->head_free
;
259 /* we have no old-freed elem */
260 if(pool
->fresh
<= pool
->tail
)
262 /* pick a slice of the current extent */
263 data
= (void*)pool
->fresh
;
264 pool
->fresh
+= pool
->size_elem
;
268 /* allocate a new extent */
269 data
= pool_take_extent(pool
, TRUE
);
274 /* re-used old freed element by chopping the head of the free list */
275 pool
->head_free
= *(void**)data
;
282 /* ===============================================
283 * Hash implementation customized to be just tracking
284 * a unique list of string (i.e no data associated
285 * with the key, no need for retrieval, etc...
287 * This is tuned for the particular use-case we have here
288 * measures in tail_build showed that
289 * we can get north of 4000 distinct values stored in a hash
290 * the collision rate is at worse around 2%
291 * the collision needing an expensive memcmp to resolve
292 * have a rate typically at 1 per 1000
293 * for tail_build we register 37229 unique key
294 * with a total of 377 extra memcmp needed
295 * which is completely negligible compared to the
296 * number of memcmp required to eliminate duplicate
297 * entry (north of 2.5 millions for tail_build)
298 * ===============================================
303 struct hash_elem
* next
;
310 struct hash_elem
** array
;
311 struct pool
* elems_pool
;
314 unsigned int load_limit
;
323 /* The following hash_compute function was adapted from :
324 * lookup3.c, by Bob Jenkins, May 2006, Public Domain.
326 * The changes from the original are mostly cosmetic
328 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
331 #if defined CORE_BIG_ENDIAN
332 #define MASK_C1 0xFFFFFF00
333 #define MASK_C2 0xFFFF0000
334 #define MASK_C3 0xFF000000
335 #elif defined CORE_LITTLE_ENDIAN
336 #define MASK_C1 0xFFFFFF
337 #define MASK_C2 0xFFFF
340 #error "Missing Endianness definition"
346 a -= c; a ^= rot(c, 4); c += b; \
347 b -= a; b ^= rot(a, 6); a += c; \
348 c -= b; c ^= rot(b, 8); b += a; \
349 a -= c; a ^= rot(c,16); c += b; \
350 b -= a; b ^= rot(a,19); a += c; \
351 c -= b; c ^= rot(b, 4); b += a; \
353 #define final(a,b,c) \
355 c ^= b; c -= rot(b,14); \
356 a ^= c; a -= rot(c,11); \
357 b ^= a; b -= rot(a,25); \
358 c ^= b; c -= rot(b,16); \
359 a ^= c; a -= rot(c,4); \
360 b ^= a; b -= rot(a,14); \
361 c ^= b; c -= rot(b,24); \
364 static unsigned int hash_compute( struct hash
const * hash
, const char* key
, int length
)
368 unsigned int c
; /* internal state */
369 const unsigned char* uk
= (const unsigned char*)key
;
371 /* Set up the internal state */
372 a
= b
= c
= 0xdeadbeef + (length
<< 2);
374 /* we use this to 'hash' full path with mostly a common root
375 * let's now waste too much cycles hashing mostly constant stuff
382 /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
385 a
+= get_unaligned_uint(uk
);
386 b
+= get_unaligned_uint(uk
+4);
387 c
+= get_unaligned_uint(uk
+8);
393 /*----------------------------- handle the last (probably partial) block */
394 /* Note: we possibly over-read, which would trigger complaint from VALGRIND
395 * but we mask the undefined stuff if any, so we are still good, thanks
396 * to alignment of memory allocation and tail-memory management overhead
397 * we always can read 3 bytes past the official end without triggering
398 * a segfault -- if you find a platform/compiler couple for which that postulate
399 * is false, then you just need to over-allocate by 2 more bytes in file_load()
400 * file_load already over-allocate by 1 to stick a \0 at the end of the buffer.
404 case 12: c
+=get_unaligned_uint(uk
+8); b
+=get_unaligned_uint(uk
+4); a
+=get_unaligned_uint(uk
); break;
405 case 11: c
+=get_unaligned_uint(uk
+8) & MASK_C1
; b
+=get_unaligned_uint(uk
+4); a
+=get_unaligned_uint(uk
); break;
406 case 10: c
+=get_unaligned_uint(uk
+8) & MASK_C2
; b
+=get_unaligned_uint(uk
+4); a
+=get_unaligned_uint(uk
); break;
407 case 9 : c
+=get_unaligned_uint(uk
+8) & MASK_C3
; b
+=get_unaligned_uint(uk
+4); a
+=get_unaligned_uint(uk
); break;
408 case 8 : b
+=get_unaligned_uint(uk
+4); a
+=get_unaligned_uint(uk
); break;
409 case 7 : b
+=get_unaligned_uint(uk
+4) & MASK_C1
; a
+=get_unaligned_uint(uk
); break;
410 case 6 : b
+=get_unaligned_uint(uk
+4) & MASK_C2
; a
+=get_unaligned_uint(uk
); break;
411 case 5 : b
+=get_unaligned_uint(uk
+4) & MASK_C3
; a
+=get_unaligned_uint(uk
); break;
412 case 4 : a
+=get_unaligned_uint(uk
); break;
413 case 3 : a
+=get_unaligned_uint(uk
) & MASK_C1
; break;
414 case 2 : a
+=get_unaligned_uint(uk
) & MASK_C2
; break;
415 case 1 : a
+=get_unaligned_uint(uk
) & MASK_C3
; break;
416 case 0 : return c
& hash
->size
; /* zero length strings require no mixing */
420 return c
& hash
->size
;
423 static void hash_destroy(struct hash
* hash
)
433 pool_destroy(hash
->elems_pool
);
439 static struct hash
* hash_create(unsigned int size
)
444 hash
= (struct hash
*)(calloc(1, sizeof(struct hash
)));
447 size
+= (size
>> 2) + 1; /* ~ 75% load factor */
450 hash
->size
= (((unsigned int)0xFFFFFFFF) >> clz((unsigned int)size
));
454 hash
->size
= size
= 15;
456 hash
->load_limit
= hash
->size
- (hash
->size
>> 2);
458 hash
->array
= (struct hash_elem
**)calloc(hash
->size
+ 1, sizeof(struct hash_elem
*));
459 if(hash
->array
== NULL
)
467 hash
->elems_pool
= pool_create(sizeof(struct hash_elem
),
469 if(!hash
->elems_pool
)
478 static void hash_resize(struct hash
* hash
)
480 unsigned int old_size
= hash
->size
;
482 struct hash_elem
* hash_elem
;
483 struct hash_elem
* next
;
484 struct hash_elem
** array
;
487 hash
->size
= (old_size
<< 1) + 1;
488 /* we really should avoid to get there... so print a message to alert of the condition */
489 fprintf(stderr
, "resize hash %u -> %u\n", old_size
, hash
->size
);
490 if(hash
->size
== old_size
)
494 array
= (struct hash_elem
**)calloc(hash
->size
+ 1, sizeof(struct hash_elem
*));
497 hash
->load_limit
= hash
->size
- (hash
->size
>> 2);
498 for(i
=0; i
<= old_size
; i
++)
500 hash_elem
= (struct hash_elem
*)hash
->array
[i
];
503 next
= hash_elem
->next
;
505 hashed
= hash_compute(hash
, hash_elem
->key
, hash_elem
->key_len
);
506 hash_elem
->next
= array
[hashed
];
507 array
[hashed
] = hash_elem
;
512 hash
->array
= (struct hash_elem
**)array
;
516 hash
->size
= old_size
;
520 static int compare_key(struct hash
const * hash
, const char* a
, const char* b
, int len
, int const * cost
)
529 return memcmp(a
,b
, len
);
532 /* a customized hash_store function that just store the key and return
533 * TRUE if the key was effectively stored, or FALSE if the key was already there
535 static int hash_store(struct hash
* hash
, const char* key
, int key_len
)
538 struct hash_elem
* hash_elem
;
542 hashed
= hash_compute(hash
, key
, key_len
);
546 hash_elem
= (struct hash_elem
*)hash
->array
[hashed
];
547 while(hash_elem
&& (hash_elem
->key_len
!= key_len
|| compare_key(hash
, hash_elem
->key
, key
, key_len
, &cost
)))
549 hash_elem
= hash_elem
->next
;
554 hash_elem
= (struct hash_elem
*)pool_alloc(hash
->elems_pool
);
557 hash_elem
->key
= key
;
558 hash_elem
->key_len
= key_len
;
559 hash_elem
->next
= hash
->array
[hashed
];
564 hash
->collisions
+= 1;
568 hash
->array
[hashed
] = hash_elem
;
570 if(hash
->used
> hash
->load_limit
)
580 static int file_stat(const char* name
, struct stat
* buffer_stat
, int* rc
)
582 int rc_local
= stat(name
, buffer_stat
);
590 static off_t
file_get_size(const char* name
, int* rc
)
592 struct stat buffer_stat
;
595 if (!file_stat(name
, &buffer_stat
, rc
))
597 if(S_ISREG(buffer_stat
.st_mode
))
599 size
= buffer_stat
.st_size
;
609 #if !ENABLE_RUNTIME_OPTIMIZATIONS
610 static void * file_load_buffers
[100000];
611 static size_t file_load_buffer_count
= 0;
614 static char* file_load(const char* name
, off_t
* size
, int* return_rc
)
616 off_t local_size
= 0;
621 assert(name
!= NULL
);
627 *size
= file_get_size(name
, &rc
);
628 if (!rc
&& *size
>= 0)
630 fd
= open(name
, FILE_O_RDONLY
| FILE_O_BINARY
);
633 buffer
= (char*)malloc((size_t)(*size
+ 1));
634 #if !ENABLE_RUNTIME_OPTIMIZATIONS
637 if (file_load_buffer_count
== 100000)
644 file_load_buffers
[file_load_buffer_count
++] = buffer
;
657 i
= read(fd
, buffer
, (size_t)(*size
));
694 static void cancel_relative(char const * base
, char** ref_cursor
, char** ref_cursor_out
, char const * end
)
696 char* cursor
= *ref_cursor
;
697 char* cursor_out
= *ref_cursor_out
;
702 while(cursor_out
> base
&& cursor_out
[-1] == '/')
704 while(cursor_out
> base
&& *--cursor_out
!= '/');
706 while(cursor
+ 3 < end
&& !memcmp(cursor
, "/../", 4));
707 *ref_cursor
= cursor
;
708 *ref_cursor_out
= cursor_out
;
711 static void eat_space(char ** token
)
713 while ((' ' == **token
) || ('\t' == **token
)) {
719 * Prune LibreOffice specific duplicate dependencies to improve
720 * gnumake startup time, and shrink the disk-space footprint.
723 elide_dependency(const char* key
, int key_len
, const char **unpacked_end
)
728 fprintf (stderr
, "elide?%d!: '", internal_boost
);
729 for (i
= 0; i
< key_len
; i
++) {
730 fprintf (stderr
, "%c", key
[i
]);
732 fprintf (stderr
, "'\n");
736 /* boost brings a plague of header files */
739 /* walk down path elements */
740 for (i
= 0; i
< key_len
- 1; i
++)
746 if (!PATHNCMP(key
+ i
+ 1, "workdir/", 8))
754 if (!PATHNCMP(key
+ i
+ 1, "UnpackedTarball/", 16))
757 *unpacked_end
= strchr(key
+ i
+ 17, '/');
768 * We collapse tens of internal boost headers to the unpacked target, such
769 * that you can re-compile / install boost and all is well.
771 static void emit_single_boost_header(void)
773 #define BOOST_TARGET "/UnpackedTarball/boost.done"
774 fprintf(stdout
, "%s" BOOST_TARGET
" ", work_dir
);
777 static void emit_unpacked_target(const char* token
, const char* end
)
779 fwrite(token
, 1, end
-token
, stdout
);
780 fputs(".done ", stdout
);
783 /* prefix paths to absolute */
784 static void print_fullpaths(char* line
)
790 const char * unpacked_end
= NULL
; /* end of UnpackedTarget match (if any) */
791 /* for UnpackedTarget the target is GenC{,xx}Object, don't mangle! */
799 /* hard to believe that in this day and age drive letters still exist */
800 if (*end
&& (':' == *(end
+1)) &&
801 (('\\' == *(end
+2)) || ('/' == *(end
+2))) &&
802 isalpha((unsigned char)*end
))
804 end
= end
+ 3; /* only one cross, err drive letter per filename */
806 while (*end
&& (' ' != *end
) && ('\t' != *end
) && (':' != *end
)) {
809 token_len
= end
- token
;
811 elide_dependency(token
, token_len
, &unpacked_end
))
815 if (internal_boost
&& !PATHNCMP(unpacked_end
- 5, "boost", 5))
818 if (boost_count
== 1)
819 emit_single_boost_header();
822 /* don't output, and swallow trailing \\\n if any */
825 if (token
[0] == '\\' && token
[1] == '\n')
831 emit_unpacked_target(token
, unpacked_end
);
838 if (fwrite(token
, token_len
, 1, stdout
) != 1)
844 if (!target_seen
&& ':' == *token
)
854 static char * eat_space_at_end(char * end
)
857 assert('\0' == *end
);
859 while (' ' == *real_end
|| '\t' == *real_end
|| '\n' == *real_end
861 { /* eat colon and whitespace at end */
867 static char* phony_content_buffer
;
868 static char* generate_phony_line(char const * phony_target
, char const * extension
)
872 char* last_dot
= NULL
;
873 //fprintf(stderr, "generate_phony_line called with phony_target %s and extension %s\n", phony_target, extension);
874 for(dest
= phony_content_buffer
+work_dir_len
+1, src
= phony_target
; *src
!= 0; ++src
, ++dest
)
882 //fprintf(stderr, "generate_phony_line after phony_target copy: %s\n", phony_content_buffer);
883 for(dest
= last_dot
+1, src
= extension
; *src
!= 0; ++src
, ++dest
)
887 //fprintf(stderr, "generate_phony_line after extension add: %s\n", phony_content_buffer);
888 strcpy(dest
, ": $(gb_Helper_PHONY)\n");
889 //fprintf(stderr, "generate_phony_line after phony add: %s\n", phony_content_buffer);
890 return phony_content_buffer
;
893 static int generate_phony_file(char* fn
, char const * content
)
896 depfile
= fopen(fn
, "w");
899 fprintf(stderr
, "Could not open '%s' for writing: %s\n", fn
, strerror(errno
));
903 fputs(content
, depfile
);
909 static int process(struct hash
* dep_hash
, char* fn
)
917 char* created_line
= NULL
;
919 int continuation
= 0;
923 buffer
= file_load(fn
, &size
, &rc
);
926 base
= cursor_out
= cursor
= end
= buffer
;
929 /* first eat unneeded space at the beginning of file
931 while(cursor
< end
&& (*cursor
== ' ' || *cursor
== '\\'))
939 *cursor_out
++ = *cursor
++;
941 else if(*cursor
== '/')
945 if(!memcmp(cursor
, "/./", 3))
953 if(!memcmp(cursor
, "/../", 4))
955 cancel_relative(base
, &cursor
, &cursor_out
, end
);
958 *cursor_out
++ = *cursor
++;
960 else if(*cursor
== '\n')
967 /* here we have a complete rule */
970 /* if the rule ended in ':' that is a no-dep rule
971 * these are the one for which we want to filter
974 int key_len
= eat_space_at_end(cursor_out
) - base
;
975 if (!elide_dependency(base
,key_len
+ 1, NULL
)
976 && hash_store(dep_hash
, base
, key_len
))
978 /* DO NOT modify base after it has been added
979 as key by hash_store */
980 print_fullpaths(base
);
986 /* rule with dep, just write it */
987 print_fullpaths(base
);
990 last_ns
= ' '; // cannot hurt to reset it
993 base
= cursor_out
= cursor
;
997 /* here we have a '\' followed by \n this is a continuation
998 * i.e not a complete rule yet
1000 *cursor_out
++ = *cursor
++;
1001 continuation
= 0; // cancel current one (empty lines!)
1007 /* not using isspace() here save 25% of I refs and 75% of D refs based on cachegrind */
1008 if(*cursor
!= ' ' && *cursor
!= '\n' && *cursor
!= '\t' )
1012 *cursor_out
++ = *cursor
++;
1016 /* just in case the file did not end with a \n, there may be a pending rule */
1017 if(base
< cursor_out
)
1021 int key_len
= eat_space_at_end(cursor_out
) - base
;
1022 if (!elide_dependency(base
,key_len
+ 1, NULL
) &&
1023 hash_store(dep_hash
, base
, key_len
))
1038 if(strncmp(fn
, work_dir
, work_dir_len
) == 0)
1040 if(strncmp(fn
+work_dir_len
, "/Dep/", 5) == 0)
1042 src_relative
= fn
+work_dir_len
+5;
1043 // cases ordered by frequency
1044 if(strncmp(src_relative
, "CxxObject/", 10) == 0)
1046 created_line
= generate_phony_line(src_relative
, "o");
1047 rc
= generate_phony_file(fn
, created_line
);
1049 else if(strncmp(src_relative
, "GenCxxObject/", 13) == 0)
1051 created_line
= generate_phony_line(src_relative
, "o");
1052 rc
= generate_phony_file(fn
, created_line
);
1054 else if(strncmp(src_relative
, "CObject/", 8) == 0)
1056 created_line
= generate_phony_line(src_relative
, "o");
1057 rc
= generate_phony_file(fn
, created_line
);
1059 else if(strncmp(src_relative
, "GenCObject/", 11) == 0)
1061 created_line
= generate_phony_line(src_relative
, "o");
1062 rc
= generate_phony_file(fn
, created_line
);
1064 else if(strncmp(src_relative
, "SdiObject/", 10) == 0)
1066 created_line
= generate_phony_line(src_relative
, "o");
1067 rc
= generate_phony_file(fn
, created_line
);
1069 else if(strncmp(src_relative
, "AsmObject/", 10) == 0)
1071 created_line
= generate_phony_line(src_relative
, "o");
1072 rc
= generate_phony_file(fn
, created_line
);
1074 else if(strncmp(src_relative
, "ObjCxxObject/", 13) == 0)
1076 created_line
= generate_phony_line(src_relative
, "o");
1077 rc
= generate_phony_file(fn
, created_line
);
1079 else if(strncmp(src_relative
, "ObjCObject/", 11) == 0)
1081 created_line
= generate_phony_line(src_relative
, "o");
1082 rc
= generate_phony_file(fn
, created_line
);
1084 else if(strncmp(src_relative
, "GenObjCxxObject/", 16) == 0)
1086 created_line
= generate_phony_line(src_relative
, "o");
1087 rc
= generate_phony_file(fn
, created_line
);
1089 else if(strncmp(src_relative
, "GenObjCObject/", 14) == 0)
1091 created_line
= generate_phony_line(src_relative
, "o");
1092 rc
= generate_phony_file(fn
, created_line
);
1094 else if(strncmp(src_relative
, "GenNasmObject/", 14) == 0)
1096 created_line
= generate_phony_line(src_relative
, "o");
1097 rc
= generate_phony_file(fn
, created_line
);
1099 else if(strncmp(src_relative
, "CxxClrObject/", 13) == 0)
1101 created_line
= generate_phony_line(src_relative
, "o");
1102 rc
= generate_phony_file(fn
, created_line
);
1104 else if(strncmp(src_relative
, "GenCxxClrObject/", 16) == 0)
1106 created_line
= generate_phony_line(src_relative
, "o");
1107 rc
= generate_phony_file(fn
, created_line
);
1111 fprintf(stderr
, "no magic for %s(%s) in %s\n", fn
, src_relative
, work_dir
);
1120 /* Note: yes we are going to leak 'buffer'
1121 * this is on purpose, to avoid cloning the 'key' out of it and our special
1122 * 'hash' just store the pointer to the key inside of buffer, hence it need
1123 * to remain allocated
1125 // coverity[leaked_storage] - this is on purpose
1129 static void usage(void)
1131 fputs("Usage: concat-deps <file that contains dep_files>\n", stderr
);
1134 #define kDEFAULT_HASH_SIZE 4096
1135 #define PHONY_TARGET_BUFFER 4096
1137 static int get_var(char **var
, const char *name
)
1139 *var
= (char *)getenv(name
);
1142 fprintf(stderr
,"Error: %s is missing in the environment\n", name
);
1148 int main(int argc
, char** argv
)
1151 off_t in_list_size
= 0;
1153 char* in_list_cursor
;
1155 struct hash
* dep_hash
= NULL
;
1156 const char *env_str
;
1163 if(get_var(&base_dir
, "SRCDIR") || get_var(&work_dir
, "WORKDIR"))
1165 work_dir_len
= strlen(work_dir
);
1166 phony_content_buffer
= (char*)malloc(PHONY_TARGET_BUFFER
);
1167 assert(phony_content_buffer
); // Don't handle OOM conditions
1168 strcpy(phony_content_buffer
, work_dir
);
1169 phony_content_buffer
[work_dir_len
] = '/';
1171 env_str
= getenv("SYSTEM_BOOST");
1172 internal_boost
= !env_str
|| strcmp(env_str
,"TRUE");
1174 in_list
= file_load(argv
[1], &in_list_size
, &rc
);
1177 dep_hash
= hash_create( kDEFAULT_HASH_SIZE
);
1178 in_list_base
= in_list_cursor
= in_list
;
1180 /* extract filename of dep file from a 'space' separated list */
1181 while(*in_list_cursor
)
1183 /* the input here may contain Win32 \r\n EOL */
1184 if(*in_list_cursor
== ' '
1185 || *in_list_cursor
== '\n' || *in_list_cursor
== '\r')
1187 *in_list_cursor
= 0;
1188 if(in_list_base
< in_list_cursor
)
1190 rc
= process(dep_hash
, in_list_base
);
1196 in_list_cursor
+= 1;
1197 in_list_base
= in_list_cursor
;
1201 in_list_cursor
+= 1;
1206 /* catch the last entry in case the input did not terminate with a 'space' */
1207 if(in_list_base
< in_list_cursor
)
1209 rc
= process(dep_hash
, in_list_base
);
1213 fprintf(stderr
, "stats: u:%d s:%d l:%d t:%d c:%d m:%d $:%d\n",
1214 dep_hash
->used
, dep_hash
->size
, dep_hash
->load_limit
, dep_hash
->stored
,
1215 dep_hash
->collisions
, dep_hash
->memcmp
, dep_hash
->cost
);
1218 #if !ENABLE_RUNTIME_OPTIMIZATIONS
1221 hash_destroy(dep_hash
);
1222 for (i
= 0; i
!= file_load_buffer_count
; ++i
)
1224 free(file_load_buffers
[i
]);
1231 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */