From f5ceb5b292fde6dab90acd0a339eafdadc7786ce Mon Sep 17 00:00:00 2001 From: sjplimp Date: Thu, 10 Mar 2016 16:34:30 +0000 Subject: [PATCH] git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@14736 f3b2605a-c512-4ea7-a41b-209d697bcdaa --- src/DEPEND/fastdep.c | 668 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 668 insertions(+) create mode 100644 src/DEPEND/fastdep.c diff --git a/src/DEPEND/fastdep.c b/src/DEPEND/fastdep.c new file mode 100644 index 0000000000..5400e03034 --- /dev/null +++ b/src/DEPEND/fastdep.c @@ -0,0 +1,668 @@ +/* Fast dependency generator for LAMMPS + * (c) 2016 Axel Kohlmeyer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +const char version[] = "2.0"; + +/************************************************************************ + * utility functions + ************************************************************************/ + +/* remove trailing path separators */ +char *trim_path(char *path) +{ + int last = strlen(path) - 1; + while ((path[last] == '/') || (path[last] == '\\')) + --last; + path[++last] = '\0'; + return path; +} + +/* test if a file exists */ +int file_exists(const char *path) +{ +#if defined(_WIN32) + struct _stat s; + + if (path == NULL) return 0; + if (_stat(path,&s) != 0) return 0; + return 1; +#else + struct stat s; + + if (path == NULL) return 0; + if (stat(path,&s) != 0) return 0; + return 1; +#endif +} + +/* simple integer square root */ +static int isqrt(int n) +{ + int b = 0; + + while(n >= 0) { + n = n - b; + b = b + 1; + n = n - b; + } + return b - 1; +} + +/* determine next available prime number */ +static int next_prime(const int num) +{ + int nprime, factor, root; + + /* nprime has to be larger than num and odd */ + nprime = num + (num & 1) + 1; + /* there is always a prime between n and 2n */ + while (nprime < 2*num) { + /* brute force division test on odd factors up to sqrt(nprime) */ + root = isqrt(nprime)+1; + for (factor = 3; factor < root; factor +=2) { + if (nprime % factor == 0) break; + } + /* if the loop didn't exit early, we have found a prime */ + if (factor >= root) return nprime; + nprime += 2; + } + return nprime; +} + +/* FNV hash function */ +static unsigned int hash_func(const void *key) +{ + const unsigned char *p = key; + unsigned int h = 2166136261; + + if (!p) return 0; + + while (*p) { + h = (h * 16777619) ^ *p; + ++p; + } + return h; +} + +/************************************************************************ + * structs for data structures + ************************************************************************/ + +/* linked list */ + +typedef struct _llnode llnode_t; +struct _llnode { + const char *key; + llnode_t *next; +}; + +typedef struct { + llnode_t *head; + llnode_t *tail; + int count; +} llist_t; + +/* set */ + +typedef struct { + llnode_t *buckets; + int nbuckets; + int count; +} set_t; + +/* map */ + +typedef struct _mapnode mapnode_t; +struct _mapnode { + const char *key; + set_t *val; + mapnode_t *next; +}; + +typedef struct { + mapnode_t *buckets; + int nbuckets; + int count; +} map_t; + +/************************************************************************ + * linked list functions + ************************************************************************/ + +/* allocate and intitialize linked list */ +static llist_t *llist_init() +{ + llist_t *ll; + ll = (llist_t *)malloc(sizeof(llist_t)); + if (ll != NULL) { + ll->head = (llnode_t *)malloc(sizeof(llnode_t)); + ll->head->next = NULL; + ll->head->key = NULL; + ll->tail = ll->head; + ll->count = 0; + } + return ll; +} + +/* destroy linked list and free all associated storage */ +static void llist_free(llist_t *ll) +{ + llnode_t *tmp; + if (ll == NULL) return; + + while (ll->head->next) { + tmp = ll->head; + ll->head = ll->head->next; + free((void *)tmp->key); + free((void *)tmp); + } + free((void *)ll->head); + free((void *)ll); +} + +/* append an item to the end of the linked list */ +static void llist_append(llist_t *ll, const char *key) +{ + llnode_t *tmp; + if ((ll == NULL) || (key == NULL)) return; + + ll->tail->key = strdup(key); + ll->count ++; + tmp = (llnode_t *)malloc(sizeof(llnode_t)); + tmp->key = NULL; + tmp->next = NULL; + ll->tail->next = tmp; + ll->tail = tmp; +} + +static int llist_size(llist_t *ll) +{ + if (ll) return ll->count; + return 0; +} + +static void llist_print(llist_t *ll) +{ + llnode_t *tmp; + if (ll == NULL) return; + tmp = ll->head; + + if (tmp->next) { + fputs(tmp->key,stdout); + tmp = tmp->next; + } + + while (tmp->next) { + fputc(':',stdout); + fputs(tmp->key,stdout); + tmp = tmp->next; + } + fputc('\n',stdout); +} + + +/************************************************************************ + * set functions + ************************************************************************/ + +/* initialize empty set */ +static set_t *set_init(int num) +{ + set_t *s = (set_t *)malloc(sizeof(set_t)); + + s->nbuckets = next_prime(num); + s->buckets = malloc(s->nbuckets*sizeof(llnode_t)); + memset(s->buckets,0,s->nbuckets*sizeof(llnode_t)); + s->count = 0; + + return s; +} + +/* destroy a set and free the associated storage */ +static void set_free(set_t *s) +{ + llnode_t *tmp, *next; + int i; + + if (!s) return; + for (i = 0; i < s->nbuckets; ++i) { + tmp = s->buckets + i; + while (tmp->next != NULL) { + free((void *)tmp->key); + next = tmp->next->next; + tmp->key = tmp->next->key; + free((void *)tmp->next); + tmp->next = next; + } + } + free((void *)s->buckets); + free((void *)s); +} + +/* add an entry to the set */ +static void set_add(set_t *s, const char *key) +{ + llnode_t *tmp; + unsigned int idx; + + if (!s) return; + + idx = hash_func(key) % s->nbuckets; + tmp = s->buckets + idx; + while (tmp->next != NULL) { + if (strcmp(tmp->key,key) == 0) return; + tmp = tmp->next; + } + s->count ++; + tmp->key = strdup(key); + tmp->next = (llnode_t *)malloc(sizeof(llnode_t)); + tmp = tmp->next; + tmp->key = NULL; + tmp->next = NULL; +} + +/* find an entry in the set */ +static int set_find(set_t *s, const char *key) +{ + llnode_t *tmp; + unsigned int idx; + + if (!s) return 0; + + idx = hash_func(key) % s->nbuckets; + tmp = s->buckets + idx; + while (tmp->next != NULL) { + if (strcmp(tmp->key,key) == 0) return 1; + tmp = tmp->next; + } + return 0; +} + +static int set_size(set_t *s) +{ + if (s) return s->count; + return 0; +} + +/************************************************************************ + * map functions + ************************************************************************/ + +/* initialize empty map */ +static map_t *map_init(int num) +{ + map_t *m = (map_t *)malloc(sizeof(map_t)); + if (!m) return NULL; + + m->nbuckets = next_prime(num); + m->buckets = malloc(m->nbuckets*sizeof(mapnode_t)); + memset(m->buckets,0,m->nbuckets*sizeof(mapnode_t)); + m->count = 0; + + return m; +} + +/* destroy a map and free the associated storage */ +static void map_free(map_t *m) +{ + mapnode_t *tmp, *next; + int i; + + if (!m) return; + for (i = 0; i < m->nbuckets; ++i) { + tmp = m->buckets + i; + while (tmp->next != NULL) { + free((void *)tmp->key); + set_free(tmp->val); + next = tmp->next->next; + tmp->key = tmp->next->key; + tmp->val = tmp->next->val; + free((void *)tmp->next); + tmp->next = next; + } + } + free((void *)m->buckets); + free((void *)m); +} + +/* add an entry to the map */ +static void map_add(map_t *m, const char *key, const char *val) +{ + mapnode_t *tmp; + unsigned int idx; + + if (!m) return; + + idx = hash_func(key) % m->nbuckets; + tmp = m->buckets + idx; + while (tmp->next != NULL) { + if (strcmp(tmp->key,key) == 0) break; + tmp = tmp->next; + } + + /* add new entry to map */ + if (tmp->next == NULL) { + m->count ++; + tmp->key = strdup(key); + tmp->val = set_init(50); /* XXX: chosen arbitrarily */ + tmp->next = (mapnode_t *)malloc(sizeof(mapnode_t)); + tmp->next->key = NULL; + tmp->next->val = NULL; + tmp->next->next = NULL; + } + set_add(tmp->val,val); +} + +/* return an entry in the map */ +static set_t *map_find(map_t *m, const char *key) +{ + mapnode_t *tmp; + unsigned int idx; + + if (!m) return 0; + + idx = hash_func(key) % m->nbuckets; + tmp = m->buckets + idx; + while (tmp->next != NULL) { + if (strcmp(tmp->key,key) == 0) return tmp->val; + tmp = tmp->next; + } + return NULL; +} + +static int map_size(map_t *m) +{ + if (m) return m->count; + return 0; +} + +/************************************************************************/ + +/* combine search for file across paths */ +static void make_path(const char *file, llist_t *paths, char *buffer) +{ + llnode_t *tmp; + const char *val; + int i; + + tmp = paths->head; + buffer[0] = '\0'; + while (tmp->next != NULL) { + i = 0; + val = tmp->key; + + while (*val) buffer[i++] = *val++; +#if defined(_WIN32) + buffer[i++] = '\\'; +#else + buffer[i++] = '/'; +#endif + val = file; + while (*val) buffer[i++] = *val++; + buffer[i] = '\0'; + + if (file_exists(buffer)) return; + tmp = tmp->next; + } + buffer[0] = '\0'; +} + +/************************************************************************/ + +static void find_includes(llnode_t *head, llist_t *todo, llist_t *paths, + set_t *incl, map_t *deps) +{ + FILE *fp; + llnode_t *tmp; + char *buffer,*full,*ptr,*end; + const char *file; + + buffer = (char *)malloc(4096); + full = (char *)malloc(4096); + + tmp = head; + while (tmp->next != NULL) { + file = tmp->key; + fp = fopen(file,"r"); + if (fp == NULL) { + perror("Cannot read source"); + fprintf(stderr,"For file: %s\n",file); + exit(EXIT_FAILURE); + } + + /* read file line by line and look for #include "..." */ + while (!feof(fp) && !ferror(fp)) { + if (fgets(buffer,4096,fp) == NULL) continue; + ptr = buffer; + while (*ptr == ' ' || *ptr == '\t') ++ptr; + if (*ptr != '#') continue; + while (*ptr == ' ' || *ptr == '\t') ++ptr; + if (*++ptr != 'i') continue; + if (*++ptr != 'n') continue; + if (*++ptr != 'c') continue; + if (*++ptr != 'l') continue; + if (*++ptr != 'u') continue; + if (*++ptr != 'd') continue; + if (*++ptr != 'e') continue; + ++ptr; + while (*ptr == ' ' || *ptr == '\t') ++ptr; + if (*ptr != '"') continue; + ++ptr; + end = ptr; + while (*end != '"') { + if (*end == '\0') { + fprintf(stderr,"Unmatched '\"': %s\n",buffer); + exit(EXIT_FAILURE); + } + ++end; + } + *end = '\0'; + + /* get full path to include file */ + make_path(ptr,paths,full); + /* skip, if not found or unreadable. */ + if (full[0] == '\0') continue; + + /* if this is a yet unknown include, add to the + * todo list, if append is enabled */ + if (set_find(incl,full) == 0) { + set_add(incl,full); + llist_append(todo,full); + } + + map_add(deps,file,full); + } + fclose(fp); + tmp = tmp->next; + } + free(buffer); + free(full); +} + +/************************************************************************/ + +static void add_depend(const char *source, set_t *incl, map_t *deps) +{ + set_t *mydeps; + llnode_t *tmp; + int i,num; + + if (source == NULL) return; + + mydeps = map_find(deps,source); + if (mydeps != NULL) { + num = mydeps->nbuckets; + + for (i = 0; i < num; ++i) { + tmp = mydeps->buckets + i; + while (tmp->next != NULL) { + if (set_find(incl,tmp->key) == 0) { + set_add(incl,tmp->key); + add_depend(tmp->key,incl,deps); + } + tmp = tmp->next; + } + } + } + +} + +/************************************************************************/ + +static void do_depend(llnode_t *head, map_t *deps) +{ + llnode_t *tmp, *lnk; + set_t *incl; + const char *source; + char *target, *ptr; + int i,num; + + tmp = head; + while (tmp->next != NULL) { + source = tmp->key; + target = strrchr(source,'/'); + if (target == NULL) { + target = strdup(source); + } else { + target = strdup(target+1); + } + + ptr = strrchr(target,'.'); + if (ptr != NULL) { + ptr[1] = 'o'; + ptr[2] = '\0'; + } + fputs(target,stdout); + fputs(" : ",stdout); + fputs(source,stdout); + free((void *)target); + + incl = set_init(50); + add_depend(source,incl,deps); + + num = incl->nbuckets; + for (i = 0; i < num; ++i) { + lnk = incl->buckets + i; + while (lnk->next != NULL) { + fputc(' ',stdout); + fputs(lnk->key,stdout); + lnk = lnk->next; + } + } + fputc('\n',stdout); + set_free(incl); + tmp = tmp->next; + } +} + + + +/************************************************************************/ + +int main(int argc, char **argv) +{ + llist_t *paths,*src,*todo; + set_t *incl; + map_t *deps; + + if (argc < 2) { + fprintf(stderr,"FastDep v%s for LAMMPS\n" + "Usage: %s [-I ...] -- [ ...]\n", + version,argv[0]); + return 1; + } + + /* hash tables for all known included files and dependencies + * we guesstimate a little over 2x as many entries as sources. */ + incl = set_init(2*argc); + deps = map_init(2*argc); + + /* list of include search paths. prefixed by "." and "..". */ + paths = llist_init(); + llist_append(paths,"."); + llist_append(paths,".."); + + while (++argv, --argc > 0) { + if (strncmp(*argv, "-I", 2) == 0) { + if ((*argv)[2] != '\0') { + llist_append(paths,trim_path(*argv+2)); + } else { + ++argv; + --argc; + if (argc > 0) { + if (strcmp(*argv,"--") == 0) { + break; + } else { + llist_append(paths,trim_path(*argv)); + } + } + } + } else if (strcmp(*argv,"--") == 0) { + break; + } // ignore all unrecognized arguments before '--'. + } + + src = llist_init(); + while (++argv, --argc > 0) { + llist_append(src,*argv); + } + + /* process files to look for includes */ + todo = llist_init(); + find_includes(src->head,todo,paths,incl,deps); + find_includes(todo->head,todo,paths,incl,deps); + llist_free(todo); + + fprintf(stdout,"# FastDep v%s for LAMMPS\n",version); + fputs("# Search path: ",stdout); + llist_print(paths); + fprintf(stdout,"# % 5d sources\n# % 5d includes\n# % 5d depfiles\n", + llist_size(src),set_size(incl),map_size(deps)); + + set_free(incl); + do_depend(src->head,deps); + + llist_free(src); + llist_free(paths); + map_free(deps); + return 0; +} + +/* + * Local Variables: + * compile-command: "gcc -o fastdep.exe -Wall -g -O fastdep.c" + * c-basic-offset: 4 + * End: + */