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 int system
; /* is it a system include (#include <name>) */
49 struct incl_file
*owner
;
50 struct incl_file
*files
[MAX_INCLUDES
];
53 static struct list sources
= LIST_INIT(sources
);
54 static struct list includes
= LIST_INIT(includes
);
56 struct object_extension
59 const char *extension
;
62 static struct list object_extensions
= LIST_INIT(object_extensions
);
70 static struct list paths
= LIST_INIT(paths
);
72 static const char *src_dir
;
73 static const char *top_src_dir
;
74 static const char *top_obj_dir
;
75 static const char *OutputFileName
= "Makefile";
76 static const char *Separator
= "### Dependencies";
77 static const char *input_file_name
;
78 static int input_line
;
79 static FILE *output_file
;
81 static const char Usage
[] =
82 "Usage: makedep [options] [files]\n"
84 " -Idir Search for include files in directory 'dir'\n"
85 " -Cdir Search for source files in directory 'dir'\n"
86 " -Sdir Set the top source directory\n"
87 " -Tdir Set the top object directory\n"
88 " -fxxx Store output in file 'xxx' (default: Makefile)\n"
89 " -sxxx Use 'xxx' as separator (default: \"### Dependencies\")\n";
93 #define __attribute__(x)
96 static void fatal_error( const char *msg
, ... ) __attribute__ ((__format__ (__printf__
, 1, 2)));
97 static void fatal_perror( const char *msg
, ... ) __attribute__ ((__format__ (__printf__
, 1, 2)));
98 static int output( const char *format
, ... ) __attribute__ ((__format__ (__printf__
, 1, 2)));
99 static char *strmake( const char* fmt
, ... ) __attribute__ ((__format__ (__printf__
, 1, 2)));
101 /*******************************************************************
104 static void fatal_error( const char *msg
, ... )
107 va_start( valist
, msg
);
110 fprintf( stderr
, "%s:", input_file_name
);
111 if (input_line
) fprintf( stderr
, "%d:", input_line
);
112 fprintf( stderr
, " error: " );
114 else fprintf( stderr
, "makedep: error: " );
115 vfprintf( stderr
, msg
, valist
);
121 /*******************************************************************
124 static void fatal_perror( const char *msg
, ... )
127 va_start( valist
, msg
);
130 fprintf( stderr
, "%s:", input_file_name
);
131 if (input_line
) fprintf( stderr
, "%d:", input_line
);
132 fprintf( stderr
, " error:" );
134 else fprintf( stderr
, "makedep: error:" );
141 /*******************************************************************
144 static void *xmalloc( size_t size
)
147 if (!(res
= malloc (size
? size
: 1)))
148 fatal_error( "Virtual memory exhausted.\n" );
153 /*******************************************************************
156 static void *xrealloc (void *ptr
, size_t size
)
160 if (!(res
= realloc( ptr
, size
)))
161 fatal_error( "Virtual memory exhausted.\n" );
165 /*******************************************************************
168 static char *xstrdup( const char *str
)
170 char *res
= strdup( str
);
171 if (!res
) fatal_error( "Virtual memory exhausted.\n" );
176 /*******************************************************************
179 static char *strmake( const char* fmt
, ... )
187 char *p
= xmalloc (size
);
189 n
= vsnprintf (p
, size
, fmt
, ap
);
191 if (n
== -1) size
*= 2;
192 else if ((size_t)n
>= size
) size
= n
+ 1;
199 /*******************************************************************
202 static int strendswith( const char* str
, const char* end
)
207 return l
>= m
&& strcmp(str
+ l
- m
, end
) == 0;
211 /*******************************************************************
214 static int output( const char *format
, ... )
219 va_start( valist
, format
);
220 ret
= vfprintf( output_file
, format
, valist
);
222 if (ret
< 0) fatal_perror( "output" );
227 /*******************************************************************
230 static void output_filename( const char *name
, int *column
)
232 if (*column
+ strlen(name
) + 1 > 100)
237 *column
+= output( " %s", name
);
241 /*******************************************************************
244 static char *get_extension( char *filename
)
246 char *ext
= strrchr( filename
, '.' );
247 if (ext
&& strchr( ext
, '/' )) ext
= NULL
;
252 /*******************************************************************
255 static char *get_line( FILE *file
)
258 static unsigned int size
;
263 buffer
= xmalloc( size
);
265 if (!fgets( buffer
, size
, file
)) return NULL
;
270 char *p
= buffer
+ strlen(buffer
);
271 /* if line is larger than buffer, resize buffer */
272 while (p
== buffer
+ size
- 1 && p
[-1] != '\n')
274 buffer
= xrealloc( buffer
, size
* 2 );
275 if (!fgets( buffer
+ size
- 1, size
+ 1, file
)) break;
276 p
= buffer
+ strlen(buffer
);
279 if (p
> buffer
&& p
[-1] == '\n')
282 if (p
> buffer
&& p
[-1] == '\r') *(--p
) = 0;
283 if (p
> buffer
&& p
[-1] == '\\')
286 /* line ends in backslash, read continuation line */
287 if (!fgets( p
, size
- (p
- buffer
), file
)) return buffer
;
296 /*******************************************************************
297 * add_object_extension
299 * Add an extension for object files.
301 static void add_object_extension( const char *ext
)
303 struct object_extension
*object_extension
= xmalloc( sizeof(*object_extension
) );
304 list_add_tail( &object_extensions
, &object_extension
->entry
);
305 object_extension
->extension
= ext
;
308 /*******************************************************************
311 * Add a directory to the include path.
313 static void add_include_path( const char *name
)
315 struct incl_path
*path
= xmalloc( sizeof(*path
) );
316 list_add_tail( &paths
, &path
->entry
);
320 /*******************************************************************
323 static struct incl_file
*find_src_file( const char *name
)
325 struct incl_file
*file
;
327 LIST_FOR_EACH_ENTRY( file
, &sources
, struct incl_file
, entry
)
328 if (!strcmp( name
, file
->name
)) return file
;
332 /*******************************************************************
335 static struct incl_file
*find_include_file( const char *name
)
337 struct incl_file
*file
;
339 LIST_FOR_EACH_ENTRY( file
, &includes
, struct incl_file
, entry
)
340 if (!strcmp( name
, file
->name
)) return file
;
344 /*******************************************************************
345 * find_target_src_file
347 * Check if we have a source file as a target for the specified source with a different extension.
349 static struct incl_file
*find_target_src_file( const char *name
, const char *ext
)
351 struct incl_file
*ret
;
352 char *p
, *match
= xmalloc( strlen( name
) + strlen( ext
) + 1 );
354 strcpy( match
, name
);
355 if ((p
= get_extension( match
))) strcpy( p
, ext
);
356 else strcat( match
, ext
);
357 ret
= find_src_file( match
);
362 /*******************************************************************
365 * Add an include file if it doesn't already exists.
367 static struct incl_file
*add_include( struct incl_file
*pFile
, const char *name
, int system
)
369 struct incl_file
*include
;
373 for (pos
= 0; pos
< MAX_INCLUDES
; pos
++) if (!pFile
->files
[pos
]) break;
374 if (pos
>= MAX_INCLUDES
)
375 fatal_error( "too many included files, please fix MAX_INCLUDES\n" );
377 /* enforce some rules for the Wine tree */
379 if (!memcmp( name
, "../", 3 ))
380 fatal_error( "#include directive with relative path not allowed\n" );
382 if (!strcmp( name
, "config.h" ))
384 if ((ext
= strrchr( pFile
->filename
, '.' )) && !strcmp( ext
, ".h" ))
385 fatal_error( "config.h must not be included by a header file\n" );
387 fatal_error( "config.h must be included before anything else\n" );
389 else if (!strcmp( name
, "wine/port.h" ))
391 if ((ext
= strrchr( pFile
->filename
, '.' )) && !strcmp( ext
, ".h" ))
392 fatal_error( "wine/port.h must not be included by a header file\n" );
393 if (!pos
) fatal_error( "config.h must be included before wine/port.h\n" );
395 fatal_error( "wine/port.h must be included before everything except config.h\n" );
396 if (strcmp( pFile
->files
[0]->name
, "config.h" ))
397 fatal_error( "config.h must be included before wine/port.h\n" );
400 LIST_FOR_EACH_ENTRY( include
, &includes
, struct incl_file
, entry
)
401 if (!strcmp( name
, include
->name
)) goto found
;
403 include
= xmalloc( sizeof(*include
) );
404 memset( include
, 0, sizeof(*include
) );
405 include
->name
= xstrdup(name
);
406 include
->included_by
= pFile
;
407 include
->included_line
= input_line
;
408 include
->system
= system
;
409 list_add_tail( &includes
, &include
->entry
);
411 pFile
->files
[pos
] = include
;
416 /*******************************************************************
419 static FILE *open_src_file( struct incl_file
*pFile
)
423 /* first try name as is */
424 if ((file
= fopen( pFile
->name
, "r" )))
426 pFile
->filename
= xstrdup( pFile
->name
);
429 /* now try in source dir */
432 pFile
->filename
= strmake( "%s/%s", src_dir
, pFile
->name
);
433 file
= fopen( pFile
->filename
, "r" );
435 if (!file
) fatal_perror( "open %s", pFile
->name
);
440 /*******************************************************************
443 static FILE *open_include_file( struct incl_file
*pFile
)
447 struct incl_path
*path
;
451 /* check for generated bison header */
453 if (strendswith( pFile
->name
, ".tab.h" ))
456 filename
= strmake( "%s/%.*s.y", src_dir
, strlen(pFile
->name
) - 6, pFile
->name
);
458 filename
= strmake( "%.*s.y", strlen(pFile
->name
) - 6, pFile
->name
);
460 if ((file
= fopen( filename
, "r" )))
462 pFile
->sourcename
= filename
;
463 pFile
->filename
= xstrdup( pFile
->name
);
464 /* don't bother to parse it */
471 /* check for generated message resource */
473 if (strendswith( pFile
->name
, ".mc.rc" ))
476 filename
= strmake( "%s/%s", src_dir
, pFile
->name
);
478 filename
= xstrdup( pFile
->name
);
480 filename
[strlen(filename
) - 3] = 0;
482 if ((file
= fopen( filename
, "r" )))
484 pFile
->sourcename
= filename
;
485 pFile
->filename
= xstrdup( pFile
->name
);
486 /* don't bother to parse it */
493 /* check for corresponding idl file in source dir */
495 if (strendswith( pFile
->name
, ".h" ))
498 filename
= strmake( "%s/%.*s.idl", src_dir
, strlen(pFile
->name
) - 2, pFile
->name
);
500 filename
= strmake( "%.*s.idl", strlen(pFile
->name
) - 2, pFile
->name
);
502 if ((file
= fopen( filename
, "r" )))
504 pFile
->sourcename
= filename
;
505 pFile
->filename
= xstrdup( pFile
->name
);
511 /* first try name as is */
512 if ((file
= fopen( pFile
->name
, "r" )))
514 pFile
->filename
= xstrdup( pFile
->name
);
518 /* now try in source dir */
521 filename
= strmake( "%s/%s", src_dir
, pFile
->name
);
522 if ((file
= fopen( filename
, "r" ))) goto found
;
526 /* check for corresponding idl file in global includes */
528 if (strendswith( pFile
->name
, ".h" ))
531 filename
= strmake( "%s/include/%.*s.idl",
532 top_src_dir
, strlen(pFile
->name
) - 2, pFile
->name
);
533 else if (top_obj_dir
)
534 filename
= strmake( "%s/include/%.*s.idl",
535 top_obj_dir
, strlen(pFile
->name
) - 2, pFile
->name
);
539 if (filename
&& (file
= fopen( filename
, "r" )))
541 pFile
->sourcename
= filename
;
542 pFile
->filename
= strmake( "%s/include/%s", top_obj_dir
, pFile
->name
);
548 /* check for corresponding .x file in global includes */
550 if (strendswith( pFile
->name
, "tmpl.h" ))
553 filename
= strmake( "%s/include/%.*s.x",
554 top_src_dir
, strlen(pFile
->name
) - 2, pFile
->name
);
555 else if (top_obj_dir
)
556 filename
= strmake( "%s/include/%.*s.x",
557 top_obj_dir
, strlen(pFile
->name
) - 2, pFile
->name
);
561 if (filename
&& (file
= fopen( filename
, "r" )))
563 pFile
->sourcename
= filename
;
564 pFile
->filename
= strmake( "%s/include/%s", top_obj_dir
, pFile
->name
);
570 /* now try in global includes */
573 filename
= strmake( "%s/include/%s", top_obj_dir
, pFile
->name
);
574 if ((file
= fopen( filename
, "r" ))) goto found
;
579 filename
= strmake( "%s/include/%s", top_src_dir
, pFile
->name
);
580 if ((file
= fopen( filename
, "r" ))) goto found
;
584 /* now search in include paths */
585 LIST_FOR_EACH_ENTRY( path
, &paths
, struct incl_path
, entry
)
587 filename
= strmake( "%s/%s", path
->name
, pFile
->name
);
588 if ((file
= fopen( filename
, "r" ))) goto found
;
591 if (pFile
->system
) return NULL
; /* ignore system files we cannot find */
593 /* try in src file directory */
594 if ((p
= strrchr(pFile
->included_by
->filename
, '/')))
596 int l
= p
- pFile
->included_by
->filename
+ 1;
597 filename
= xmalloc(l
+ strlen(pFile
->name
) + 1);
598 memcpy( filename
, pFile
->included_by
->filename
, l
);
599 strcpy( filename
+ l
, pFile
->name
);
600 if ((file
= fopen( filename
, "r" ))) goto found
;
604 fprintf( stderr
, "%s:%d: error: ", pFile
->included_by
->filename
, pFile
->included_line
);
605 perror( pFile
->name
);
606 pFile
= pFile
->included_by
;
607 while (pFile
&& pFile
->included_by
)
609 const char *parent
= pFile
->included_by
->sourcename
;
610 if (!parent
) parent
= pFile
->included_by
->name
;
611 fprintf( stderr
, "%s:%d: note: %s was first included here\n",
612 parent
, pFile
->included_line
, pFile
->name
);
613 pFile
= pFile
->included_by
;
618 pFile
->filename
= filename
;
623 /*******************************************************************
626 * If for_h_file is non-zero, it means we are not interested in the idl file
627 * itself, but only in the contents of the .h file that will be generated from it.
629 static void parse_idl_file( struct incl_file
*pFile
, FILE *file
, int for_h_file
)
631 char *buffer
, *include
;
636 /* generated .h file always includes these */
637 add_include( pFile
, "rpc.h", 1 );
638 add_include( pFile
, "rpcndr.h", 1 );
641 while ((buffer
= get_line( file
)))
645 while (*p
&& isspace(*p
)) p
++;
647 if (!strncmp( p
, "import", 6 ))
650 while (*p
&& isspace(*p
)) p
++;
651 if (*p
!= '"') continue;
653 while (*p
&& (*p
!= '"')) p
++;
654 if (!*p
) fatal_error( "malformed import directive\n" );
656 if (for_h_file
&& strendswith( include
, ".idl" )) strcpy( p
- 4, ".h" );
657 add_include( pFile
, include
, 0 );
661 if (for_h_file
) /* only check for #include inside cpp_quote */
663 if (strncmp( p
, "cpp_quote", 9 )) continue;
665 while (*p
&& isspace(*p
)) p
++;
666 if (*p
++ != '(') continue;
667 while (*p
&& isspace(*p
)) p
++;
668 if (*p
++ != '"') continue;
669 if (*p
++ != '#') continue;
670 while (*p
&& isspace(*p
)) p
++;
671 if (strncmp( p
, "include", 7 )) continue;
673 while (*p
&& isspace(*p
)) p
++;
674 if (*p
== '\\' && p
[1] == '"')
681 if (*p
++ != '<' ) continue;
685 while (*p
&& (*p
!= quote
)) p
++;
686 if (!*p
|| (quote
== '"' && p
[-1] != '\\'))
687 fatal_error( "malformed #include directive inside cpp_quote\n" );
688 if (quote
== '"') p
--; /* remove backslash */
690 add_include( pFile
, include
, (quote
== '>') );
694 /* check for normal #include */
695 if (*p
++ != '#') continue;
696 while (*p
&& isspace(*p
)) p
++;
697 if (strncmp( p
, "include", 7 )) continue;
699 while (*p
&& isspace(*p
)) p
++;
700 if (*p
!= '\"' && *p
!= '<' ) continue;
702 if (quote
== '<') quote
= '>';
704 while (*p
&& (*p
!= quote
)) p
++;
705 if (!*p
) fatal_error( "malformed #include directive\n" );
707 add_include( pFile
, include
, (quote
== '>') );
711 /*******************************************************************
714 static void parse_c_file( struct incl_file
*pFile
, FILE *file
)
716 char *buffer
, *include
;
719 while ((buffer
= get_line( file
)))
723 while (*p
&& isspace(*p
)) p
++;
724 if (*p
++ != '#') continue;
725 while (*p
&& isspace(*p
)) p
++;
726 if (!strncmp( p
, "include", 7 )) p
+= 7;
727 else if (!strncmp( p
, "import", 6 )) p
+= 6;
729 while (*p
&& isspace(*p
)) p
++;
730 if (*p
!= '\"' && *p
!= '<' ) continue;
732 if (quote
== '<') quote
= '>';
734 while (*p
&& (*p
!= quote
)) p
++;
735 if (!*p
) fatal_error( "malformed #include directive\n" );
737 add_include( pFile
, include
, (quote
== '>') );
742 /*******************************************************************
745 static void parse_rc_file( struct incl_file
*pFile
, FILE *file
)
747 char *buffer
, *include
;
750 while ((buffer
= get_line( file
)))
754 while (*p
&& isspace(*p
)) p
++;
756 if (p
[0] == '/' && p
[1] == '*') /* check for magic makedep comment */
759 while (*p
&& isspace(*p
)) p
++;
760 if (strncmp( p
, "@makedep:", 9 )) continue;
762 while (*p
&& isspace(*p
)) p
++;
767 while (*p
&& *p
!= quote
) p
++;
772 while (*p
&& !isspace(*p
) && *p
!= '*') p
++;
775 fatal_error( "malformed makedep comment\n" );
778 else /* check for #include */
780 if (*p
++ != '#') continue;
781 while (*p
&& isspace(*p
)) p
++;
782 if (strncmp( p
, "include", 7 )) continue;
784 while (*p
&& isspace(*p
)) p
++;
785 if (*p
!= '\"' && *p
!= '<' ) continue;
787 if (quote
== '<') quote
= '>';
789 while (*p
&& (*p
!= quote
)) p
++;
790 if (!*p
) fatal_error( "malformed #include directive\n" );
793 add_include( pFile
, include
, (quote
== '>') );
798 /*******************************************************************
799 * parse_generated_idl
801 static void parse_generated_idl( struct incl_file
*source
)
803 char *header
, *basename
;
805 basename
= xstrdup( source
->name
);
806 basename
[strlen(basename
) - 4] = 0;
807 header
= strmake( "%s.h", basename
);
808 source
->filename
= xstrdup( source
->name
);
810 if (strendswith( source
->name
, "_c.c" ))
812 add_include( source
, header
, 0 );
814 else if (strendswith( source
->name
, "_i.c" ))
816 add_include( source
, "rpc.h", 1 );
817 add_include( source
, "rpcndr.h", 1 );
818 add_include( source
, "guiddef.h", 1 );
820 else if (strendswith( source
->name
, "_p.c" ))
822 add_include( source
, "objbase.h", 1 );
823 add_include( source
, "rpcproxy.h", 1 );
824 add_include( source
, "wine/exception.h", 1 );
825 add_include( source
, header
, 0 );
827 else if (strendswith( source
->name
, "_s.c" ))
829 add_include( source
, "wine/exception.h", 1 );
830 add_include( source
, header
, 0 );
837 /*******************************************************************
840 static int is_generated_idl( struct incl_file
*source
)
842 return (strendswith( source
->name
, "_c.c" ) ||
843 strendswith( source
->name
, "_i.c" ) ||
844 strendswith( source
->name
, "_p.c" ) ||
845 strendswith( source
->name
, "_s.c" ));
848 /*******************************************************************
851 static void parse_file( struct incl_file
*source
, int src
)
855 /* special case for source files generated from idl */
856 if (is_generated_idl( source
))
858 parse_generated_idl( source
);
862 if (!strcmp( source
->name
, "dlldata.o" ))
864 source
->filename
= xstrdup( "dlldata.c" );
865 add_include( source
, "objbase.h", 1 );
866 add_include( source
, "rpcproxy.h", 1 );
870 if (!strcmp( source
->name
, "testlist.o" ))
872 source
->filename
= xstrdup( "testlist.c" );
873 add_include( source
, "wine/test.h", 1 );
877 if (strendswith( source
->name
, ".o" ))
879 /* default to .c for unknown extra object files */
880 source
->filename
= xstrdup( source
->name
);
881 source
->filename
[strlen(source
->filename
) - 1] = 'c';
885 /* don't try to open certain types of files */
886 if (strendswith( source
->name
, ".tlb" ) ||
887 strendswith( source
->name
, ".res" ) ||
888 strendswith( source
->name
, ".pot" ) ||
889 strendswith( source
->name
, ".x" ))
891 source
->filename
= xstrdup( source
->name
);
895 file
= src
? open_src_file( source
) : open_include_file( source
);
897 input_file_name
= source
->filename
;
899 if (source
->sourcename
&& strendswith( source
->sourcename
, ".idl" ))
900 parse_idl_file( source
, file
, 1 );
901 else if (strendswith( source
->filename
, ".idl" ))
902 parse_idl_file( source
, file
, 0 );
903 else if (strendswith( source
->filename
, ".c" ) ||
904 strendswith( source
->filename
, ".m" ) ||
905 strendswith( source
->filename
, ".h" ) ||
906 strendswith( source
->filename
, ".l" ) ||
907 strendswith( source
->filename
, ".y" ))
908 parse_c_file( source
, file
);
909 else if (strendswith( source
->filename
, ".rc" ))
910 parse_rc_file( source
, file
);
912 input_file_name
= NULL
;
916 /*******************************************************************
919 * Add a source file to the list.
921 static struct incl_file
*add_src_file( const char *name
)
923 struct incl_file
*file
;
925 if (find_src_file( name
)) return NULL
; /* we already have it */
926 file
= xmalloc( sizeof(*file
) );
927 memset( file
, 0, sizeof(*file
) );
928 file
->name
= xstrdup(name
);
929 list_add_tail( &sources
, &file
->entry
);
930 parse_file( file
, 1 );
935 /*******************************************************************
938 static void output_include( struct incl_file
*pFile
, struct incl_file
*owner
, int *column
)
942 if (pFile
->owner
== owner
) return;
943 if (!pFile
->filename
) return;
944 pFile
->owner
= owner
;
945 output_filename( pFile
->filename
, column
);
946 for (i
= 0; i
< MAX_INCLUDES
; i
++)
947 if (pFile
->files
[i
]) output_include( pFile
->files
[i
], owner
, column
);
951 /*******************************************************************
954 static void output_sources(void)
956 struct incl_file
*source
;
957 int i
, column
, po_srcs
= 0, mc_srcs
= 0;
959 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
961 char *obj
= xstrdup( source
->name
);
962 char *ext
= get_extension( obj
);
964 if (!ext
) fatal_error( "unsupported file type %s\n", source
->name
);
968 if (!strcmp( ext
, "y" )) /* yacc file */
970 /* add source file dependency for parallel makes */
971 char *header
= strmake( "%s.tab.h", obj
);
972 if (find_include_file( header
))
974 output( "%s.tab.h: %s\n", obj
, source
->filename
);
975 output( "\t$(BISON) $(BISONFLAGS) -p %s_ -o %s.tab.c -d %s\n",
976 obj
, obj
, source
->filename
);
977 output( "%s.tab.c: %s %s\n", obj
, source
->filename
, header
);
979 else output( "%s.tab.c: %s\n", obj
, source
->filename
);
981 output( "\t$(BISON) $(BISONFLAGS) -p %s_ -o $@ %s\n", obj
, source
->filename
);
982 column
+= output( "%s.tab.o: %s.tab.c", obj
, obj
);
985 else if (!strcmp( ext
, "l" )) /* lex file */
987 output( "%s.yy.c: %s\n", obj
, source
->filename
);
988 output( "\t$(FLEX) $(LEXFLAGS) -o$@ %s\n", source
->filename
);
989 column
+= output( "%s.yy.o: %s.yy.c", obj
, obj
);
991 else if (!strcmp( ext
, "rc" )) /* resource file */
993 if (find_target_src_file( source
->name
, ".pot" ))
995 output( "%s.res: $(WRC) $(ALL_MO_FILES) %s\n", obj
, source
->filename
);
996 output( "\t$(WRC) $(RCFLAGS) -o $@ %s\n", source
->filename
);
997 column
+= output( "%s.res rsrc.pot:", obj
);
1002 output( "%s.res: $(WRC) %s\n", obj
, source
->filename
);
1003 output( "\t$(WRC) $(RCFLAGS) -o $@ %s\n", source
->filename
);
1004 column
+= output( "%s.res:", obj
);
1007 else if (!strcmp( ext
, "mc" )) /* message file */
1009 output( "%s.res: $(WMC) $(ALL_MO_FILES) %s\n", obj
, source
->filename
);
1010 output( "\t$(WMC) -U -O res $(PORCFLAGS) -o $@ %s\n", source
->filename
);
1012 column
+= output( "msg.pot %s.res:", obj
);
1014 else if (!strcmp( ext
, "idl" )) /* IDL file */
1018 char ending
[] = "_?.c";
1020 char *header
= strmake( "%s.h", obj
);
1022 if (find_target_src_file( source
->name
, ".tlb" ))
1024 output( "%s.tlb %s_t.res: $(WIDL)\n", obj
, obj
);
1025 output( "\t$(WIDL) $(TARGETFLAGS) $(IDLFLAGS) -t -o $@ %s\n", source
->filename
);
1026 targets
[nb_targets
++] = strmake( "%s.tlb", obj
);
1027 targets
[nb_targets
++] = strmake( "%s_t.res", obj
);
1030 for (suffix
= "cips"; *suffix
; suffix
++)
1032 ending
[1] = *suffix
;
1033 if (!find_target_src_file( source
->name
, ending
)) continue;
1034 output( "%s%s: $(WIDL)\n", obj
, ending
);
1035 output( "\t$(WIDL) $(IDLFLAGS) -%c -o $@ %s\n",
1036 *suffix
== 'i' ? 'u' : *suffix
, source
->filename
);
1037 targets
[nb_targets
++] = strmake( "%s%s", obj
, ending
);
1040 if (find_target_src_file( source
->name
, "_r.res" ))
1042 output( "%s_r.res: $(WIDL)\n", obj
);
1043 output( "\t$(WIDL) $(IDLFLAGS) -r -o $@ %s\n", source
->filename
);
1044 targets
[nb_targets
++] = strmake( "%s_r.res", obj
);
1047 if (!nb_targets
|| find_include_file( header
))
1049 output( "%s.h: $(WIDL)\n", obj
);
1050 output( "\t$(WIDL) $(IDLFLAGS) -h -o $@ %s\n", source
->filename
);
1051 targets
[nb_targets
++] = header
;
1053 else free( header
);
1055 for (i
= 0; i
< nb_targets
; i
++)
1057 column
+= output( "%s%c", targets
[i
], i
< nb_targets
- 1 ? ' ' : ':' );
1060 column
+= output( " %s", source
->filename
);
1062 else if (!strcmp( ext
, "tlb" ) || !strcmp( ext
, "res" ) || !strcmp( ext
, "pot" ))
1064 continue; /* nothing to do for typelib files */
1068 struct object_extension
*ext
;
1069 LIST_FOR_EACH_ENTRY( ext
, &object_extensions
, struct object_extension
, entry
)
1070 column
+= output( "%s.%s ", obj
, ext
->extension
);
1071 column
+= output( ": %s", source
->filename
);
1075 for (i
= 0; i
< MAX_INCLUDES
; i
++)
1076 if (source
->files
[i
]) output_include( source
->files
[i
], source
, &column
);
1080 /* rules for files that depend on multiple sources */
1084 column
= output( "rsrc.pot: $(WRC)" );
1085 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1086 if (strendswith( source
->name
, ".rc" ) && find_target_src_file( source
->name
, ".pot" ))
1087 output_filename( source
->filename
, &column
);
1089 column
= output( "\t$(WRC) $(RCFLAGS) -O pot -o $@" );
1090 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1091 if (strendswith( source
->name
, ".rc" ) && find_target_src_file( source
->name
, ".pot" ))
1092 output_filename( source
->filename
, &column
);
1098 column
= output( "msg.pot: $(WMC)" );
1099 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1100 if (strendswith( source
->name
, ".mc" )) output_filename( source
->filename
, &column
);
1102 column
= output( "\t$(WMC) -O pot -o $@" );
1103 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1104 if (strendswith( source
->name
, ".mc" )) output_filename( source
->filename
, &column
);
1108 if (find_src_file( "dlldata.o" ))
1110 output( "dlldata.c: $(WIDL) Makefile.in\n" );
1111 column
= output( "\t$(WIDL) $(IDLFLAGS) --dlldata-only -o $@" );
1112 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1113 if (strendswith( source
->name
, ".idl" ) && find_target_src_file( source
->name
, "_p.c" ))
1114 output_filename( source
->filename
, &column
);
1118 if (find_src_file( "testlist.o" ))
1120 output( "testlist.c: $(MAKECTESTS) Makefile.in\n" );
1121 column
= output( "\t$(MAKECTESTS) -o $@" );
1122 LIST_FOR_EACH_ENTRY( source
, &sources
, struct incl_file
, entry
)
1123 if (strendswith( source
->name
, ".c" ) && !is_generated_idl( source
))
1124 output_filename( source
->filename
, &column
);
1130 /*******************************************************************
1133 static FILE *create_temp_file( char **tmp_name
)
1135 char *name
= xmalloc( strlen(OutputFileName
) + 13 );
1136 unsigned int i
, id
= getpid();
1140 for (i
= 0; i
< 100; i
++)
1142 sprintf( name
, "%s.tmp%08x", OutputFileName
, id
);
1143 if ((fd
= open( name
, O_RDWR
| O_CREAT
| O_EXCL
, 0666 )) != -1)
1145 ret
= fdopen( fd
, "w" );
1148 if (errno
!= EEXIST
) break;
1151 if (!ret
) fatal_error( "failed to create output file for '%s'\n", OutputFileName
);
1157 /*******************************************************************
1158 * output_dependencies
1160 static void output_dependencies(void)
1162 char *tmp_name
= NULL
;
1164 if (Separator
&& ((output_file
= fopen( OutputFileName
, "r" ))))
1167 FILE *tmp_file
= create_temp_file( &tmp_name
);
1170 while (fgets( buffer
, sizeof(buffer
), output_file
) && !found
)
1172 if (fwrite( buffer
, 1, strlen(buffer
), tmp_file
) != strlen(buffer
))
1173 fatal_error( "failed to write to %s\n", tmp_name
);
1174 found
= !strncmp( buffer
, Separator
, strlen(Separator
) );
1176 fclose( output_file
);
1177 output_file
= tmp_file
;
1178 if (!found
&& list_head(&sources
)) output( "\n%s\n", Separator
);
1182 if (!(output_file
= fopen( OutputFileName
, Separator
? "a" : "w" )))
1183 fatal_perror( "%s", OutputFileName
);
1188 fclose( output_file
);
1193 int ret
= rename( tmp_name
, OutputFileName
);
1194 if (ret
== -1 && errno
== EEXIST
)
1196 /* rename doesn't overwrite on windows */
1197 unlink( OutputFileName
);
1198 ret
= rename( tmp_name
, OutputFileName
);
1203 fatal_error( "failed to rename output file to '%s'\n", OutputFileName
);
1210 /*******************************************************************
1213 static void parse_option( const char *opt
)
1218 if (opt
[2]) add_include_path( opt
+ 2 );
1224 top_src_dir
= opt
+ 2;
1227 top_obj_dir
= opt
+ 2;
1230 if (opt
[2]) OutputFileName
= opt
+ 2;
1233 if (opt
[2]) Separator
= opt
+ 2;
1234 else Separator
= NULL
;
1237 if (opt
[2]) add_object_extension( opt
+ 2 );
1240 fprintf( stderr
, "Unknown option '%s'\n%s", opt
, Usage
);
1246 /*******************************************************************
1249 int main( int argc
, char *argv
[] )
1251 struct incl_file
*pFile
;
1252 struct incl_path
*path
, *next
;
1258 if (argv
[i
][0] == '-')
1260 parse_option( argv
[i
] );
1261 for (j
= i
; j
< argc
; j
++) argv
[j
] = argv
[j
+1];
1267 /* ignore redundant source paths */
1268 if (src_dir
&& !strcmp( src_dir
, "." )) src_dir
= NULL
;
1269 if (top_src_dir
&& top_obj_dir
&& !strcmp( top_src_dir
, top_obj_dir
)) top_src_dir
= NULL
;
1271 /* set the default extension list for object files */
1272 if (list_empty( &object_extensions
))
1273 add_object_extension( "o" );
1275 /* get rid of absolute paths that don't point into the source dir */
1276 LIST_FOR_EACH_ENTRY_SAFE( path
, next
, &paths
, struct incl_path
, entry
)
1278 if (path
->name
[0] != '/') continue;
1281 if (!strncmp( path
->name
, top_src_dir
, strlen(top_src_dir
) ) &&
1282 path
->name
[strlen(top_src_dir
)] == '/') continue;
1284 list_remove( &path
->entry
);
1288 for (i
= 1; i
< argc
; i
++) add_src_file( argv
[i
] );
1290 LIST_FOR_EACH_ENTRY( pFile
, &includes
, struct incl_file
, entry
) parse_file( pFile
, 0 );
1291 output_dependencies();