2 * Generate include file dependencies
4 * Copyright 1996 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define NO_LIBWINE_PORT
23 #include "wine/port.h"
35 #include "wine/list.h"
37 /* Max first-level includes per file */
38 #define MAX_INCLUDES 200
45 char *sourcename
; /* source file name for generated headers */
46 struct incl_file
*included_by
; /* file that included this one */
47 int included_line
; /* line where this file was included */
48 unsigned int flags
; /* flags (see below) */
49 struct incl_file
*owner
;
50 struct incl_file
*files
[MAX_INCLUDES
];
53 #define FLAG_SYSTEM 0x0001 /* is it a system include (#include <name>) */
54 #define FLAG_IDL_PROXY 0x0002 /* generates a proxy (_p.c) file */
55 #define FLAG_IDL_CLIENT 0x0004 /* generates a client (_c.c) file */
56 #define FLAG_IDL_SERVER 0x0008 /* generates a server (_s.c) file */
57 #define FLAG_IDL_IDENT 0x0010 /* generates an ident (_i.c) file */
58 #define FLAG_IDL_REGISTER 0x0020 /* generates a registration (_r.res) file */
59 #define FLAG_IDL_TYPELIB 0x0040 /* generates a typelib (.tlb) file */
60 #define FLAG_IDL_HEADER 0x0080 /* generates a header (.h) file */
61 #define FLAG_RC_PO 0x0100 /* rc file contains translations */
62 #define FLAG_C_IMPLIB 0x0200 /* file is part of an import library */
71 { FLAG_IDL_TYPELIB
, ".tlb", "$(TARGETFLAGS) $(IDLFLAGS) -t" },
72 { FLAG_IDL_TYPELIB
, "_t.res", "$(TARGETFLAGS) $(IDLFLAGS) -t" },
73 { FLAG_IDL_CLIENT
, "_c.c", "$(IDLFLAGS) -c" },
74 { FLAG_IDL_IDENT
, "_i.c", "$(IDLFLAGS) -u" },
75 { FLAG_IDL_PROXY
, "_p.c", "$(IDLFLAGS) -p" },
76 { FLAG_IDL_SERVER
, "_s.c", "$(IDLFLAGS) -s" },
77 { FLAG_IDL_REGISTER
, "_r.res", "$(IDLFLAGS) -r" },
78 { FLAG_IDL_HEADER
, ".h", "$(IDLFLAGS) -h" },
81 static struct list sources
= LIST_INIT(sources
);
82 static struct list includes
= LIST_INIT(includes
);
86 unsigned int count
; /* strings in use */
87 unsigned int size
; /* total allocated size */
91 static struct strarray include_args
;
92 static struct strarray object_extensions
;
100 static struct make_var
*make_vars
;
101 static unsigned int nb_make_vars
;
103 static const char *base_dir
= ".";
104 static const char *src_dir
;
105 static const char *top_src_dir
;
106 static const char *top_obj_dir
;
107 static const char *parent_dir
;
108 static const char *makefile_name
= "Makefile";
109 static const char *Separator
= "### Dependencies";
110 static const char *input_file_name
;
111 static int parse_makefile_mode
;
112 static int relative_dir_mode
;
113 static int input_line
;
114 static FILE *output_file
;
116 static const char Usage
[] =
117 "Usage: makedep [options] [files]\n"
119 " -Idir Search for include files in directory 'dir'\n"
120 " -Cdir Search for source files in directory 'dir'\n"
121 " -Sdir Set the top source directory\n"
122 " -Tdir Set the top object directory\n"
123 " -Pdir Set the parent source directory\n"
124 " -M dirs Parse the makefiles from the specified directories\n"
125 " -R from to Compute the relative path between two directories\n"
126 " -fxxx Store output in file 'xxx' (default: Makefile)\n"
127 " -sxxx Use 'xxx' as separator (default: \"### Dependencies\")\n";
131 #define __attribute__(x)
134 static void fatal_error( const char *msg
, ... ) __attribute__ ((__format__ (__printf__
, 1, 2)));
135 static void fatal_perror( const char *msg
, ... ) __attribute__ ((__format__ (__printf__
, 1, 2)));
136 static int output( const char *format
, ... ) __attribute__ ((__format__ (__printf__
, 1, 2)));
137 static char *strmake( const char* fmt
, ... ) __attribute__ ((__format__ (__printf__
, 1, 2)));
139 /*******************************************************************
142 static void fatal_error( const char *msg
, ... )
145 va_start( valist
, msg
);
148 fprintf( stderr
, "%s:", input_file_name
);
149 if (input_line
) fprintf( stderr
, "%d:", input_line
);
150 fprintf( stderr
, " error: " );
152 else fprintf( stderr
, "makedep: error: " );
153 vfprintf( stderr
, msg
, valist
);
159 /*******************************************************************
162 static void fatal_perror( const char *msg
, ... )
165 va_start( valist
, msg
);
168 fprintf( stderr
, "%s:", input_file_name
);
169 if (input_line
) fprintf( stderr
, "%d:", input_line
);
170 fprintf( stderr
, " error: " );
172 else fprintf( stderr
, "makedep: error: " );
173 vfprintf( stderr
, msg
, valist
);
180 /*******************************************************************
183 static void *xmalloc( size_t size
)
186 if (!(res
= malloc (size
? size
: 1)))
187 fatal_error( "Virtual memory exhausted.\n" );
192 /*******************************************************************
195 static void *xrealloc (void *ptr
, size_t size
)
199 if (!(res
= realloc( ptr
, size
)))
200 fatal_error( "Virtual memory exhausted.\n" );
204 /*******************************************************************
207 static char *xstrdup( const char *str
)
209 char *res
= strdup( str
);
210 if (!res
) fatal_error( "Virtual memory exhausted.\n" );
215 /*******************************************************************
218 static char *strmake( const char* fmt
, ... )
226 char *p
= xmalloc (size
);
228 n
= vsnprintf (p
, size
, fmt
, ap
);
230 if (n
== -1) size
*= 2;
231 else if ((size_t)n
>= size
) size
= n
+ 1;
238 /*******************************************************************
241 static int strendswith( const char* str
, const char* end
)
246 return l
>= m
&& strcmp(str
+ l
- m
, end
) == 0;
250 /*******************************************************************
253 static int output( const char *format
, ... )
258 va_start( valist
, format
);
259 ret
= vfprintf( output_file
, format
, valist
);
261 if (ret
< 0) fatal_perror( "output" );
266 /*******************************************************************
269 static void strarray_init( struct strarray
*array
)
277 /*******************************************************************
280 static void strarray_add( struct strarray
*array
, const char *str
)
282 if (array
->count
== array
->size
)
284 if (array
->size
) array
->size
*= 2;
285 else array
->size
= 16;
286 array
->str
= xrealloc( array
->str
, sizeof(array
->str
[0]) * array
->size
);
288 array
->str
[array
->count
++] = str
;
292 /*******************************************************************
295 static void strarray_insert( struct strarray
*array
, unsigned int pos
, const char *str
)
299 strarray_add( array
, NULL
);
300 for (i
= array
->count
- 1; i
> pos
; i
--) array
->str
[i
] = array
->str
[i
- 1];
301 array
->str
[pos
] = str
;
305 /*******************************************************************
308 static void strarray_add_uniq( struct strarray
*array
, const char *str
)
312 for (i
= 0; i
< array
->count
; i
++) if (!strcmp( array
->str
[i
], str
)) return;
313 strarray_add( array
, str
);
317 /*******************************************************************
320 static void output_filename( const char *name
, int *column
)
322 if (*column
+ strlen(name
) + 1 > 100)
327 *column
+= output( " %s", name
);
331 /*******************************************************************
334 static char *get_extension( char *filename
)
336 char *ext
= strrchr( filename
, '.' );
337 if (ext
&& strchr( ext
, '/' )) ext
= NULL
;
342 /*******************************************************************
345 static char *replace_extension( const char *name
, unsigned int old_len
, const char *new_ext
)
347 char *ret
= xmalloc( strlen( name
) + strlen( new_ext
) + 1 );
349 strcpy( ret
+ strlen( ret
) - old_len
, new_ext
);
354 /*******************************************************************
357 static char *replace_substr( const char *str
, const char *start
, unsigned int len
, const char *replace
)
359 unsigned int pos
= start
- str
;
360 char *ret
= xmalloc( pos
+ strlen(replace
) + strlen(start
+ len
) + 1 );
361 memcpy( ret
, str
, pos
);
362 strcpy( ret
+ pos
, replace
);
363 strcat( ret
+ pos
, start
+ len
);
368 /*******************************************************************
371 * Determine where the destination path is located relative to the 'from' path.
373 static char *get_relative_path( const char *from
, const char *dest
)
377 unsigned int dotdots
= 0;
379 /* a path of "." is equivalent to an empty path */
380 if (!strcmp( from
, "." )) from
= "";
384 while (*from
== '/') from
++;
385 while (*dest
== '/') dest
++;
386 start
= dest
; /* save start of next path element */
389 while (*from
&& *from
!= '/' && *from
== *dest
) { from
++; dest
++; }
390 if ((!*from
|| *from
== '/') && (!*dest
|| *dest
== '/')) continue;
392 /* count remaining elements in 'from' */
396 while (*from
&& *from
!= '/') from
++;
397 while (*from
== '/') from
++;
403 if (!start
[0] && !dotdots
) return NULL
; /* empty path */
405 ret
= xmalloc( 3 * dotdots
+ strlen( start
) + 1 );
406 for (p
= ret
; dotdots
; dotdots
--, p
+= 3) memcpy( p
, "../", 3 );
408 if (start
[0]) strcpy( p
, start
);
409 else p
[-1] = 0; /* remove trailing slash */
414 /*******************************************************************
417 static void init_paths(void)
419 /* ignore redundant source paths */
420 if (src_dir
&& !strcmp( src_dir
, "." )) src_dir
= NULL
;
421 if (top_src_dir
&& top_obj_dir
&& !strcmp( top_src_dir
, top_obj_dir
)) top_src_dir
= NULL
;
423 if (top_src_dir
) strarray_insert( &include_args
, 0, strmake( "-I%s/include", top_src_dir
));
424 else if (top_obj_dir
) strarray_insert( &include_args
, 0, strmake( "-I%s/include", top_obj_dir
));
426 /* set the default extension list for object files */
427 if (!object_extensions
.count
) strarray_add( &object_extensions
, "o" );
431 /*******************************************************************
434 static char *get_line( FILE *file
)
437 static unsigned int size
;
442 buffer
= xmalloc( size
);
444 if (!fgets( buffer
, size
, file
)) return NULL
;
449 char *p
= buffer
+ strlen(buffer
);
450 /* if line is larger than buffer, resize buffer */
451 while (p
== buffer
+ size
- 1 && p
[-1] != '\n')
453 buffer
= xrealloc( buffer
, size
* 2 );
454 if (!fgets( buffer
+ size
- 1, size
+ 1, file
)) break;
455 p
= buffer
+ strlen(buffer
);
458 if (p
> buffer
&& p
[-1] == '\n')
461 if (p
> buffer
&& p
[-1] == '\r') *(--p
) = 0;
462 if (p
> buffer
&& p
[-1] == '\\')
465 /* line ends in backslash, read continuation line */
466 if (!fgets( p
, size
- (p
- buffer
), file
)) return buffer
;
475 /*******************************************************************
478 static struct incl_file
*find_src_file( const char *name
)
480 struct incl_file
*file
;
482 LIST_FOR_EACH_ENTRY( file
, &sources
, struct incl_file
, entry
)
483 if (!strcmp( name
, file
->name
)) return file
;
487 /*******************************************************************
490 static struct incl_file
*find_include_file( const char *name
)
492 struct incl_file
*file
;
494 LIST_FOR_EACH_ENTRY( file
, &includes
, struct incl_file
, entry
)
495 if (!strcmp( name
, file
->name
)) return file
;
499 /*******************************************************************
502 * Add an include file if it doesn't already exists.
504 static struct incl_file
*add_include( struct incl_file
*pFile
, const char *name
, int system
)
506 struct incl_file
*include
;
510 for (pos
= 0; pos
< MAX_INCLUDES
; pos
++) if (!pFile
->files
[pos
]) break;
511 if (pos
>= MAX_INCLUDES
)
512 fatal_error( "too many included files, please fix MAX_INCLUDES\n" );
514 /* enforce some rules for the Wine tree */
516 if (!memcmp( name
, "../", 3 ))
517 fatal_error( "#include directive with relative path not allowed\n" );
519 if (!strcmp( name
, "config.h" ))
521 if ((ext
= strrchr( pFile
->filename
, '.' )) && !strcmp( ext
, ".h" ))
522 fatal_error( "config.h must not be included by a header file\n" );
524 fatal_error( "config.h must be included before anything else\n" );
526 else if (!strcmp( name
, "wine/port.h" ))
528 if ((ext
= strrchr( pFile
->filename
, '.' )) && !strcmp( ext
, ".h" ))
529 fatal_error( "wine/port.h must not be included by a header file\n" );
530 if (!pos
) fatal_error( "config.h must be included before wine/port.h\n" );
532 fatal_error( "wine/port.h must be included before everything except config.h\n" );
533 if (strcmp( pFile
->files
[0]->name
, "config.h" ))
534 fatal_error( "config.h must be included before wine/port.h\n" );
537 LIST_FOR_EACH_ENTRY( include
, &includes
, struct incl_file
, entry
)
538 if (!strcmp( name
, include
->name
)) goto found
;
540 include
= xmalloc( sizeof(*include
) );
541 memset( include
, 0, sizeof(*include
) );
542 include
->name
= xstrdup(name
);
543 include
->included_by
= pFile
;
544 include
->included_line
= input_line
;
545 if (system
) include
->flags
|= FLAG_SYSTEM
;
546 list_add_tail( &includes
, &include
->entry
);
548 pFile
->files
[pos
] = include
;
553 /*******************************************************************
556 static FILE *open_file( const char *path
)
560 if (path
[0] != '/' && strcmp( base_dir
, "." ))
562 char *full_path
= strmake( "%s/%s", base_dir
, path
);
563 ret
= fopen( full_path
, "r" );
566 else ret
= fopen( path
, "r" );
571 /*******************************************************************
574 static FILE *open_src_file( struct incl_file
*pFile
)
578 /* first try name as is */
579 if ((file
= open_file( pFile
->name
)))
581 pFile
->filename
= xstrdup( pFile
->name
);
584 /* now try in source dir */
587 pFile
->filename
= strmake( "%s/%s", src_dir
, pFile
->name
);
588 file
= open_file( pFile
->filename
);
590 /* now try parent dir */
591 if (!file
&& parent_dir
)
594 pFile
->filename
= strmake( "%s/%s/%s", src_dir
, parent_dir
, pFile
->name
);
596 pFile
->filename
= strmake( "%s/%s", parent_dir
, pFile
->name
);
597 file
= open_file( pFile
->filename
);
599 if (!file
) fatal_perror( "open %s", pFile
->name
);
604 /*******************************************************************
607 static FILE *open_include_file( struct incl_file
*pFile
)
615 /* check for generated bison header */
617 if (strendswith( pFile
->name
, ".tab.h" ))
619 filename
= replace_extension( pFile
->name
, 6, ".y" );
620 if (src_dir
) filename
= strmake( "%s/%s", src_dir
, filename
);
622 if ((file
= open_file( filename
)))
624 pFile
->sourcename
= filename
;
625 pFile
->filename
= xstrdup( pFile
->name
);
626 /* don't bother to parse it */
633 /* check for corresponding idl file in source dir */
635 if (strendswith( pFile
->name
, ".h" ))
637 filename
= replace_extension( pFile
->name
, 2, ".idl" );
638 if (src_dir
) filename
= strmake( "%s/%s", src_dir
, filename
);
640 if ((file
= open_file( filename
)))
642 pFile
->sourcename
= filename
;
643 pFile
->filename
= xstrdup( pFile
->name
);
649 /* now try in source dir */
651 filename
= strmake( "%s/%s", src_dir
, pFile
->name
);
653 filename
= xstrdup( pFile
->name
);
654 if ((file
= open_file( filename
))) goto found
;
657 /* now try in parent source dir */
661 filename
= strmake( "%s/%s/%s", src_dir
, parent_dir
, pFile
->name
);
663 filename
= strmake( "%s/%s", parent_dir
, pFile
->name
);
664 if ((file
= open_file( filename
))) goto found
;
668 /* check for corresponding idl file in global includes */
670 if (strendswith( pFile
->name
, ".h" ))
672 filename
= replace_extension( pFile
->name
, 2, ".idl" );
674 filename
= strmake( "%s/include/%s", top_src_dir
, filename
);
675 else if (top_obj_dir
)
676 filename
= strmake( "%s/include/%s", top_obj_dir
, filename
);
680 if (filename
&& (file
= open_file( filename
)))
682 pFile
->sourcename
= filename
;
683 pFile
->filename
= strmake( "%s/include/%s", top_obj_dir
, pFile
->name
);
689 /* check for corresponding .in file in global includes (for config.h.in) */
691 if (strendswith( pFile
->name
, ".h" ))
693 filename
= replace_extension( pFile
->name
, 2, ".h.in" );
695 filename
= strmake( "%s/include/%s", top_src_dir
, filename
);
696 else if (top_obj_dir
)
697 filename
= strmake( "%s/include/%s", top_obj_dir
, filename
);
701 if (filename
&& (file
= open_file( filename
)))
703 pFile
->sourcename
= filename
;
704 pFile
->filename
= strmake( "%s/include/%s", top_obj_dir
, pFile
->name
);
710 /* check for corresponding .x file in global includes */
712 if (strendswith( pFile
->name
, "tmpl.h" ))
714 filename
= replace_extension( pFile
->name
, 2, ".x" );
716 filename
= strmake( "%s/include/%s", top_src_dir
, filename
);
717 else if (top_obj_dir
)
718 filename
= strmake( "%s/include/%s", top_obj_dir
, filename
);
722 if (filename
&& (file
= open_file( filename
)))
724 pFile
->sourcename
= filename
;
725 pFile
->filename
= strmake( "%s/include/%s", top_obj_dir
, pFile
->name
);
731 /* now search in include paths */
732 for (i
= 0; i
< include_args
.count
; i
++)
734 const char *dir
= include_args
.str
[i
] + 2; /* skip -I */
737 /* ignore absolute paths that don't point into the source dir */
738 if (!top_src_dir
) continue;
739 len
= strlen( top_src_dir
);
740 if (strncmp( dir
, top_src_dir
, len
)) continue;
741 if (dir
[len
] && dir
[len
] != '/') continue;
743 filename
= strmake( "%s/%s", dir
, pFile
->name
);
744 if ((file
= open_file( filename
))) goto found
;
747 if (pFile
->flags
& FLAG_SYSTEM
) return NULL
; /* ignore system files we cannot find */
749 /* try in src file directory */
750 if ((p
= strrchr(pFile
->included_by
->filename
, '/')))
752 int l
= p
- pFile
->included_by
->filename
+ 1;
753 filename
= xmalloc(l
+ strlen(pFile
->name
) + 1);
754 memcpy( filename
, pFile
->included_by
->filename
, l
);
755 strcpy( filename
+ l
, pFile
->name
);
756 if ((file
= open_file( filename
))) goto found
;
760 fprintf( stderr
, "%s:%d: error: ", pFile
->included_by
->filename
, pFile
->included_line
);
761 perror( pFile
->name
);
762 pFile
= pFile
->included_by
;
763 while (pFile
&& pFile
->included_by
)
765 const char *parent
= pFile
->included_by
->sourcename
;
766 if (!parent
) parent
= pFile
->included_by
->name
;
767 fprintf( stderr
, "%s:%d: note: %s was first included here\n",
768 parent
, pFile
->included_line
, pFile
->name
);
769 pFile
= pFile
->included_by
;
774 pFile
->filename
= filename
;
779 /*******************************************************************
780 * parse_include_directive
782 static void parse_include_directive( struct incl_file
*source
, char *str
)
784 char quote
, *include
, *p
= str
;
786 while (*p
&& isspace(*p
)) p
++;
787 if (*p
!= '\"' && *p
!= '<' ) return;
789 if (quote
== '<') quote
= '>';
791 while (*p
&& (*p
!= quote
)) p
++;
792 if (!*p
) fatal_error( "malformed include directive '%s'\n", str
);
794 add_include( source
, include
, (quote
== '>') );
798 /*******************************************************************
799 * parse_pragma_directive
801 static void parse_pragma_directive( struct incl_file
*source
, char *str
)
803 char *flag
, *p
= str
;
805 if (!isspace( *p
)) return;
806 while (*p
&& isspace(*p
)) p
++;
807 p
= strtok( p
, " \t" );
808 if (strcmp( p
, "makedep" )) return;
810 while ((flag
= strtok( NULL
, " \t" )))
812 if (!strcmp( flag
, "depend" ))
814 while ((p
= strtok( NULL
, " \t" ))) add_include( source
, p
, 0 );
817 if (strendswith( source
->name
, ".idl" ))
819 if (!strcmp( flag
, "header" )) source
->flags
|= FLAG_IDL_HEADER
;
820 else if (!strcmp( flag
, "proxy" )) source
->flags
|= FLAG_IDL_PROXY
;
821 else if (!strcmp( flag
, "client" )) source
->flags
|= FLAG_IDL_CLIENT
;
822 else if (!strcmp( flag
, "server" )) source
->flags
|= FLAG_IDL_SERVER
;
823 else if (!strcmp( flag
, "ident" )) source
->flags
|= FLAG_IDL_IDENT
;
824 else if (!strcmp( flag
, "typelib" )) source
->flags
|= FLAG_IDL_TYPELIB
;
825 else if (!strcmp( flag
, "register" )) source
->flags
|= FLAG_IDL_REGISTER
;
827 else if (strendswith( source
->name
, ".rc" ))
829 if (!strcmp( flag
, "po" )) source
->flags
|= FLAG_RC_PO
;
831 else if (!strcmp( flag
, "implib" )) source
->flags
|= FLAG_C_IMPLIB
;
836 /*******************************************************************
837 * parse_cpp_directive
839 static void parse_cpp_directive( struct incl_file
*source
, char *str
)
841 while (*str
&& isspace(*str
)) str
++;
842 if (*str
++ != '#') return;
843 while (*str
&& isspace(*str
)) str
++;
845 if (!strncmp( str
, "include", 7 ))
846 parse_include_directive( source
, str
+ 7 );
847 else if (!strncmp( str
, "import", 6 ) && strendswith( source
->name
, ".m" ))
848 parse_include_directive( source
, str
+ 6 );
849 else if (!strncmp( str
, "pragma", 6 ))
850 parse_pragma_directive( source
, str
+ 6 );
854 /*******************************************************************
857 * If for_h_file is non-zero, it means we are not interested in the idl file
858 * itself, but only in the contents of the .h file that will be generated from it.
860 static void parse_idl_file( struct incl_file
*pFile
, FILE *file
, int for_h_file
)
862 char *buffer
, *include
;
867 /* generated .h file always includes these */
868 add_include( pFile
, "rpc.h", 1 );
869 add_include( pFile
, "rpcndr.h", 1 );
872 while ((buffer
= get_line( file
)))
876 while (*p
&& isspace(*p
)) p
++;
878 if (!strncmp( p
, "import", 6 ))
881 while (*p
&& isspace(*p
)) p
++;
882 if (*p
!= '"') continue;
884 while (*p
&& (*p
!= '"')) p
++;
885 if (!*p
) fatal_error( "malformed import directive\n" );
887 if (for_h_file
&& strendswith( include
, ".idl" )) strcpy( p
- 4, ".h" );
888 add_include( pFile
, include
, 0 );
892 if (for_h_file
) /* only check for #include inside cpp_quote */
894 if (strncmp( p
, "cpp_quote", 9 )) continue;
896 while (*p
&& isspace(*p
)) p
++;
897 if (*p
++ != '(') continue;
898 while (*p
&& isspace(*p
)) p
++;
899 if (*p
++ != '"') continue;
900 if (*p
++ != '#') continue;
901 while (*p
&& isspace(*p
)) p
++;
902 if (strncmp( p
, "include", 7 )) continue;
904 while (*p
&& isspace(*p
)) p
++;
905 if (*p
== '\\' && p
[1] == '"')
912 if (*p
++ != '<' ) continue;
916 while (*p
&& (*p
!= quote
)) p
++;
917 if (!*p
|| (quote
== '"' && p
[-1] != '\\'))
918 fatal_error( "malformed #include directive inside cpp_quote\n" );
919 if (quote
== '"') p
--; /* remove backslash */
921 add_include( pFile
, include
, (quote
== '>') );
925 parse_cpp_directive( pFile
, p
);
929 /*******************************************************************
932 static void parse_c_file( struct incl_file
*pFile
, FILE *file
)
937 while ((buffer
= get_line( file
)))
939 parse_cpp_directive( pFile
, buffer
);
944 /*******************************************************************
947 static void parse_rc_file( struct incl_file
*pFile
, FILE *file
)
949 char *buffer
, *include
;
952 while ((buffer
= get_line( file
)))
956 while (*p
&& isspace(*p
)) p
++;
958 if (p
[0] == '/' && p
[1] == '*') /* check for magic makedep comment */
961 while (*p
&& isspace(*p
)) p
++;
962 if (strncmp( p
, "@makedep:", 9 )) continue;
964 while (*p
&& isspace(*p
)) p
++;
969 while (*p
&& *p
!= quote
) p
++;
974 while (*p
&& !isspace(*p
) && *p
!= '*') p
++;
977 fatal_error( "malformed makedep comment\n" );
979 add_include( pFile
, include
, (quote
== '>') );
983 parse_cpp_directive( pFile
, buffer
);
988 /*******************************************************************
991 static void parse_in_file( struct incl_file
*source
, FILE *file
)
995 /* make sure it gets rebuilt when the version changes */
996 add_include( source
, "config.h", 1 );
998 if (!strendswith( source
->filename
, ".man.in" )) return; /* not a man page */
1001 while ((buffer
= get_line( file
)))
1003 if (strncmp( buffer
, ".TH", 3 )) continue;
1004 if (!(p
= strtok( buffer
, " \t" ))) continue; /* .TH */
1005 if (!(p
= strtok( NULL
, " \t" ))) continue; /* program name */
1006 if (!(p
= strtok( NULL
, " \t" ))) continue; /* man section */
1007 source
->sourcename
= xstrdup( p
); /* abuse source name to store section */
1013 /*******************************************************************
1014 * parse_generated_idl
1016 static void parse_generated_idl( struct incl_file
*source
)
1018 char *header
= replace_extension( source
->name
, 4, ".h" );
1020 source
->filename
= xstrdup( source
->name
);
1022 if (strendswith( source
->name
, "_c.c" ))
1024 add_include( source
, header
, 0 );
1026 else if (strendswith( source
->name
, "_i.c" ))
1028 add_include( source
, "rpc.h", 1 );
1029 add_include( source
, "rpcndr.h", 1 );
1030 add_include( source
, "guiddef.h", 1 );
1032 else if (strendswith( source
->name
, "_p.c" ))
1034 add_include( source
, "objbase.h", 1 );
1035 add_include( source
, "rpcproxy.h", 1 );
1036 add_include( source
, "wine/exception.h", 1 );
1037 add_include( source
, header
, 0 );
1039 else if (strendswith( source
->name
, "_s.c" ))
1041 add_include( source
, "wine/exception.h", 1 );
1042 add_include( source
, header
, 0 );
1048 /*******************************************************************
1051 static int is_generated_idl( struct incl_file
*source
)
1053 return (strendswith( source
->name
, "_c.c" ) ||
1054 strendswith( source
->name
, "_i.c" ) ||
1055 strendswith( source
->name
, "_p.c" ) ||
1056 strendswith( source
->name
, "_s.c" ));
1059 /*******************************************************************
1062 static void parse_file( struct incl_file
*source
, int src
)
1066 /* don't try to open certain types of files */
1067 if (strendswith( source
->name
, ".tlb" ))
1069 source
->filename
= xstrdup( source
->name
);
1073 file
= src
? open_src_file( source
) : open_include_file( source
);
1075 input_file_name
= source
->filename
;
1077 if (source
->sourcename
&& strendswith( source
->sourcename
, ".idl" ))
1078 parse_idl_file( source
, file
, 1 );
1079 else if (strendswith( source
->filename
, ".idl" ))
1080 parse_idl_file( source
, file
, 0 );
1081 else if (strendswith( source
->filename
, ".c" ) ||
1082 strendswith( source
->filename
, ".m" ) ||
1083 strendswith( source
->filename
, ".h" ) ||
1084 strendswith( source
->filename
, ".l" ) ||
1085 strendswith( source
->filename
, ".y" ))
1086 parse_c_file( source
, file
);
1087 else if (strendswith( source
->filename
, ".rc" ))
1088 parse_rc_file( source
, file
);
1089 else if (strendswith( source
->filename
, ".in" ))
1090 parse_in_file( source
, file
);
1092 input_file_name
= NULL
;
1096 /*******************************************************************
1099 * Add a source file to the list.
1101 static struct incl_file
*add_src_file( const char *name
)
1103 struct incl_file
*file
;
1105 if ((file
= find_src_file( name
))) return file
; /* we already have it */
1106 file
= xmalloc( sizeof(*file
) );
1107 memset( file
, 0, sizeof(*file
) );
1108 file
->name
= xstrdup(name
);
1109 list_add_tail( &sources
, &file
->entry
);
1111 /* special cases for generated files */
1113 if (is_generated_idl( file
))
1115 parse_generated_idl( file
);
1119 if (!strcmp( file
->name
, "dlldata.o" ))
1121 file
->filename
= xstrdup( "dlldata.c" );
1122 add_include( file
, "objbase.h", 1 );
1123 add_include( file
, "rpcproxy.h", 1 );
1127 if (!strcmp( file
->name
, "testlist.o" ))
1129 file
->filename
= xstrdup( "testlist.c" );
1130 add_include( file
, "wine/test.h", 1 );
1134 if (strendswith( file
->name
, ".o" ))
1136 /* default to .c for unknown extra object files */
1137 file
->filename
= replace_extension( file
->name
, 2, ".c" );
1141 if (strendswith( file
->name
, ".tlb" ) ||
1142 strendswith( file
->name
, ".res" ) ||
1143 strendswith( file
->name
, ".pot" ))
1145 file
->filename
= xstrdup( file
->name
);
1149 parse_file( file
, 1 );
1154 /*******************************************************************
1155 * add_generated_sources
1157 static void add_generated_sources(void)
1160 struct incl_file
*source
, *next
;
1162 LIST_FOR_EACH_ENTRY_SAFE( source
, next
, &sources
, struct incl_file
, entry
)
1164 if (!source
->flags
) continue;
1165 for (i
= 0; i
< sizeof(idl_outputs
) / sizeof(idl_outputs
[0]); i
++)
1167 if (!(source
->flags
& idl_outputs
[i
].flag
)) continue;
1168 if (!strendswith( idl_outputs
[i
].ext
, ".c" )) continue;
1169 add_src_file( replace_extension( source
->name
, 4, idl_outputs
[i
].ext
));
1171 if (source
->flags
& FLAG_IDL_PROXY
) add_src_file( "dlldata.o" );
1174 LIST_FOR_EACH_ENTRY_SAFE( source
, next
, &sources
, struct incl_file
, entry
)
1176 if (strendswith( source
->name
, "_c.c" ) ||
1177 strendswith( source
->name
, "_i.c" ) ||
1178 strendswith( source
->name
, "_p.c" ) ||
1179 strendswith( source
->name
, "_s.c" ) ||
1180 strendswith( source
->name
, ".tlb" ))
1182 char *idl
= replace_extension( source
->name
, 4, ".idl" );
1183 struct incl_file
*file
= add_src_file( idl
);
1184 if (strendswith( source
->name
, "_c.c" )) file
->flags
|= FLAG_IDL_CLIENT
;
1185 else if (strendswith( source
->name
, "_i.c" )) file
->flags
|= FLAG_IDL_IDENT
;
1186 else if (strendswith( source
->name
, "_p.c" )) file
->flags
|= FLAG_IDL_PROXY
;
1187 else if (strendswith( source
->name
, "_s.c" )) file
->flags
|= FLAG_IDL_SERVER
;
1188 else if (strendswith( source
->name
, ".tlb" )) file
->flags
|= FLAG_IDL_TYPELIB
;
1191 if (strendswith( source
->name
, "_r.res" ) ||
1192 strendswith( source
->name
, "_t.res" ))
1194 char *idl
= replace_extension( source
->name
, 6, ".idl" );
1195 struct incl_file
*file
= add_src_file( idl
);
1196 if (strendswith( source
->name
, "_r.res" )) file
->flags
|= FLAG_IDL_REGISTER
;
1197 else if (strendswith( source
->name
, "_t.res" )) file
->flags
|= FLAG_IDL_TYPELIB
;
1200 if (strendswith( source
->name
, ".pot" ))
1202 char *rc
= replace_extension( source
->name
, 4, ".rc" );
1203 struct incl_file
*file
= add_src_file( rc
);
1204 file
->flags
|= FLAG_RC_PO
;
1210 /*******************************************************************
1213 static char *get_make_variable( const char *name
)
1217 for (i
= 0; i
< nb_make_vars
; i
++)
1218 if (!strcmp( make_vars
[i
].name
, name
))
1219 return xstrdup( make_vars
[i
].value
);
1224 /*******************************************************************
1225 * get_expanded_make_variable
1227 static char *get_expanded_make_variable( const char *name
)
1229 char *p
, *end
, *var
, *expand
, *tmp
;
1231 expand
= get_make_variable( name
);
1232 if (!expand
) return NULL
;
1235 while ((p
= strchr( p
, '$' )))
1239 if (!(end
= strchr( p
+ 2, ')' ))) fatal_error( "syntax error in '%s'\n", expand
);
1241 if (strchr( p
+ 2, ':' )) fatal_error( "pattern replacement not supported for '%s'\n", p
+ 2 );
1242 var
= get_make_variable( p
+ 2 );
1243 tmp
= replace_substr( expand
, p
, end
- p
, var
? var
: "" );
1246 else if (p
[1] == '$')
1248 tmp
= replace_substr( expand
, p
, 2, "$" );
1250 else fatal_error( "syntax error in '%s'\n", expand
);
1252 /* switch to the new string */
1253 p
= tmp
+ (p
- expand
);
1261 /*******************************************************************
1262 * get_expanded_make_var_array
1264 static struct strarray
get_expanded_make_var_array( const char *name
)
1266 struct strarray ret
;
1267 char *value
, *token
;
1269 strarray_init( &ret
);
1270 if ((value
= get_expanded_make_variable( name
)))
1271 for (token
= strtok( value
, " \t" ); token
; token
= strtok( NULL
, " \t" ))
1272 strarray_add( &ret
, token
);
1277 /*******************************************************************
1280 static void parse_makefile(void)
1283 unsigned int i
, vars_size
= 0;
1286 input_file_name
= strmake( "%s/%s", base_dir
, makefile_name
);
1287 if (!(file
= fopen( input_file_name
, "r" )))
1289 fatal_perror( "open" );
1295 while ((buffer
= get_line( file
)))
1297 char *name
, *p
= buffer
;
1299 if (Separator
&& !strncmp( buffer
, Separator
, strlen(Separator
) )) break;
1300 while (isspace(*p
)) p
++;
1301 if (*p
== '#') continue; /* comment */
1303 while (isalnum(*p
) || *p
== '_') p
++;
1304 if (name
== p
) continue; /* not a variable */
1308 while (isspace(*p
)) p
++;
1310 if (*p
!= '=') continue; /* not an assignment */
1312 while (isspace(*p
)) p
++;
1314 /* redefining a variable replaces the previous value */
1315 for (i
= 0; i
< nb_make_vars
; i
++)
1316 if (!strcmp( make_vars
[i
].name
, name
)) break;
1317 if (i
== nb_make_vars
)
1319 if (nb_make_vars
== vars_size
)
1322 if (!vars_size
) vars_size
= 32;
1323 make_vars
= xrealloc( make_vars
, vars_size
* sizeof(*make_vars
) );
1325 make_vars
[nb_make_vars
++].name
= xstrdup( name
);
1327 else free( make_vars
[i
].value
);
1329 make_vars
[i
].value
= xstrdup( p
);
1332 input_file_name
= NULL
;
1336 /*******************************************************************
1339 static void output_include( struct incl_file
*pFile
, struct incl_file
*owner
, int *column
)
1343 if (pFile
->owner
== owner
) return;
1344 if (!pFile
->filename
) return;
1345 pFile
->owner
= owner
;
1346 output_filename( pFile
->filename
, column
);
1347 for (i
= 0; i
< MAX_INCLUDES
; i
++)
1348 if (pFile
->files
[i
]) output_include( pFile
->files
[i
], owner
, column
);
1352 /*******************************************************************
1355 static struct strarray
output_sources(void)
1357 struct incl_file
*source
;
1358 struct strarray clean_files
, subdirs
;
1359 int i
, column
, po_srcs
= 0, mc_srcs
= 0;
1360 int is_test
= find_src_file( "testlist.o" ) != NULL
;
1362 strarray_init( &clean_files
);
1363 strarray_init( &subdirs
);
1365 column
= output( "includes = -I." );
1366 if (src_dir
) output_filename( strmake( "-I%s", src_dir
), &column
);
1369 if (src_dir
) output_filename( strmake( "-I%s/%s", src_dir
, parent_dir
), &column
);
1370 else output_filename( strmake( "-I%s", parent_dir
), &column
);
1372 if (top_src_dir
&& top_obj_dir
) output_filename( strmake( "-I%s/include", top_obj_dir
), &column
);
1373 for (i
= 0; i
< include_args
.count
; i
++) output_filename( include_args
.str
[i
], &column
);
1376 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1379 char *obj
= xstrdup( source
->name
);
1380 char *ext
= get_extension( obj
);
1382 if (!ext
) fatal_error( "unsupported file type %s\n", source
->name
);
1386 if (src_dir
&& strchr( obj
, '/' ))
1388 char *dir
= xstrdup( obj
);
1389 *strrchr( dir
, '/' ) = 0;
1390 strarray_add_uniq( &subdirs
, dir
);
1391 sourcedep
= strmake( "%s %s", dir
, source
->filename
);
1393 else sourcedep
= xstrdup( source
->filename
);
1395 if (!strcmp( ext
, "y" )) /* yacc file */
1397 /* add source file dependency for parallel makes */
1398 char *header
= strmake( "%s.tab.h", obj
);
1400 if (find_include_file( header
))
1402 output( "%s.tab.h: %s\n", obj
, sourcedep
);
1403 output( "\t$(BISON) $(BISONFLAGS) -p %s_ -o %s.tab.c -d %s\n",
1404 obj
, obj
, source
->filename
);
1405 output( "%s.tab.c: %s %s\n", obj
, source
->filename
, header
);
1406 strarray_add( &clean_files
, strmake( "%s.tab.h", obj
));
1408 else output( "%s.tab.c: %s\n", obj
, sourcedep
);
1410 output( "\t$(BISON) $(BISONFLAGS) -p %s_ -o $@ %s\n", obj
, source
->filename
);
1411 output( "%s.tab.o: %s.tab.c\n", obj
, obj
);
1412 output( "\t$(CC) -c $(includes) $(ALLCFLAGS) -o $@ %s.tab.c\n", obj
);
1413 strarray_add( &clean_files
, strmake( "%s.tab.c", obj
));
1414 strarray_add( &clean_files
, strmake( "%s.tab.o", obj
));
1415 column
+= output( "%s.tab.o:", obj
);
1418 else if (!strcmp( ext
, "x" )) /* template file */
1420 output( "%s.h: $(MAKEXFTMPL) %s\n", obj
, sourcedep
);
1421 output( "\t$(MAKEXFTMPL) -H -o $@ %s\n", source
->filename
);
1422 strarray_add( &clean_files
, strmake( "%s.h", obj
));
1425 else if (!strcmp( ext
, "l" )) /* lex file */
1427 output( "%s.yy.c: %s\n", obj
, sourcedep
);
1428 output( "\t$(FLEX) $(LEXFLAGS) -o$@ %s\n", source
->filename
);
1429 output( "%s.yy.o: %s.yy.c\n", obj
, obj
);
1430 output( "\t$(CC) -c $(includes) $(ALLCFLAGS) -o $@ %s.yy.c\n", obj
);
1431 strarray_add( &clean_files
, strmake( "%s.yy.c", obj
));
1432 strarray_add( &clean_files
, strmake( "%s.yy.o", obj
));
1433 column
+= output( "%s.yy.o:", obj
);
1435 else if (!strcmp( ext
, "rc" )) /* resource file */
1437 if (source
->flags
& FLAG_RC_PO
)
1439 output( "%s.res: $(WRC) $(ALL_MO_FILES) %s\n", obj
, sourcedep
);
1440 output( "\t$(WRC) $(includes) $(RCFLAGS) -o $@ %s\n", source
->filename
);
1441 column
+= output( "%s.res rsrc.pot:", obj
);
1446 output( "%s.res: $(WRC) %s\n", obj
, sourcedep
);
1447 output( "\t$(WRC) $(includes) $(RCFLAGS) -o $@ %s\n", source
->filename
);
1448 column
+= output( "%s.res:", obj
);
1450 strarray_add( &clean_files
, strmake( "%s.res", obj
));
1452 else if (!strcmp( ext
, "mc" )) /* message file */
1454 output( "%s.res: $(WMC) $(ALL_MO_FILES) %s\n", obj
, sourcedep
);
1455 output( "\t$(WMC) -U -O res $(PORCFLAGS) -o $@ %s\n", source
->filename
);
1456 strarray_add( &clean_files
, strmake( "%s.res", obj
));
1458 column
+= output( "msg.pot %s.res:", obj
);
1460 else if (!strcmp( ext
, "idl" )) /* IDL file */
1463 unsigned int i
, nb_targets
= 0;
1465 if (!source
->flags
|| find_include_file( strmake( "%s.h", obj
)))
1466 source
->flags
|= FLAG_IDL_HEADER
;
1468 for (i
= 0; i
< sizeof(idl_outputs
) / sizeof(idl_outputs
[0]); i
++)
1470 if (!(source
->flags
& idl_outputs
[i
].flag
)) continue;
1471 output( "%s%s: $(WIDL)\n", obj
, idl_outputs
[i
].ext
);
1472 output( "\t$(WIDL) $(includes) %s -o $@ %s\n", idl_outputs
[i
].widl_arg
, source
->filename
);
1473 targets
[nb_targets
++] = strmake( "%s%s", obj
, idl_outputs
[i
].ext
);
1475 for (i
= 0; i
< nb_targets
; i
++)
1477 column
+= output( "%s%c", targets
[i
], i
< nb_targets
- 1 ? ' ' : ':' );
1478 strarray_add( &clean_files
, targets
[i
] );
1480 column
+= output( " %s", sourcedep
);
1482 else if (!strcmp( ext
, "in" )) /* .in file or man page */
1484 if (strendswith( obj
, ".man" ) && source
->sourcename
)
1486 char *dir
, *dest
= replace_extension( obj
, 4, "" );
1487 char *lang
= strchr( dest
, '.' );
1491 dir
= strmake( "$(DESTDIR)$(mandir)/%s/man%s", lang
, source
->sourcename
);
1493 else dir
= strmake( "$(DESTDIR)$(mandir)/man%s", source
->sourcename
);
1494 output( "install-man-pages:: %s %s\n", obj
, dir
);
1495 output( "\t$(INSTALL_DATA) %s %s/%s.%s\n",
1496 obj
, dir
, dest
, source
->sourcename
);
1497 output( "uninstall::\n" );
1498 output( "\t$(RM) %s/%s.%s\n",
1499 dir
, dest
, source
->sourcename
);
1501 strarray_add_uniq( &subdirs
, dir
);
1503 strarray_add( &clean_files
, xstrdup(obj
) );
1504 output( "%s: %s\n", obj
, sourcedep
);
1505 output( "\t$(SED_CMD) %s >$@ || ($(RM) $@ && false)\n", source
->filename
);
1506 column
+= output( "%s:", obj
);
1508 else if (!strcmp( ext
, "tlb" ) || !strcmp( ext
, "res" ) || !strcmp( ext
, "pot" ))
1510 strarray_add( &clean_files
, source
->name
);
1511 continue; /* nothing to do for typelib files */
1515 for (i
= 0; i
< object_extensions
.count
; i
++)
1517 strarray_add( &clean_files
, strmake( "%s.%s", obj
, object_extensions
.str
[i
] ));
1518 output( "%s.%s: %s\n", obj
, object_extensions
.str
[i
], sourcedep
);
1519 if (strstr( object_extensions
.str
[i
], "cross" ))
1520 output( "\t$(CROSSCC) -c $(includes) $(ALLCROSSCFLAGS) -o $@ %s\n", source
->filename
);
1522 output( "\t$(CC) -c $(includes) $(ALLCFLAGS) -o $@ %s\n", source
->filename
);
1524 if (source
->flags
& FLAG_C_IMPLIB
)
1526 strarray_add( &clean_files
, strmake( "%s.cross.o", obj
));
1527 output( "%s.cross.o: %s\n", obj
, sourcedep
);
1528 output( "\t$(CROSSCC) -c $(includes) $(ALLCROSSCFLAGS) -o $@ %s\n", source
->filename
);
1530 if (is_test
&& !strcmp( ext
, "c" ) && !is_generated_idl( source
))
1532 output( "%s.ok:\n", obj
);
1533 output( "\t$(RUNTEST) $(RUNTESTFLAGS) %s && touch $@\n", obj
);
1535 for (i
= 0; i
< object_extensions
.count
; i
++)
1536 column
+= output( "%s.%s ", obj
, object_extensions
.str
[i
] );
1537 if (source
->flags
& FLAG_C_IMPLIB
) column
+= output( "%s.cross.o", obj
);
1538 column
+= output( ":" );
1543 for (i
= 0; i
< MAX_INCLUDES
; i
++)
1544 if (source
->files
[i
]) output_include( source
->files
[i
], source
, &column
);
1548 /* rules for files that depend on multiple sources */
1552 column
= output( "rsrc.pot: $(WRC)" );
1553 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1554 if (source
->flags
& FLAG_RC_PO
) output_filename( source
->filename
, &column
);
1556 column
= output( "\t$(WRC) $(includes) $(RCFLAGS) -O pot -o $@" );
1557 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1558 if (source
->flags
& FLAG_RC_PO
) output_filename( source
->filename
, &column
);
1560 strarray_add( &clean_files
, "rsrc.pot" );
1565 column
= output( "msg.pot: $(WMC)" );
1566 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1567 if (strendswith( source
->name
, ".mc" )) output_filename( source
->filename
, &column
);
1569 column
= output( "\t$(WMC) -O pot -o $@" );
1570 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1571 if (strendswith( source
->name
, ".mc" )) output_filename( source
->filename
, &column
);
1573 strarray_add( &clean_files
, "msg.pot" );
1576 if (find_src_file( "dlldata.o" ))
1578 output( "dlldata.c: $(WIDL) %s\n", src_dir
? strmake("%s/Makefile.in", src_dir
) : "Makefile.in" );
1579 column
= output( "\t$(WIDL) --dlldata-only -o $@" );
1580 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1581 if (source
->flags
& FLAG_IDL_PROXY
) output_filename( source
->filename
, &column
);
1583 strarray_add( &clean_files
, "dlldata.c" );
1588 output( "testlist.c: $(MAKECTESTS) %s\n", src_dir
? strmake("%s/Makefile.in", src_dir
) : "Makefile.in" );
1589 column
= output( "\t$(MAKECTESTS) -o $@" );
1590 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1591 if (strendswith( source
->name
, ".c" ) && !is_generated_idl( source
))
1592 output_filename( source
->name
, &column
);
1594 column
= output( "check test:" );
1595 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1596 if (strendswith( source
->name
, ".c" ) && !is_generated_idl( source
))
1597 output_filename( replace_extension( source
->name
, 2, ".ok" ), &column
);
1599 output( "testclean::\n" );
1600 column
= output( "\t$(RM)" );
1601 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1602 if (strendswith( source
->name
, ".c" ) && !is_generated_idl( source
))
1604 char *ok_file
= replace_extension( source
->name
, 2, ".ok" );
1605 output_filename( ok_file
, &column
);
1606 strarray_add( &clean_files
, ok_file
);
1609 strarray_add( &clean_files
, "testlist.c" );
1612 if (clean_files
.count
)
1614 output( "clean::\n" );
1615 column
= output( "\t$(RM)" );
1616 for (i
= 0; i
< clean_files
.count
; i
++) output_filename( clean_files
.str
[i
], &column
);
1622 for (i
= column
= 0; i
< subdirs
.count
; i
++) output_filename( subdirs
.str
[i
], &column
);
1624 output( "\t$(MKDIR_P) -m 755 $@\n" );
1630 /*******************************************************************
1633 static FILE *create_temp_file( const char *orig
, char **tmp_name
)
1635 char *name
= xmalloc( strlen(orig
) + 13 );
1636 unsigned int i
, id
= getpid();
1640 for (i
= 0; i
< 100; i
++)
1642 sprintf( name
, "%s.tmp%08x", orig
, id
);
1643 if ((fd
= open( name
, O_RDWR
| O_CREAT
| O_EXCL
, 0666 )) != -1)
1645 ret
= fdopen( fd
, "w" );
1648 if (errno
!= EEXIST
) break;
1651 if (!ret
) fatal_error( "failed to create output file for '%s'\n", orig
);
1657 /*******************************************************************
1660 static void rename_temp_file( const char *tmp_name
, const char *dest
)
1662 int ret
= rename( tmp_name
, dest
);
1663 if (ret
== -1 && errno
== EEXIST
)
1665 /* rename doesn't overwrite on windows */
1667 ret
= rename( tmp_name
, dest
);
1672 fatal_error( "failed to rename output file to '%s'\n", dest
);
1677 /*******************************************************************
1680 static void output_gitignore( const char *dest
, const struct strarray
*files
)
1685 output_file
= create_temp_file( dest
, &tmp_name
);
1687 output( "# Automatically generated by make depend; DO NOT EDIT!!\n" );
1688 output( "/.gitignore\n" );
1689 output( "/Makefile\n" );
1690 for (i
= 0; i
< files
->count
; i
++)
1692 if (!strchr( files
->str
[i
], '/' )) output( "/" );
1693 output( "%s\n", files
->str
[i
] );
1696 fclose( output_file
);
1698 rename_temp_file( tmp_name
, dest
);
1703 /*******************************************************************
1704 * output_dependencies
1706 static void output_dependencies(void)
1708 char *tmp_name
= NULL
;
1709 char *path
= strmake( "%s/%s", base_dir
, makefile_name
);
1710 struct strarray targets
;
1712 strarray_init( &targets
);
1714 if (Separator
&& ((output_file
= fopen( path
, "r" ))))
1717 FILE *tmp_file
= create_temp_file( path
, &tmp_name
);
1720 while (fgets( buffer
, sizeof(buffer
), output_file
) && !found
)
1722 if (fwrite( buffer
, 1, strlen(buffer
), tmp_file
) != strlen(buffer
))
1723 fatal_error( "failed to write to %s\n", tmp_name
);
1724 found
= !strncmp( buffer
, Separator
, strlen(Separator
) );
1726 fclose( output_file
);
1727 output_file
= tmp_file
;
1728 if (!found
&& !list_empty(&sources
)) output( "\n%s\n", Separator
);
1732 if (!(output_file
= fopen( path
, Separator
? "a" : "w" )))
1733 fatal_perror( "%s", path
);
1736 if (!list_empty( &sources
)) targets
= output_sources();
1738 fclose( output_file
);
1742 rename_temp_file( tmp_name
, path
);
1747 if (!src_dir
) output_gitignore( strmake( "%s/.gitignore", base_dir
), &targets
);
1751 /*******************************************************************
1754 static void update_makefile( const char *path
)
1756 static const char *source_vars
[] =
1779 struct strarray value
;
1780 struct incl_file
*file
;
1785 src_dir
= get_expanded_make_variable( "srcdir" );
1786 top_src_dir
= get_expanded_make_variable( "top_srcdir" );
1787 top_obj_dir
= get_expanded_make_variable( "top_builddir" );
1788 parent_dir
= get_expanded_make_variable( "PARENTSRC" );
1790 strarray_init( &object_extensions
);
1791 value
= get_expanded_make_var_array( "MAKEDEPFLAGS" );
1792 for (i
= 0; i
< value
.count
; i
++)
1793 if (!strncmp( value
.str
[i
], "-x", 2 ))
1794 strarray_add( &object_extensions
, value
.str
[i
] + 2 );
1796 strarray_init( &include_args
);
1797 value
= get_expanded_make_var_array( "EXTRAINCL" );
1798 for (i
= 0; i
< value
.count
; i
++)
1799 if (!strncmp( value
.str
[i
], "-I", 2 ))
1800 strarray_add( &include_args
, value
.str
[i
] );
1804 list_init( &sources
);
1805 list_init( &includes
);
1807 for (var
= source_vars
; *var
; var
++)
1809 value
= get_expanded_make_var_array( *var
);
1810 for (i
= 0; i
< value
.count
; i
++) add_src_file( value
.str
[i
] );
1813 add_generated_sources();
1814 LIST_FOR_EACH_ENTRY( file
, &includes
, struct incl_file
, entry
) parse_file( file
, 0 );
1815 output_dependencies();
1819 /*******************************************************************
1822 static void parse_option( const char *opt
)
1827 if (opt
[2]) strarray_add( &include_args
, opt
);
1833 top_src_dir
= opt
+ 2;
1836 top_obj_dir
= opt
+ 2;
1839 parent_dir
= opt
+ 2;
1842 if (opt
[2]) makefile_name
= opt
+ 2;
1845 parse_makefile_mode
= 1;
1848 relative_dir_mode
= 1;
1851 if (opt
[2]) Separator
= opt
+ 2;
1852 else Separator
= NULL
;
1855 if (opt
[2]) strarray_add( &object_extensions
, xstrdup( opt
+ 2 ));
1858 fprintf( stderr
, "Unknown option '%s'\n%s", opt
, Usage
);
1864 /*******************************************************************
1867 int main( int argc
, char *argv
[] )
1869 struct incl_file
*pFile
;
1875 if (argv
[i
][0] == '-')
1877 parse_option( argv
[i
] );
1878 for (j
= i
; j
< argc
; j
++) argv
[j
] = argv
[j
+1];
1884 if (relative_dir_mode
)
1890 fprintf( stderr
, "Option -r needs two directories\n%s", Usage
);
1893 relpath
= get_relative_path( argv
[1], argv
[2] );
1894 printf( "%s\n", relpath
? relpath
: "." );
1898 if (parse_makefile_mode
)
1900 for (i
= 1; i
< argc
; i
++) update_makefile( argv
[i
] );
1905 for (i
= 1; i
< argc
; i
++) add_src_file( argv
[i
] );
1906 add_generated_sources();
1908 LIST_FOR_EACH_ENTRY( pFile
, &includes
, struct incl_file
, entry
) parse_file( pFile
, 0 );
1909 output_dependencies();