2 * Copyright (C) 2000-2006 Erik Edelmann <Erik.Edelmann@iki.fi>
4 * This program is free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License version 2 as published by the Free Software
9 * This program is distributed in the hope that it will be
10 * useful, but WITHOUT ANY WARRANTY; without even the implied
11 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 * PURPOSE. See the GNU General Public License for more
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the Free
17 * Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307 USA
27 #include <sys/types.h>
31 #include "errormesg.h"
32 #include "modfile_name.h"
41 /* File Specific Rules */
47 static int fsr_strcmp(const char *file
, const Fsr
*rule
)
49 return fnmatch(rule
->file
, file
, FNM_PATHNAME
);
53 static const char helpstring
[] =
54 "\nUsage: makedepf90 [options] sourcefile(s)\n\n"
56 "\n-h\tprint this message to stdout and quit.\n"
57 "\n-V\tprint version and copyright information to stdout and quit.\n"
58 "\n-W\tprint warning messages about missing includes/modules.\n"
59 "\n-m fmt\tWrite mod-file names using the format 'fmt'.\n"
60 "\t'fmt' may contain any of the following modifiers:\n"
62 "\t '%f' for name of the source file (without suffix),\n"
63 "\t '%m' for 'modulename' (in lowercase)\n"
64 "\t '%M' for 'MODULENAME' (in uppercase).\n"
65 "\tDefault: \"%f.o\".\n"
66 "\n-u module\n\tIgnore modules named 'module'.\n"
67 "\n-d file\tMake all targets dependent on 'file'.\n"
68 "\n-r rule\tAdd 'rule' (indented by a tab) to all dependency lines,\n"
69 "\texcept lines given rule(s) with the -R option below.\n"
70 "\t'rule' may contain the modifiers:\n"
71 "\t '%f' for the name (without suffix) of the source file that\n"
72 "\t line was created for.\n"
74 "\n-R pattern rule\n\tAdd 'rule' (indented by a tab) to the dependency\n"
75 "\tline for files matching 'pattern', where 'pattern' is a\n"
76 "\t\"shell pattern\", i.e it may contain the wildcards\n"
77 "\t '*' for any number of any characters\n"
78 "\t '?' for any character\n"
79 "\t '[abc]' for any of 'a', 'b' or 'c'.\n"
80 "\n-fixed\tTreat all files as fixed format.\n"
81 "\n-free\tTreat all files as free format.\n"
82 "\n-o name\tCreate a dependency line + rule for linking the final\n"
83 "\texecutable 'name'.\n"
84 "\n-l rule\tUse 'rule' for linking the executable.\n"
85 "\tDefault: $(FC) -o $@ $(FFLAGS) $(LDFLAGS) $(FOBJ) $(LIBS)\n"
86 "\n-coco\tLook for coco set-files. Implies '-free'.\n"
87 "\n-D NAME\tDefine pre-processor symbol 'NAME'\n"
88 "\n-b PATH\tAssume object files are placed in PATH.\n"
89 "\n-nosrc\tRemove the explicit dependency on the source file\n"
90 "\n-I PATH1:PATH2:...\n\tSearch path(s) for source files\n"
91 "\n\nReport bugs to erik.edelmann@iki.fi\n";
94 static char ver
[]="makedepf90 version " VERSION
;
97 static const char license
[]=
98 "\nCopyright (C) 2000--2006 Erik Edelmann <Erik.Edelmann@iki.fi>\n"
100 "makedepf90 is free software; you can redistribute it and/or modify\n"
101 "it under the terms of the GNU General Public License version 2 as\n"
102 "published by the Free Software Foundation.\n"
104 "This program is distributed in the hope that it will be useful,\n"
105 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
106 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
107 "General Public License for more details.\n"
109 "You should have received a copy of the GNU General Public License\n"
110 "along with this program; if not, write to the Free Software Foundation,\n"
111 "Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.";
114 int main (int argc
, char **argv
)
120 List
*deplist
= NULL
; /* Dependencies */
121 List
*modlist
= NULL
; /* Defined modules */
122 List
*extradeps
= NULL
; /* "Extra" dependencies (given by the '-d' option */
123 List
*rules
= NULL
; /* List of rules to be added to all dependency lines */
124 List
*fspecrules
= NULL
; /* FileSpecific rules */
126 List
*macrolist
= NULL
; /* -D MACRO */
130 set_progname(argv
[0]);
133 printf ("%s", helpstring
);
137 /* Set a few option defaults */
138 options
.warn_missing
= false;
139 options
.modfile_fmt
= (char *)MODFILE_FMT_DEFAULT
;
140 options
.src_fmt
= SUFFIX
;
141 options
.create_obj
= false;
142 options
.exe_name
= NULL
;
143 options
.link_rule
= (char *)LINK_RULE_DEFAULT
;
144 options
.coco
= false;
145 options
.obj_dir_set
= false;
146 options
.obj_dir
= "";
147 options
.src_dep
= true;
148 options
.ignore_mods
= NULL
;
149 options
.src_path
= NULL
;
151 /* Parse command line arguments */
152 for (i
= 1; i
< argc
; i
++) {
153 if (strcmp(argv
[i
], "-h") == 0 || strcmp(argv
[i
], "--help") == 0) {
154 printf ("%s", helpstring
);
157 } else if (strcmp(argv
[i
], "-V") == 0
158 || strcmp(argv
[i
], "--version") == 0) {
160 printf("%s\n", license
);
163 } else if (strcmp(argv
[i
], "-W") == 0
164 || strcmp(argv
[i
], "-Wmissing") == 0) {
165 options
.warn_missing
= true;
167 } else if (strcmp(argv
[i
], "-Wconfused") == 0) {
168 options
.warn_confused
= true;
170 } else if (strncmp(argv
[i
], "-m", 2) == 0) {
171 if (strlen(argv
[i
]) == 2) {
172 if (i
== argc
-1) fatal_error("Option '-m' needs argument");
173 options
.modfile_fmt
= xstrdup(argv
[++i
]);
175 options
.modfile_fmt
= xstrdup(&(argv
[i
][2]));
177 } else if (strncmp (argv
[i
], "-u", 2) == 0) {
178 if (strlen(argv
[i
]) == 2) {
179 if (i
== argc
-1) fatal_error("Option '-u' needs argument");
180 s
= xstrdup(argv
[++i
]);
182 s
= xstrdup(&(argv
[i
][2]));
184 if (!list_find(options
.ignore_mods
, s
, COMP_FUN(&strcasecmp
)))
185 options
.ignore_mods
= list_prepend(options
.ignore_mods
, s
);
187 } else if (strcmp(argv
[i
], "-fixed") == 0) {
188 options
.src_fmt
= FIXED
;
190 } else if (strcmp(argv
[i
], "-free") == 0) {
191 options
.src_fmt
= FREE
;
193 } else if (strncmp(argv
[i
], "-d", 2) == 0) {
194 if (strlen(argv
[i
]) == 2) {
195 if (i
== argc
-1) fatal_error("Option '-d' needs argument");
196 s
= xstrdup(argv
[++i
]);
198 s
= xstrdup(&(argv
[i
][2]));
200 if (!list_find(extradeps
, s
, COMP_FUN(&strcasecmp
)))
201 extradeps
= list_prepend(extradeps
, s
);
203 } else if (strncmp(argv
[i
], "-r", 2) == 0) {
204 if (strlen(argv
[i
]) == 2) {
205 if (i
== argc
-1) fatal_error ("Option '-r' needs argument");
206 s
= xstrdup(argv
[++i
]);
208 s
= xstrdup(&(argv
[i
][2]));
210 if (!list_find(rules
, s
, COMP_FUN(&strcasecmp
)))
211 rules
= list_append(rules
, s
);
213 } else if (strncmp(argv
[i
], "-R", 2) == 0) {
215 h
= (Fsr
*) xmalloc(sizeof(Fsr
));
216 if (strlen(argv
[i
]) == 2) {
217 if (i
== argc
-1) fatal_error("Option '-R' needs 2 arguments");
218 h
->file
= xstrdup(argv
[++i
]);
220 h
->file
= xstrdup(&(argv
[i
][2]));
222 if (i
== argc
-1) fatal_error("Option '-R' needs 2 arguments");
223 h
->rule
= xstrdup (argv
[++i
]);
224 fspecrules
= list_append(fspecrules
, h
);
226 } else if (strncmp(argv
[i
], "-o", 2) == 0) {
227 options
.create_obj
= true;
228 if (strlen(argv
[i
]) == 2) {
229 if (i
== argc
-1) fatal_error("Option '-o' needs argument");
230 options
.exe_name
= xstrdup(argv
[++i
]);
232 options
.exe_name
= xstrdup(&(argv
[i
][2]));
234 } else if (strncmp(argv
[i
], "-l", 2) == 0) {
235 if (strlen(argv
[i
]) == 2) {
236 if (i
== argc
-1) fatal_error("Option '-l' needs argument");
237 options
.link_rule
= xstrdup(argv
[++i
]);
239 options
.link_rule
= xstrdup(&(argv
[i
][2]));
241 } else if (strcmp(argv
[i
], "-coco") == 0) {
243 options
.src_fmt
= FREE
;
245 } else if (strncmp(argv
[i
], "-D", 2) == 0) {
250 /* Copy the argument of -D (ignoring any '=definition') to a
251 * 'Macro' and add it to 'macrolist'. */
253 if (strlen(argv
[i
]) == 2) {
257 if (i
== argc
-1) fatal_error("Option '-D' needs argument");
260 eq
= strchr(argv
[i
], '=');
262 s
= xstrndup(argv
[i
], eq
- argv
[i
]);
264 s
= xstrdup(argv
[i
]);
266 macro_setname(mac
, s
);
268 eq
= strchr(&argv
[i
][2], '=');
270 s
= xstrndup(&argv
[i
][2], eq
- argv
[i
] - 2);
272 s
= xstrdup(&argv
[i
][2]);
274 macro_setname(mac
, s
);
276 if (!list_find(macrolist
, mac
, ¯ocmp
))
277 macrolist
= list_prepend(macrolist
, mac
);
279 } else if (strncmp(argv
[i
], "-b", 2) == 0) {
280 if (strlen(argv
[i
]) == 2) {
281 if (i
== argc
- 1) fatal_error("Option '-b' needs argument");
282 options
.obj_dir
= xstrdup(argv
[++i
]);
284 if (argv
[i
][2] == '=') {
285 options
.obj_dir
= xstrdup(&(argv
[i
][3]));
287 options
.obj_dir
= xstrdup(&(argv
[i
][2]));
289 n
= strlen(options
.obj_dir
);
290 if (n
> 0 && options
.obj_dir
[n
- 1] != '/') {
291 options
.obj_dir
= xrealloc(options
.obj_dir
, n
+2);
292 strcat(options
.obj_dir
, "/");
295 options
.obj_dir_set
= true;
297 } else if (strncmp(argv
[i
], "-I", 2) == 0) {
300 if (strlen(argv
[i
]) == 2) {
301 if (i
== argc
- 1) fatal_error("Option '-I' needs argument");
302 s
= xstrdup(argv
[++i
]);
304 if (argv
[i
][2] == '=' ) {
305 s
= xstrdup(&(argv
[i
][3]));
307 s
= xstrdup(&(argv
[i
][2]));
311 for(j
= 0;j
< n
; j
++){
312 if (s
[j
] == ' ' || s
[j
]==':') {
313 options
.src_path
= list_append(options
.src_path
,
314 xstrndup(s
+jp
, j
-jp
));
316 } else if (j
== n
-1) {
317 options
.src_path
= list_append(options
.src_path
,xstrdup(s
+jp
));
321 } else if (strcmp(argv
[i
], "-nosrc") == 0) {
322 options
.src_dep
= false;
325 * Add new options here
328 } else if (*argv
[i
] == '-') {
329 fatal_error("Unknown Option '%s'", argv
[i
]);
332 /* Gee, we got a filename! */
333 if (!list_find(files
, argv
[i
], COMP_FUN(&strcasecmp
)))
334 files
= list_prepend(files
, argv
[i
]);
338 /* Parse the files, creating target and dependency lists. */
339 for (h1
= files
; h1
; h1
= h1
->next
) {
342 dep
= dependency_new();
343 srcfile
= (char *)h1
->data
;
344 if (find_dep(srcfile
, dep
, &modlist
, macrolist
)) {
345 dep
->sourcefile
= srcfile
;
347 tmp
= replace_suffix(srcfile
, ".o");
348 if (!list_find(dep
->targets
, tmp
, COMP_FUN(&strcasecmp
)))
349 dep
->targets
= list_prepend(dep
->targets
, tmp
);
354 dep
->includes
= list_prepend(dep
->includes
, srcfile
);
360 setfile
= replace_suffix(srcfile
, ".set");
361 if (stat(setfile
, &blah
) == 0) {
362 if (!list_find(dep
->includes
,setfile
,COMP_FUN(&strcasecmp
)))
363 dep
->includes
= list_append(dep
->includes
, setfile
);
364 } else if (stat("coco.set", &blah
) == 0) {
366 setfile
= xstrdup("coco.set");
367 if (!list_find(dep
->includes
,setfile
,COMP_FUN(&strcasecmp
)))
368 dep
->includes
= list_append(dep
->includes
, setfile
);
373 deplist
= list_prepend(deplist
, dep
);
377 if (options
.create_obj
)
378 obj
= list_prepend(obj
, replace_suffix(srcfile
, ".o"));
381 /* Print FOBJ macro and linking dependecy-line + rule. */
382 if (options
.create_obj
) {
384 for (h1
= obj
; h1
; h1
= h1
->next
)
385 if (options
.obj_dir_set
)
386 printf("%s ", set_path(h1
->data
, options
.obj_dir
));
388 printf("%s ", (char *)h1
->data
);
389 printf("\n\n%s: $(FOBJ)\n\t%s\n\n", options
.exe_name
,options
.link_rule
);
392 /* Print the 'target: dependency' lists. */
393 for (h1
= deplist
; h1
; h1
= h1
->next
) {
396 dep
= (Dependency
*)h1
->data
;
398 /* If there are no dependencys, there is no need to output anything */
399 if (list_length(dep
->includes
) + list_length(dep
->modules
) == 0)
403 for (h2
= dep
->targets
; h2
; h2
= h2
->next
)
404 if (options
.obj_dir_set
)
405 printf("%s ", set_path(h2
->data
, options
.obj_dir
));
407 printf("%s ", (char *)h2
->data
);
412 for (h2
= dep
->includes
; h2
; h2
= h2
->next
)
413 printf("%s ", (char *)h2
->data
);
416 for (h2
= dep
->modules
; h2
; h2
= h2
->next
) {
418 s
= (char *)h2
->data
;
420 if (!(l
= list_find(modlist
, s
, &modstrcmp
))) {
421 /* Don't write *.mod-file to dependency list if its definition
423 if (options
.warn_missing
) warning("Module '%s' not found", s
);
426 mod
= (Module
*)l
->data
;
427 if (strcasecmp(mod
->sourcefile
, dep
->sourcefile
) == 0) {
428 /* Dont' write *.mod-file to the dependency list if it
429 * defined in the same file it is USEd from. */
431 if (options
.obj_dir_set
)
433 set_path(mod
->modfile_name
, options
.obj_dir
));
435 printf("%s ", mod
->modfile_name
);
441 /* Extra dependencies (given with the '-d' option */
442 for (h2
= extradeps
; h2
; h2
= h2
->next
)
443 printf("%s ", (char *)h2
->data
);
447 /* Print -R rules (if there are any) */
448 for (h2
= fspecrules
; h2
; h2
= h2
->next
) {
449 Fsr
*h
= (Fsr
*)h2
->data
;
451 if (fsr_strcmp(dep
->sourcefile
, h
) == 0) {
452 char *tmp
= expand_rule(h
->rule
, dep
->sourcefile
);
459 /* If the file wasn't given any rules by the -R option, print -r rules*/
461 for (h2
= rules
; h2
; h2
= h2
->next
) {
462 char *tmp
= expand_rule((char *)h2
->data
, dep
->sourcefile
);