2 * Copyright (c) 1994 University of Maryland
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of U.M. not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission. U.M. makes no representations about the
12 * suitability of this software for any purpose. It is provided "as is"
13 * without express or implied warranty.
15 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
17 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Author: James da Silva, Systems Design and Analysis Group
23 * Computer Science Department
24 * University of Maryland at College Park
27 * ========================================================================
30 * Generates a Makefile and main C file for a crunched executable,
31 * from specs given in a .conf file.
34 #include <sys/param.h>
45 #define CRUNCH_VERSION "0.2"
47 #define MAXLINELEN 16384
48 #define MAXFIELDS 2048
51 /* internal representation of conf file: */
53 /* simple lists of strings suffice for most parms */
55 typedef struct strlst
{
60 /* progs have structure, each field can be set with "special" or calculated */
63 struct prog
*next
; /* link field */
64 char *name
; /* program name */
65 char *ident
; /* C identifier for the program name */
69 char *objvar
; /* Makefile variable to replace OBJS */
70 strlst_t
*objs
, *objpaths
;
82 strlst_t
*buildopts
= NULL
;
83 strlst_t
*srcdirs
= NULL
;
84 strlst_t
*libs
= NULL
;
85 strlst_t
*libs_so
= NULL
;
88 char confname
[MAXPATHLEN
], infilename
[MAXPATHLEN
];
89 char outmkname
[MAXPATHLEN
], outcfname
[MAXPATHLEN
], execfname
[MAXPATHLEN
];
90 char tempfname
[MAXPATHLEN
], cachename
[MAXPATHLEN
], curfilename
[MAXPATHLEN
];
91 char outhdrname
[MAXPATHLEN
] ; /* user-supplied header for *.mk */
92 char *objprefix
; /* where are the objects ? */
97 int verbose
, readcache
; /* options */
99 int makeobj
= 0; /* add 'make obj' rules to the makefile */
103 /* general library routines */
105 void status(const char *str
);
106 void out_of_memory(void);
107 void add_string(strlst_t
**listp
, char *str
);
108 int is_dir(const char *pathname
);
109 int is_nonempty_file(const char *pathname
);
110 int subtract_strlst(strlst_t
**lista
, strlst_t
**listb
);
111 int in_list(strlst_t
**listp
, char *str
);
113 /* helper routines for main() */
116 void parse_conf_file(void);
117 void gen_outputs(void);
119 extern char *crunched_skel
[];
123 main(int argc
, char **argv
)
130 *outmkname
= *outcfname
= *execfname
= '\0';
132 path_make
= getenv("MAKE");
133 if (path_make
== NULL
|| *path_make
== '\0')
136 p
= getenv("MAKEOBJDIRPREFIX");
137 if (p
== NULL
|| *p
== '\0')
138 objprefix
= "/usr/obj"; /* default */
140 if ((objprefix
= strdup(p
)) == NULL
)
143 while((optc
= getopt(argc
, argv
, "lh:m:c:e:p:foq")) != -1) {
156 strlcpy(outmkname
, optarg
, sizeof(outmkname
));
159 if ((objprefix
= strdup(optarg
)) == NULL
)
164 strlcpy(outhdrname
, optarg
, sizeof(outhdrname
));
167 strlcpy(outcfname
, optarg
, sizeof(outcfname
));
170 strlcpy(execfname
, optarg
, sizeof(execfname
));
194 strlcpy(infilename
, argv
[0], sizeof(infilename
));
196 /* confname = `basename infilename .conf` */
198 if ((p
=strrchr(infilename
, '/')) != NULL
)
199 strlcpy(confname
, p
+ 1, sizeof(confname
));
201 strlcpy(confname
, infilename
, sizeof(confname
));
203 if ((p
=strrchr(confname
, '.')) != NULL
&& !strcmp(p
, ".conf"))
207 snprintf(outmkname
, sizeof(outmkname
), "%s.mk", confname
);
209 snprintf(outcfname
, sizeof(outcfname
), "%s.c", confname
);
211 snprintf(execfname
, sizeof(execfname
), "%s", confname
);
213 snprintf(cachename
, sizeof(cachename
), "%s.cache", confname
);
214 snprintf(tempfname
, sizeof(tempfname
), "%s/crunchgen_%sXXXXXX",
215 getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP
, confname
);
230 fprintf(stderr
, "%s%s\n\t%s%s\n", "usage: crunchgen [-foq] ",
231 "[-h <makefile-header-name>] [-m <makefile>]",
232 "[-p <obj-prefix>] [-c <c-file-name>] [-e <exec-file>] ",
239 * ========================================================================
240 * parse_conf_file subsystem
244 /* helper routines for parse_conf_file */
246 void parse_one_file(char *filename
);
247 void parse_line(char *pline
, int *fc
, char **fv
, int nf
);
248 void add_srcdirs(int argc
, char **argv
);
249 void add_progs(int argc
, char **argv
);
250 void add_link(int argc
, char **argv
);
251 void add_libs(int argc
, char **argv
);
252 void add_libs_so(int argc
, char **argv
);
253 void add_buildopts(int argc
, char **argv
);
254 void add_special(int argc
, char **argv
);
256 prog_t
*find_prog(char *str
);
257 void add_prog(char *progname
);
261 parse_conf_file(void)
263 if (!is_nonempty_file(infilename
))
264 errx(1, "fatal: input file \"%s\" not found", infilename
);
266 parse_one_file(infilename
);
267 if (readcache
&& is_nonempty_file(cachename
)) {
269 parse_one_file(cachename
);
275 parse_one_file(char *filename
)
277 char *fieldv
[MAXFIELDS
];
279 void (*f
)(int c
, char **v
);
281 char line
[MAXLINELEN
];
283 snprintf(line
, sizeof(line
), "reading %s", filename
);
285 strlcpy(curfilename
, filename
, sizeof(curfilename
));
287 if ((cf
= fopen(curfilename
, "r")) == NULL
) {
288 warn("%s", curfilename
);
294 while (fgets(line
, MAXLINELEN
, cf
) != NULL
) {
296 parse_line(line
, &fieldc
, fieldv
, MAXFIELDS
);
301 if (!strcmp(fieldv
[0], "srcdirs"))
303 else if(!strcmp(fieldv
[0], "progs"))
305 else if(!strcmp(fieldv
[0], "ln"))
307 else if(!strcmp(fieldv
[0], "libs"))
309 else if(!strcmp(fieldv
[0], "libs_so"))
311 else if(!strcmp(fieldv
[0], "buildopts"))
313 else if(!strcmp(fieldv
[0], "special"))
316 warnx("%s:%d: skipping unknown command `%s'",
317 curfilename
, linenum
, fieldv
[0]);
323 warnx("%s:%d: %s %s",
324 curfilename
, linenum
, fieldv
[0],
325 "command needs at least 1 argument, skipping");
334 warn("%s", curfilename
);
342 parse_line(char *pline
, int *fc
, char **fv
, int nf
)
350 while (isspace((unsigned char)*p
))
353 if (*p
== '\0' || *p
== '#')
359 while (*p
&& !isspace((unsigned char)*p
) && *p
!= '#')
362 if (*p
== '\0' || *p
== '#')
369 *p
= '\0'; /* needed for '#' case */
374 add_srcdirs(int argc
, char **argv
)
378 for (i
= 1; i
< argc
; i
++) {
380 add_string(&srcdirs
, argv
[i
]);
382 warnx("%s:%d: `%s' is not a directory, skipping it",
383 curfilename
, linenum
, argv
[i
]);
391 add_progs(int argc
, char **argv
)
395 for (i
= 1; i
< argc
; i
++)
401 add_prog(char *progname
)
405 /* add to end, but be smart about dups */
407 for (p1
= NULL
, p2
= progs
; p2
!= NULL
; p1
= p2
, p2
= p2
->next
)
408 if (!strcmp(p2
->name
, progname
))
411 p2
= malloc(sizeof(prog_t
));
413 memset(p2
, 0, sizeof(prog_t
));
414 p2
->name
= strdup(progname
);
416 if (!p2
|| !p2
->name
)
427 p2
->realsrcdir
= NULL
;
434 p2
->buildopts
= NULL
;
438 printf("%s\n",progname
);
443 add_link(int argc
, char **argv
)
446 prog_t
*p
= find_prog(argv
[1]);
449 warnx("%s:%d: no prog %s previously declared, skipping link",
450 curfilename
, linenum
, argv
[1]);
455 for (i
= 2; i
< argc
; i
++) {
457 printf("%s\n",argv
[i
]);
459 add_string(&p
->links
, argv
[i
]);
465 add_libs(int argc
, char **argv
)
469 for(i
= 1; i
< argc
; i
++) {
470 add_string(&libs
, argv
[i
]);
471 if ( in_list(&libs_so
, argv
[i
]) )
473 "library `%s' specified as dynamic earlier",
474 curfilename
, linenum
, argv
[i
]);
480 add_libs_so(int argc
, char **argv
)
484 for(i
= 1; i
< argc
; i
++) {
485 add_string(&libs_so
, argv
[i
]);
486 if ( in_list(&libs
, argv
[i
]) )
488 "library `%s' specified as static earlier",
489 curfilename
, linenum
, argv
[i
]);
495 add_buildopts(int argc
, char **argv
)
499 for (i
= 1; i
< argc
; i
++)
500 add_string(&buildopts
, argv
[i
]);
505 add_special(int argc
, char **argv
)
508 prog_t
*p
= find_prog(argv
[1]);
514 warnx("%s:%d: no prog %s previously declared, skipping special",
515 curfilename
, linenum
, argv
[1]);
520 if (!strcmp(argv
[2], "ident")) {
523 if ((p
->ident
= strdup(argv
[3])) == NULL
)
525 } else if (!strcmp(argv
[2], "srcdir")) {
528 if ((p
->srcdir
= strdup(argv
[3])) == NULL
)
530 } else if (!strcmp(argv
[2], "objdir")) {
533 if((p
->objdir
= strdup(argv
[3])) == NULL
)
535 } else if (!strcmp(argv
[2], "objs")) {
537 for (i
= 3; i
< argc
; i
++)
538 add_string(&p
->objs
, argv
[i
]);
539 } else if (!strcmp(argv
[2], "objpaths")) {
541 for (i
= 3; i
< argc
; i
++)
542 add_string(&p
->objpaths
, argv
[i
]);
543 } else if (!strcmp(argv
[2], "keep")) {
545 for(i
= 3; i
< argc
; i
++)
546 add_string(&p
->keeplist
, argv
[i
]);
547 } else if (!strcmp(argv
[2], "objvar")) {
550 if ((p
->objvar
= strdup(argv
[3])) == NULL
)
552 } else if (!strcmp(argv
[2], "buildopts")) {
554 for (i
= 3; i
< argc
; i
++)
555 add_string(&p
->buildopts
, argv
[i
]);
556 } else if (!strcmp(argv
[2], "lib")) {
557 for (i
= 3; i
< argc
; i
++)
558 add_string(&p
->libs
, argv
[i
]);
560 warnx("%s:%d: bad parameter name `%s', skipping line",
561 curfilename
, linenum
, argv
[2]);
567 warnx("%s:%d: too %s arguments, expected \"special %s %s <string>\"",
568 curfilename
, linenum
, argc
< 4? "few" : "many", argv
[1], argv
[2]);
573 prog_t
*find_prog(char *str
)
577 for (p
= progs
; p
!= NULL
; p
= p
->next
)
578 if (!strcmp(p
->name
, str
))
586 * ========================================================================
587 * gen_outputs subsystem
591 /* helper subroutines */
593 void remove_error_progs(void);
594 void fillin_program(prog_t
*p
);
595 void gen_specials_cache(void);
596 void gen_output_makefile(void);
597 void gen_output_cfile(void);
599 void fillin_program_objs(prog_t
*p
, char *path
);
600 void top_makefile_rules(FILE *outmk
);
601 void prog_makefile_rules(FILE *outmk
, prog_t
*p
);
602 void output_strlst(FILE *outf
, strlst_t
*lst
);
603 char *genident(char *str
);
604 char *dir_search(char *progname
);
612 for (p
= progs
; p
!= NULL
; p
= p
->next
)
615 remove_error_progs();
616 gen_specials_cache();
618 gen_output_makefile();
621 "Run \"%s -f %s\" to build crunched binary.\n",
622 path_make
, outmkname
);
626 * run the makefile for the program to find which objects are necessary
629 fillin_program(prog_t
*p
)
631 char path
[MAXPATHLEN
];
632 char line
[MAXLINELEN
];
635 snprintf(line
, MAXLINELEN
, "filling in parms for %s", p
->name
);
639 p
->ident
= genident(p
->name
);
641 /* look for the source directory if one wasn't specified by a special */
643 p
->srcdir
= dir_search(p
->name
);
646 /* Determine the actual srcdir (maybe symlinked). */
648 snprintf(line
, MAXLINELEN
, "cd %s && echo -n `/bin/pwd`",
652 errx(1, "Can't execute: %s\n", line
);
655 fgets(path
, sizeof path
, f
);
657 errx(1, "Can't execute: %s\n", line
);
660 errx(1, "Can't perform pwd on: %s\n", p
->srcdir
);
662 p
->realsrcdir
= strdup(path
);
665 /* Unless the option to make object files was specified the
666 * the objects will be built in the source directory unless
667 * an object directory already exists.
669 if (!makeobj
&& !p
->objdir
&& p
->srcdir
) {
670 snprintf(line
, sizeof line
, "%s/%s", objprefix
, p
->realsrcdir
);
672 if ((p
->objdir
= strdup(line
)) == NULL
)
675 p
->objdir
= p
->realsrcdir
;
679 * XXX look for a Makefile.{name} in local directory first.
680 * This lets us override the original Makefile.
682 snprintf(path
, sizeof(path
), "Makefile.%s", p
->name
);
683 if (is_nonempty_file(path
)) {
684 snprintf(line
, MAXLINELEN
, "Using %s for %s", path
, p
->name
);
688 snprintf(path
, sizeof(path
), "%s/Makefile", p
->srcdir
);
689 if (!p
->objs
&& p
->srcdir
&& is_nonempty_file(path
))
690 fillin_program_objs(p
, path
);
692 if (!p
->srcdir
&& !p
->objdir
&& verbose
)
694 "warning: could not find source directory",
695 infilename
, p
->name
);
696 if (!p
->objs
&& verbose
)
697 warnx("%s: %s: warning: could not find any .o files",
698 infilename
, p
->name
);
700 if ((!p
->srcdir
|| !p
->objdir
) && !p
->objs
)
705 fillin_program_objs(prog_t
*p
, char *path
)
712 char line
[MAXLINELEN
];
714 /* discover the objs from the srcdir Makefile */
716 if ((fd
= mkstemp(tempfname
)) == -1) {
720 if ((f
= fdopen(fd
, "w")) == NULL
) {
721 warn("%s", tempfname
);
729 * XXX include outhdrname (e.g. to contain Make variables)
731 if (outhdrname
[0] != '\0')
732 fprintf(f
, ".include \"%s\"\n", outhdrname
);
733 fprintf(f
, ".include \"%s\"\n", path
);
734 fprintf(f
, ".POSIX:\n");
736 fprintf(f
, "BUILDOPTS+=");
737 output_strlst(f
, buildopts
);
739 fprintf(f
, ".if defined(PROG)\n");
740 fprintf(f
, "%s?=${PROG}.o\n", objvar
);
741 fprintf(f
, ".endif\n");
742 fprintf(f
, "loop:\n\t@echo 'OBJS= '${%s}\n", objvar
);
744 fprintf(f
, "crunchgen_objs:\n"
745 "\t@cd %s && %s -f %s $(BUILDOPTS) $(%s_OPTS)",
746 p
->srcdir
, path_make
, tempfname
, p
->ident
);
747 for (s
= p
->buildopts
; s
!= NULL
; s
= s
->next
)
748 fprintf(f
, " %s", s
->str
);
749 fprintf(f
, " loop\n");
753 snprintf(line
, MAXLINELEN
, "cd %s && %s -f %s -B crunchgen_objs",
754 p
->srcdir
, path_make
, tempfname
);
755 if ((f
= popen(line
, "r")) == NULL
) {
756 warn("submake pipe");
761 while(fgets(line
, MAXLINELEN
, f
)) {
762 if (strncmp(line
, "OBJS= ", 6)) {
763 warnx("make error: %s", line
);
769 while (isspace((unsigned char)*cp
))
774 while (*cp
&& !isspace((unsigned char)*cp
))
778 add_string(&p
->objs
, obj
);
779 while (isspace((unsigned char)*cp
))
784 if ((rc
=pclose(f
)) != 0) {
785 warnx("make error: make returned %d", rc
);
793 remove_error_progs(void)
797 p1
= NULL
; p2
= progs
;
800 p1
= p2
, p2
= p2
->next
;
802 /* delete it from linked list */
803 warnx("%s: %s: ignoring program because of errors",
804 infilename
, p2
->name
);
815 gen_specials_cache(void)
819 char line
[MAXLINELEN
];
821 snprintf(line
, MAXLINELEN
, "generating %s", cachename
);
824 if ((cachef
= fopen(cachename
, "w")) == NULL
) {
825 warn("%s", cachename
);
830 fprintf(cachef
, "# %s - parm cache generated from %s by crunchgen "
832 cachename
, infilename
, CRUNCH_VERSION
);
834 for (p
= progs
; p
!= NULL
; p
= p
->next
) {
835 fprintf(cachef
, "\n");
837 fprintf(cachef
, "special %s srcdir %s\n",
840 fprintf(cachef
, "special %s objdir %s\n",
843 fprintf(cachef
, "special %s objs", p
->name
);
844 output_strlst(cachef
, p
->objs
);
847 fprintf(cachef
, "special %s objpaths", p
->name
);
848 output_strlst(cachef
, p
->objpaths
);
856 gen_output_makefile(void)
860 char line
[MAXLINELEN
];
862 snprintf(line
, MAXLINELEN
, "generating %s", outmkname
);
865 if ((outmk
= fopen(outmkname
, "w")) == NULL
) {
866 warn("%s", outmkname
);
871 fprintf(outmk
, "# %s - generated from %s by crunchgen %s\n\n",
872 outmkname
, infilename
, CRUNCH_VERSION
);
874 if (outhdrname
[0] != '\0')
875 fprintf(outmk
, ".include \"%s\"\n", outhdrname
);
877 top_makefile_rules(outmk
);
878 for (p
= progs
; p
!= NULL
; p
= p
->next
)
879 prog_makefile_rules(outmk
, p
);
881 fprintf(outmk
, "\n# ========\n");
887 gen_output_cfile(void)
893 char line
[MAXLINELEN
];
895 snprintf(line
, MAXLINELEN
, "generating %s", outcfname
);
898 if((outcf
= fopen(outcfname
, "w")) == NULL
) {
899 warn("%s", outcfname
);
905 "/* %s - generated from %s by crunchgen %s */\n",
906 outcfname
, infilename
, CRUNCH_VERSION
);
908 fprintf(outcf
, "#define EXECNAME \"%s\"\n", execfname
);
909 for (cp
= crunched_skel
; *cp
!= NULL
; cp
++)
910 fprintf(outcf
, "%s\n", *cp
);
912 for (p
= progs
; p
!= NULL
; p
= p
->next
)
913 fprintf(outcf
, "extern int _crunched_%s_stub();\n", p
->ident
);
915 fprintf(outcf
, "\nstruct stub entry_points[] = {\n");
916 for (p
= progs
; p
!= NULL
; p
= p
->next
) {
917 fprintf(outcf
, "\t{ \"%s\", _crunched_%s_stub },\n",
919 for (s
= p
->links
; s
!= NULL
; s
= s
->next
)
920 fprintf(outcf
, "\t{ \"%s\", _crunched_%s_stub },\n",
924 fprintf(outcf
, "\t{ EXECNAME, crunched_main },\n");
925 fprintf(outcf
, "\t{ NULL, NULL }\n};\n");
930 char *genident(char *str
)
935 * generates a Makefile/C identifier from a program name,
936 * mapping '-' to '_' and ignoring all other non-identifier
937 * characters. This leads to programs named "foo.bar" and
938 * "foobar" to map to the same identifier.
941 if ((n
= strdup(str
)) == NULL
)
943 for (d
= s
= n
; *s
!= '\0'; s
++) {
946 else if (*s
== '_' || isalnum((unsigned char)*s
))
954 char *dir_search(char *progname
)
956 char path
[MAXPATHLEN
];
960 for (dir
= srcdirs
; dir
!= NULL
; dir
= dir
->next
) {
961 snprintf(path
, MAXPATHLEN
, "%s/%s", dir
->str
, progname
);
965 if ((srcdir
= strdup(path
)) == NULL
)
975 top_makefile_rules(FILE *outmk
)
979 fprintf(outmk
, "LD?= ld\n");
980 if ( subtract_strlst(&libs
, &libs_so
) )
981 fprintf(outmk
, "# NOTE: Some LIBS declarations below overridden by LIBS_SO\n");
983 fprintf(outmk
, "LIBS+=");
984 output_strlst(outmk
, libs
);
986 fprintf(outmk
, "LIBS_SO+=");
987 output_strlst(outmk
, libs_so
);
990 fprintf(outmk
, "MAKEOBJDIRPREFIX?=%s\n", objprefix
);
991 fprintf(outmk
, "MAKEENV=env MAKEOBJDIRPREFIX=$(MAKEOBJDIRPREFIX)\n");
992 fprintf(outmk
, "CRUNCHMAKE=$(MAKEENV) $(MAKE)\n");
994 fprintf(outmk
, "CRUNCHMAKE=$(MAKE)\n");
998 fprintf(outmk
, "BUILDOPTS+=");
999 output_strlst(outmk
, buildopts
);
1002 fprintf(outmk
, "CRUNCHED_OBJS=");
1003 for (p
= progs
; p
!= NULL
; p
= p
->next
)
1004 fprintf(outmk
, " %s.lo", p
->name
);
1005 fprintf(outmk
, "\n");
1007 fprintf(outmk
, "SUBMAKE_TARGETS=");
1008 for (p
= progs
; p
!= NULL
; p
= p
->next
)
1009 fprintf(outmk
, " %s_make", p
->ident
);
1010 fprintf(outmk
, "\nSUBCLEAN_TARGETS=");
1011 for (p
= progs
; p
!= NULL
; p
= p
->next
)
1012 fprintf(outmk
, " %s_clean", p
->ident
);
1013 fprintf(outmk
, "\n\n");
1015 fprintf(outmk
, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n");
1016 fprintf(outmk
, "exe: %s\n", execfname
);
1017 fprintf(outmk
, "%s: %s.o $(CRUNCHED_OBJS) $(SUBMAKE_TARGETS)\n", execfname
, execfname
);
1018 fprintf(outmk
, ".if defined(LIBS_SO) && !empty(LIBS_SO)\n");
1019 fprintf(outmk
, "\t$(CC) -o %s %s.o $(CRUNCHED_OBJS) \\\n",
1020 execfname
, execfname
);
1021 fprintf(outmk
, "\t\t-Xlinker -Bstatic $(LIBS) \\\n");
1022 fprintf(outmk
, "\t\t-Xlinker -Bdynamic $(LIBS_SO)\n");
1023 fprintf(outmk
, ".else\n");
1024 fprintf(outmk
, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n",
1025 execfname
, execfname
);
1026 fprintf(outmk
, ".endif\n");
1027 fprintf(outmk
, "\tstrip %s\n", execfname
);
1028 fprintf(outmk
, "realclean: clean subclean\n");
1029 fprintf(outmk
, "clean:\n\trm -f %s *.lo *.o *_stub.c\n", execfname
);
1030 fprintf(outmk
, "subclean: $(SUBCLEAN_TARGETS)\n");
1035 prog_makefile_rules(FILE *outmk
, prog_t
*p
)
1039 fprintf(outmk
, "\n# -------- %s\n\n", p
->name
);
1041 fprintf(outmk
, "%s_OBJDIR=", p
->ident
);
1043 fprintf(outmk
, "%s", p
->objdir
);
1045 fprintf(outmk
, "$(MAKEOBJDIRPREFIX)/$(%s_REALSRCDIR)\n",
1047 fprintf(outmk
, "\n");
1049 fprintf(outmk
, "%s_OBJPATHS=", p
->ident
);
1051 output_strlst(outmk
, p
->objpaths
);
1053 for (lst
= p
->objs
; lst
!= NULL
; lst
= lst
->next
) {
1054 fprintf(outmk
, " $(%s_OBJDIR)/%s", p
->ident
, lst
->str
);
1056 fprintf(outmk
, "\n");
1058 fprintf(outmk
, "$(%s_OBJPATHS): .NOMETA\n", p
->ident
);
1060 if (p
->srcdir
&& p
->objs
) {
1061 fprintf(outmk
, "%s_SRCDIR=%s\n", p
->ident
, p
->srcdir
);
1062 fprintf(outmk
, "%s_REALSRCDIR=%s\n", p
->ident
, p
->realsrcdir
);
1064 fprintf(outmk
, "%s_OBJS=", p
->ident
);
1065 output_strlst(outmk
, p
->objs
);
1066 if (p
->buildopts
!= NULL
) {
1067 fprintf(outmk
, "%s_OPTS+=", p
->ident
);
1068 output_strlst(outmk
, p
->buildopts
);
1071 fprintf(outmk
, "$(%s_OBJPATHS): %s_make\n\n", p
->ident
, p
->ident
);
1073 fprintf(outmk
, "%s_make:\n", p
->ident
);
1074 fprintf(outmk
, "\t(cd $(%s_SRCDIR) && ", p
->ident
);
1076 fprintf(outmk
, "$(CRUNCHMAKE) obj && ");
1077 fprintf(outmk
, "\\\n");
1078 fprintf(outmk
, "\t\t$(CRUNCHMAKE) $(BUILDOPTS) $(%s_OPTS) depend &&",
1080 fprintf(outmk
, "\\\n");
1081 fprintf(outmk
, "\t\t$(CRUNCHMAKE) $(BUILDOPTS) $(%s_OPTS) "
1083 p
->ident
, p
->ident
);
1084 fprintf(outmk
, "\n");
1085 fprintf(outmk
, "%s_clean:\n", p
->ident
);
1086 fprintf(outmk
, "\t(cd $(%s_SRCDIR) && $(CRUNCHMAKE) $(BUILDOPTS) clean cleandepend)\n\n",
1089 fprintf(outmk
, "%s_make:\n", p
->ident
);
1090 fprintf(outmk
, "\t@echo \"** cannot make objs for %s\"\n\n",
1095 fprintf(outmk
, "%s_LIBS=", p
->ident
);
1096 output_strlst(outmk
, p
->libs
);
1099 fprintf(outmk
, "%s_stub.c:\n", p
->name
);
1100 fprintf(outmk
, "\techo \""
1101 "extern int main(int, char **, char **); "
1102 "int _crunched_%s_stub(int argc, char **argv, char **envp)"
1103 "{return main(argc,argv,envp);}\" >%s_stub.c\n",
1105 fprintf(outmk
, "%s.lo: %s_stub.o $(%s_OBJPATHS)",
1106 p
->name
, p
->name
, p
->ident
);
1108 fprintf(outmk
, " $(%s_LIBS)", p
->ident
);
1110 fprintf(outmk
, "\n");
1111 fprintf(outmk
, "\t$(CC) -nostdlib -Wl,-dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)",
1112 p
->name
, p
->name
, p
->ident
);
1114 fprintf(outmk
, " $(%s_LIBS)", p
->ident
);
1115 fprintf(outmk
, "\n");
1116 fprintf(outmk
, "\tcrunchide -k _crunched_%s_stub ", p
->ident
);
1117 for (lst
= p
->keeplist
; lst
!= NULL
; lst
= lst
->next
)
1118 fprintf(outmk
, "-k %s ", lst
->str
);
1119 fprintf(outmk
, "%s.lo\n", p
->name
);
1123 output_strlst(FILE *outf
, strlst_t
*lst
)
1125 for (; lst
!= NULL
; lst
= lst
->next
)
1126 if ( strlen(lst
->str
) )
1127 fprintf(outf
, " %s", lst
->str
);
1128 fprintf(outf
, "\n");
1133 * ========================================================================
1134 * general library routines
1139 status(const char *str
)
1141 static int lastlen
= 0;
1148 spaces
= lastlen
- len
;
1152 fprintf(stderr
, " [%s]%*.*s\r", str
, spaces
, spaces
, " ");
1161 err(1, "%s: %d: out of memory, stopping", infilename
, linenum
);
1166 add_string(strlst_t
**listp
, char *str
)
1170 /* add to end, but be smart about dups */
1172 for (p1
= NULL
, p2
= *listp
; p2
!= NULL
; p1
= p2
, p2
= p2
->next
)
1173 if (!strcmp(p2
->str
, str
))
1176 p2
= malloc(sizeof(strlst_t
));
1179 p2
->str
= strdup(str
);
1181 if (!p2
|| !p2
->str
)
1191 subtract_strlst(strlst_t
**lista
, strlst_t
**listb
)
1193 int subtract_count
= 0;
1195 for (p1
= *listb
; p1
!= NULL
; p1
= p1
->next
)
1196 if ( in_list(lista
, p1
->str
) ) {
1197 warnx("Will compile library `%s' dynamically", p1
->str
);
1198 strcat(p1
->str
, "");
1201 return subtract_count
;
1205 in_list(strlst_t
**listp
, char *str
)
1208 for (p1
= *listp
; p1
!= NULL
; p1
= p1
->next
)
1209 if (!strcmp(p1
->str
, str
))
1215 is_dir(const char *pathname
)
1219 if (stat(pathname
, &buf
) == -1)
1222 return S_ISDIR(buf
.st_mode
);
1226 is_nonempty_file(const char *pathname
)
1230 if (stat(pathname
, &buf
) == -1)
1233 return S_ISREG(buf
.st_mode
) && buf
.st_size
> 0;