1 /* $NetBSD: crunchgen.c,v 1.74 2008/10/19 22:10:05 apb Exp $ */
3 * Copyright (c) 1994 University of Maryland
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Author: James da Silva, Systems Design and Analysis Group
24 * Computer Science Department
25 * University of Maryland at College Park
28 * ========================================================================
31 * Generates a Makefile and main C file for a crunched executable,
32 * from specs given in a .conf file.
35 #if HAVE_NBTOOL_CONFIG_H
36 #include "nbtool_config.h"
39 #include <sys/cdefs.h>
41 __RCSID("$NetBSD: crunchgen.c,v 1.74 2008/10/19 22:10:05 apb Exp $");
53 #include <sys/types.h>
55 #include <sys/param.h>
56 #include <sys/utsname.h>
58 #define CRUNCH_VERSION "20050208"
60 #define MAXLINELEN 16384
61 #define MAXFIELDS 2048
63 /* internal representation of conf file: */
65 /* simple lists of strings suffice for most parms */
67 typedef struct strlst
{
72 /* progs have structure, each field can be set with "special" or calculated */
77 char *srcdir
, *objdir
;
78 strlst_t
*objs
, *objpaths
;
79 strlst_t
*links
, *keepsymbols
;
86 strlst_t
*srcdirs
= NULL
;
87 strlst_t
*libs
= NULL
;
88 strlst_t
*vars
= NULL
;
91 char line
[MAXLINELEN
];
93 char confname
[MAXPATHLEN
], infilename
[MAXPATHLEN
];
94 char outmkname
[MAXPATHLEN
], outcfname
[MAXPATHLEN
], execfname
[MAXPATHLEN
];
95 char cachename
[MAXPATHLEN
], curfilename
[MAXPATHLEN
];
96 char curdir
[MAXPATHLEN
];
97 char topdir
[MAXPATHLEN
];
98 char libdir
[MAXPATHLEN
] = "/usr/lib";
99 char dbg
[MAXPATHLEN
] = "-Os";
103 const char *pname
= "crunchgen";
105 int verbose
, readcache
, useobjs
, oneobj
; /* options */
108 char *makeobjdirprefix
;
112 /* general library routines */
114 void status(const char *str
);
115 void out_of_memory(void);
116 void add_string(strlst_t
**listp
, char *str
);
117 int is_dir(const char *pathname
);
118 int is_nonempty_file(const char *pathname
);
120 /* helper routines for main() */
123 void parse_conf_file(void);
124 void gen_outputs(void);
126 extern char *crunched_skel
[];
129 main(int argc
, char **argv
)
134 if ((makebin
= getenv("MAKE")) == NULL
)
135 makebin
= strdup("make");
137 if ((makeflags
= getenv("MAKEFLAGS")) == NULL
)
138 makeflags
= strdup("");
140 if ((machine
= getenv("MACHINE")) == NULL
) {
141 static struct utsname utsname
;
143 if (uname(&utsname
) == -1) {
147 machine
= utsname
.machine
;
149 makeobjdirprefix
= getenv("MAKEOBJDIRPREFIX");
154 *outmkname
= *outcfname
= *execfname
= '\0';
159 while ((optc
= getopt(argc
, argv
, "m:c:d:e:foqD:L:Ov:")) != -1) {
161 case 'f': readcache
= 0; break;
162 case 'q': verbose
= 0; break;
163 case 'O': oneobj
= 0; break;
164 case 'o': useobjs
= 1, oneobj
= 0; break;
166 case 'm': (void)estrlcpy(outmkname
, optarg
, sizeof(outmkname
)); break;
167 case 'c': (void)estrlcpy(outcfname
, optarg
, sizeof(outcfname
)); break;
168 case 'e': (void)estrlcpy(execfname
, optarg
, sizeof(execfname
)); break;
169 case 'd': (void)estrlcpy(dbg
, optarg
, sizeof(dbg
)); break;
171 case 'D': (void)estrlcpy(topdir
, optarg
, sizeof(topdir
)); break;
172 case 'L': (void)estrlcpy(libdir
, optarg
, sizeof(libdir
)); break;
173 case 'v': add_string(&vars
, optarg
); break;
190 (void)estrlcpy(infilename
, argv
[0], sizeof(infilename
));
191 getcwd(curdir
, MAXPATHLEN
);
193 /* confname = `basename infilename .conf` */
195 if ((p
= strrchr(infilename
, '/')) != NULL
)
196 (void)estrlcpy(confname
, p
+ 1, sizeof(confname
));
198 (void)estrlcpy(confname
, infilename
, sizeof(confname
));
199 if ((p
= strrchr(confname
, '.')) != NULL
&& !strcmp(p
, ".conf"))
203 (void)snprintf(outmkname
, sizeof(outmkname
), "%s.mk", confname
);
205 (void)snprintf(outcfname
, sizeof(outcfname
), "%s.c", confname
);
207 (void)snprintf(execfname
, sizeof(execfname
), "%s", confname
);
209 (void)snprintf(cachename
, sizeof(cachename
), "%s.cache", confname
);
222 "%s [-fOoq] [-c c-file-name] [-D src-root] [-d build-options]\n"
223 "\t [-e exec-file-name] [-L lib-dir] [-m makefile-name]\n"
224 "\t [-v var-spec] conf-file\n", pname
);
230 * ========================================================================
231 * parse_conf_file subsystem
235 /* helper routines for parse_conf_file */
237 void parse_one_file(char *filename
);
238 void parse_line(char *line
, int *fc
, char **fv
, int nf
);
239 void add_srcdirs(int argc
, char **argv
);
240 void add_progs(int argc
, char **argv
);
241 void add_link(int argc
, char **argv
);
242 void add_libs(int argc
, char **argv
);
243 void add_special(int argc
, char **argv
);
245 prog_t
*find_prog(char *str
);
246 void add_prog(char *progname
);
250 parse_conf_file(void)
252 if (!is_nonempty_file(infilename
)) {
253 fprintf(stderr
, "%s: fatal: input file \"%s\" not found.\n",
257 parse_one_file(infilename
);
258 if (readcache
&& is_nonempty_file(cachename
)) {
260 parse_one_file(cachename
);
266 parse_one_file(char *filename
)
268 char *fieldv
[MAXFIELDS
];
270 void (*f
)(int c
, char **v
);
273 (void)snprintf(line
, sizeof(line
), "reading %s", filename
);
275 (void)estrlcpy(curfilename
, filename
, sizeof(curfilename
));
277 if ((cf
= fopen(curfilename
, "r")) == NULL
) {
284 while (fgets(line
, MAXLINELEN
, cf
) != NULL
) {
286 parse_line(line
, &fieldc
, fieldv
, MAXFIELDS
);
289 if (!strcmp(fieldv
[0], "srcdirs")) f
= add_srcdirs
;
290 else if (!strcmp(fieldv
[0], "progs")) f
= add_progs
;
291 else if (!strcmp(fieldv
[0], "ln")) f
= add_link
;
292 else if (!strcmp(fieldv
[0], "libs")) f
= add_libs
;
293 else if (!strcmp(fieldv
[0], "special")) f
= add_special
;
295 fprintf(stderr
, "%s:%d: skipping unknown command `%s'.\n",
296 curfilename
, linenum
, fieldv
[0]);
302 "%s:%d: %s command needs at least 1 argument, skipping.\n",
303 curfilename
, linenum
, fieldv
[0]);
319 parse_line(char *pline
, int *fc
, char **fv
, int nf
)
326 while (isspace((unsigned char)*p
))
328 if (*p
== '\0' || *p
== '#')
333 while (*p
&& !isspace((unsigned char)*p
) && *p
!= '#')
335 if (*p
== '\0' || *p
== '#')
340 *p
= '\0'; /* needed for '#' case */
345 add_srcdirs(int argc
, char **argv
)
348 char tmppath
[MAXPATHLEN
];
350 for (i
= 1; i
< argc
; i
++) {
351 if (argv
[i
][0] == '/')
352 (void)estrlcpy(tmppath
, argv
[i
], sizeof(tmppath
));
354 if (topdir
[0] == '\0')
355 (void)estrlcpy(tmppath
, curdir
, sizeof(tmppath
));
357 (void)estrlcpy(tmppath
, topdir
, sizeof(tmppath
));
358 (void)estrlcat(tmppath
, "/", sizeof(tmppath
));
359 (void)estrlcat(tmppath
, argv
[i
], sizeof(tmppath
));
362 add_string(&srcdirs
, tmppath
);
364 fprintf(stderr
, "%s:%d: `%s' is not a directory, skipping it.\n",
365 curfilename
, linenum
, tmppath
);
373 add_progs(int argc
, char **argv
)
377 for (i
= 1; i
< argc
; i
++)
383 add_prog(char *progname
)
387 /* add to end, but be smart about dups */
389 for (p1
= NULL
, p2
= progs
; p2
!= NULL
; p1
= p2
, p2
= p2
->next
)
390 if (!strcmp(p2
->name
, progname
))
393 p2
= malloc(sizeof(prog_t
));
395 p2
->name
= strdup(progname
);
396 if (!p2
|| !p2
->name
)
405 p2
->ident
= p2
->srcdir
= p2
->objdir
= NULL
;
406 p2
->objs
= p2
->objpaths
= p2
->links
= p2
->keepsymbols
= NULL
;
412 add_link(int argc
, char **argv
)
415 prog_t
*p
= find_prog(argv
[1]);
419 "%s:%d: no prog %s previously declared, skipping link.\n",
420 curfilename
, linenum
, argv
[1]);
424 for (i
= 2; i
< argc
; i
++)
425 add_string(&p
->links
, argv
[i
]);
430 add_libs(int argc
, char **argv
)
434 for (i
= 1; i
< argc
; i
++)
435 add_string(&libs
, argv
[i
]);
440 add_special(int argc
, char **argv
)
443 prog_t
*p
= find_prog(argv
[1]);
449 "%s:%d: no prog %s previously declared, skipping special.\n",
450 curfilename
, linenum
, argv
[1]);
455 if (!strcmp(argv
[2], "ident")) {
458 if ((p
->ident
= strdup(argv
[3])) == NULL
)
463 if (!strcmp(argv
[2], "srcdir")) {
466 if (argv
[3][0] == '/') {
467 if ((p
->srcdir
= strdup(argv
[3])) == NULL
)
470 char tmppath
[MAXPATHLEN
];
471 if (topdir
[0] == '\0')
472 (void)estrlcpy(tmppath
, curdir
, sizeof(tmppath
));
474 (void)estrlcpy(tmppath
, topdir
, sizeof(tmppath
));
475 (void)estrlcat(tmppath
, "/", sizeof(tmppath
));
476 (void)estrlcat(tmppath
, argv
[3], sizeof(tmppath
));
477 if ((p
->srcdir
= strdup(tmppath
)) == NULL
)
483 if (!strcmp(argv
[2], "objdir")) {
486 if ((p
->objdir
= strdup(argv
[3])) == NULL
)
491 if (!strcmp(argv
[2], "objs")) {
493 for (i
= 3; i
< argc
; i
++)
494 add_string(&p
->objs
, argv
[i
]);
498 if (!strcmp(argv
[2], "objpaths")) {
500 for (i
= 3; i
< argc
; i
++)
501 add_string(&p
->objpaths
, argv
[i
]);
505 if (!strcmp(argv
[2], "keepsymbols")) {
506 for (i
= 3; i
< argc
; i
++)
507 add_string(&p
->keepsymbols
, argv
[i
]);
511 fprintf(stderr
, "%s:%d: bad parameter name `%s', skipping line.\n",
512 curfilename
, linenum
, argv
[2]);
518 "%s:%d: too %s arguments, expected \"special %s %s <string>\".\n",
519 curfilename
, linenum
, argc
< 4? "few" : "many", argv
[1], argv
[2]);
529 for (p
= progs
; p
!= NULL
; p
= p
->next
)
530 if (!strcmp(p
->name
, str
))
538 * ========================================================================
539 * gen_outputs subsystem
543 /* helper subroutines */
545 void remove_error_progs(void);
546 void fillin_program(prog_t
*p
);
547 void gen_specials_cache(void);
548 void gen_output_makefile(void);
549 void gen_output_cfile(void);
551 void fillin_program_objs(prog_t
*p
, char *path
);
552 void top_makefile_rules(FILE *outmk
);
553 void bottom_makefile_rules(FILE *outmk
);
554 void prog_makefile_rules(FILE *outmk
, prog_t
*p
);
555 void output_strlst(FILE *outf
, strlst_t
*lst
);
556 char *genident(char *str
);
557 char *dir_search(char *progname
);
565 for (p
= progs
; p
!= NULL
; p
= p
->next
)
568 remove_error_progs();
569 gen_specials_cache();
571 gen_output_makefile();
574 "Run \"make -f %s objs exe\" to build crunched binary.\n",
580 fillin_program(prog_t
*p
)
582 char path
[MAXPATHLEN
];
586 (void)snprintf(line
, sizeof(line
), "filling in parms for %s", p
->name
);
590 p
->ident
= genident(p
->name
);
592 srcparent
= dir_search(p
->name
);
594 (void)snprintf(path
, sizeof(path
), "%s/%s", srcparent
, p
->name
);
596 if (path
[0] == '/') {
597 if ((p
->srcdir
= strdup(path
)) == NULL
)
600 char tmppath
[MAXPATHLEN
];
601 if (topdir
[0] == '\0')
602 (void)estrlcpy(tmppath
, curdir
, sizeof(tmppath
));
604 (void)estrlcpy(tmppath
, topdir
, sizeof(tmppath
));
605 (void)estrlcat(tmppath
, "/", sizeof(tmppath
));
606 (void)estrlcat(tmppath
, path
, sizeof(tmppath
));
607 if ((p
->srcdir
= strdup(tmppath
)) == NULL
)
614 if (!p
->srcdir
&& verbose
)
615 fprintf(stderr
, "%s: %s: warning: could not find source directory.\n",
616 infilename
, p
->name
);
618 if (!p
->objdir
&& p
->srcdir
&& useobjs
) {
619 if (makeobjdirprefix
) {
620 (void)snprintf(path
, sizeof(path
), "%s/%s", makeobjdirprefix
, p
->srcdir
);
622 p
->objdir
= strdup(path
);
625 (void)snprintf(path
, sizeof(path
), "%s/obj.%s", p
->srcdir
, machine
);
627 p
->objdir
= strdup(path
);
630 (void)snprintf(path
, sizeof(path
), "%s/obj", p
->srcdir
);
632 p
->objdir
= strdup(path
);
635 p
->objdir
= p
->srcdir
;
643 (void)snprintf(path
, sizeof(path
), "%s/Makefile", p
->srcdir
);
644 if (!p
->objs
&& p
->srcdir
&& is_nonempty_file(path
))
645 fillin_program_objs(p
, p
->srcdir
);
647 if (!p
->objpaths
&& p
->objs
) {
649 if (p
->objdir
&& useobjs
)
653 for (s
= p
->objs
; s
!= NULL
; s
= s
->next
) {
654 (void)snprintf(line
, sizeof(line
), "%s/%s", objdir
, s
->str
);
655 add_string(&p
->objpaths
, line
);
659 if (!p
->objs
&& verbose
)
660 fprintf(stderr
, "%s: %s: warning: could not find any .o files.\n",
661 infilename
, p
->name
);
665 "%s: %s: error: no objpaths specified or calculated.\n",
666 infilename
, p
->name
);
667 p
->goterror
= goterror
= 1;
672 fillin_program_objs(prog_t
*p
, char *dirpath
)
678 char tempfname
[MAXPATHLEN
];
680 /* discover the objs from the srcdir Makefile */
682 (void)snprintf(tempfname
, sizeof(tempfname
), "/tmp/%sXXXXXX", confname
);
683 if ((fd
= mkstemp(tempfname
)) < 0) {
688 if ((f
= fdopen(fd
, "w")) == NULL
) {
694 fprintf(f
, ".include \"${.CURDIR}/Makefile\"\n");
695 fprintf(f
, ".if defined(PROG)\n");
696 fprintf(f
, "OBJS?= ${PROG}.o\n");
697 fprintf(f
, ".endif\n");
698 fprintf(f
, "crunchgen_objs:\n\t@echo 'OBJS= '${OBJS}\n");
701 (void)snprintf(line
, sizeof(line
),
702 "cd %s && %s -B -f %s %s CRUNCHEDPROG=1 crunchgen_objs 2>&1", dirpath
,
703 makebin
, tempfname
, makeflags
);
704 if ((f
= popen(line
, "r")) == NULL
) {
705 perror("submake pipe");
711 while (fgets(line
, MAXLINELEN
, f
)) {
712 if (strncmp(line
, "OBJS= ", 6)) {
714 "sh: warning: running as root with dot in PATH\n") == 0)
716 fprintf(stderr
, "make error: %s", line
);
721 while (isspace((unsigned char)*cp
))
725 while (*cp
&& !isspace((unsigned char)*cp
))
729 add_string(&p
->objs
, obj
);
730 while (isspace((unsigned char)*cp
))
734 if ((rc
=pclose(f
)) != 0) {
735 fprintf(stderr
, "make error: make returned %d\n", rc
);
742 remove_error_progs(void)
746 p1
= NULL
; p2
= progs
;
749 p1
= p2
, p2
= p2
->next
;
751 /* delete it from linked list */
752 fprintf(stderr
, "%s: %s: ignoring program because of errors.\n",
753 infilename
, p2
->name
);
764 gen_specials_cache(void)
769 (void)snprintf(line
, sizeof(line
), "generating %s", cachename
);
772 if ((cachef
= fopen(cachename
, "w")) == NULL
) {
778 fprintf(cachef
, "# %s - parm cache generated from %s by crunchgen %s\n\n",
779 cachename
, infilename
, CRUNCH_VERSION
);
781 for (p
= progs
; p
!= NULL
; p
= p
->next
) {
782 fprintf(cachef
, "\n");
784 fprintf(cachef
, "special %s srcdir %s\n", p
->name
, p
->srcdir
);
785 if (p
->objdir
&& useobjs
)
786 fprintf(cachef
, "special %s objdir %s\n", p
->name
, p
->objdir
);
788 fprintf(cachef
, "special %s objs", p
->name
);
789 output_strlst(cachef
, p
->objs
);
792 fprintf(cachef
, "special %s objpaths", p
->name
);
793 output_strlst(cachef
, p
->objpaths
);
801 gen_output_makefile(void)
806 (void)snprintf(line
, sizeof(line
), "generating %s", outmkname
);
809 if ((outmk
= fopen(outmkname
, "w")) == NULL
) {
815 fprintf(outmk
, "# %s - generated from %s by crunchgen %s\n\n",
816 outmkname
, infilename
, CRUNCH_VERSION
);
818 top_makefile_rules(outmk
);
820 for (p
= progs
; p
!= NULL
; p
= p
->next
)
821 prog_makefile_rules(outmk
, p
);
823 fprintf(outmk
, "\n.include <bsd.prog.mk>\n");
824 fprintf(outmk
, "\n# ========\n");
826 bottom_makefile_rules(outmk
);
833 gen_output_cfile(void)
840 (void)snprintf(line
, sizeof(line
), "generating %s", outcfname
);
843 if ((outcf
= fopen(outcfname
, "w")) == NULL
) {
850 "/* %s - generated from %s by crunchgen %s */\n",
851 outcfname
, infilename
, CRUNCH_VERSION
);
853 fprintf(outcf
, "#define EXECNAME \"%s\"\n", execfname
);
854 for (cp
= crunched_skel
; *cp
!= NULL
; cp
++)
855 fprintf(outcf
, "%s\n", *cp
);
857 for (p
= progs
; p
!= NULL
; p
= p
->next
)
858 fprintf(outcf
, "extern int _crunched_%s_stub();\n", p
->ident
);
860 fprintf(outcf
, "\nstruct stub entry_points[] = {\n");
861 for (p
= progs
; p
!= NULL
; p
= p
->next
) {
862 fprintf(outcf
, "\t{ \"%s\", _crunched_%s_stub },\n",
864 for (s
= p
->links
; s
!= NULL
; s
= s
->next
)
865 fprintf(outcf
, "\t{ \"%s\", _crunched_%s_stub },\n",
869 fprintf(outcf
, "\t{ EXECNAME, crunched_main },\n");
870 fprintf(outcf
, "\t{ NULL, NULL }\n};\n");
881 * generates a Makefile/C identifier from a program name, mapping '-' to
882 * '_' and ignoring all other non-identifier characters. This leads to
883 * programs named "foo.bar" and "foobar" to map to the same identifier.
886 if ((n
= strdup(str
)) == NULL
)
888 for (d
= s
= n
; *s
!= '\0'; s
++) {
892 if (*s
== '_' || isalnum((unsigned char)*s
))
901 dir_search(char *progname
)
903 char path
[MAXPATHLEN
];
906 for (dir
=srcdirs
; dir
!= NULL
; dir
=dir
->next
) {
907 (void)snprintf(path
, sizeof(path
), "%s/%s", dir
->str
, progname
);
916 top_makefile_rules(FILE *outmk
)
920 fprintf(outmk
, "NOMAN=\n\n");
922 fprintf(outmk
, "DBG=%s\n", dbg
);
923 fprintf(outmk
, "MAKE?=make\n");
925 fprintf(outmk
, "OBJCOPY?=objcopy\n");
926 fprintf(outmk
, "NM?=nm\n");
927 fprintf(outmk
, "AWK?=awk\n");
929 fprintf(outmk
, "CRUNCHIDE?=crunchide\n");
932 fprintf(outmk
, "CRUNCHED_OBJS=");
933 for (p
= progs
; p
!= NULL
; p
= p
->next
)
934 fprintf(outmk
, " %s.cro", p
->name
);
935 fprintf(outmk
, "\n");
936 fprintf(outmk
, "DPADD+= ${CRUNCHED_OBJS}\n");
937 fprintf(outmk
, "LDADD+= ${CRUNCHED_OBJS} ");
938 output_strlst(outmk
, libs
);
939 fprintf(outmk
, "CRUNCHEDOBJSDIRS=");
940 for (p
= progs
; p
!= NULL
; p
= p
->next
)
941 fprintf(outmk
, " %s", p
->ident
);
942 fprintf(outmk
, "\n\n");
944 fprintf(outmk
, "SUBMAKE_TARGETS=");
945 for (p
= progs
; p
!= NULL
; p
= p
->next
)
946 fprintf(outmk
, " %s_make", p
->ident
);
947 fprintf(outmk
, "\n\n");
949 fprintf(outmk
, "PROG=%s\n\n", execfname
);
951 fprintf(outmk
, "all: ${PROG}.crunched\n");
952 fprintf(outmk
, "${PROG}.crunched: ${SUBMAKE_TARGETS} .WAIT ${PROG}.strip\n");
953 fprintf(outmk
, "${PROG}.strip:\n");
954 fprintf(outmk
, "\t${MAKE} -f ${PROG}.mk ${PROG}\n");
955 fprintf(outmk
, "\t@[ -f ${PROG}.unstripped -a ! ${PROG} -nt ${PROG}.unstripped ] || { \\\n");
956 fprintf(outmk
, "\t\t${_MKSHMSG:Uecho} \" strip \" ${PROG}; \\\n");
957 fprintf(outmk
, "\t\tcp ${PROG} ${PROG}.unstripped && \\\n");
958 fprintf(outmk
, "\t\t${OBJCOPY} -S -R .note -R .ident -R .comment -R .copyright ${PROG} && \\\n");
959 fprintf(outmk
, "\t\ttouch ${PROG}.unstripped; \\\n");
960 fprintf(outmk
, "\t}\n");
961 fprintf(outmk
, "objs: $(SUBMAKE_TARGETS)\n");
962 fprintf(outmk
, "exe: %s\n", execfname
);
963 fprintf(outmk
, "clean:\n\trm -rf %s *.cro *.cro.syms *.o *_stub.c ${CRUNCHEDOBJSDIRS} ${PROG}.unstripped\n",
968 bottom_makefile_rules(FILE *outmk
)
970 fprintf(outmk
, "LDSTATIC=-static\n");
975 prog_makefile_rules(FILE *outmk
, prog_t
*p
)
979 fprintf(outmk
, "\n# -------- %s\n\n", p
->name
);
981 fprintf(outmk
, "%s_OBJPATHS=", p
->ident
);
982 #ifndef NEW_TOOLCHAIN
983 fprintf(outmk
, " %s_stub.o", p
->name
);
986 output_strlst(outmk
, p
->objpaths
);
988 fprintf(outmk
, " %s/%s.ro\n", p
->ident
, p
->name
);
990 if (p
->srcdir
&& !useobjs
) {
991 fprintf(outmk
, "%s_SRCDIR=%s\n", p
->ident
, p
->srcdir
);
993 fprintf(outmk
, "%s_OBJS=", p
->ident
);
994 output_strlst(outmk
, p
->objs
);
996 fprintf(outmk
, "%s:\n\t mkdir %s\n", p
->ident
, p
->ident
);
997 fprintf(outmk
, "%s_make: %s .PHONY\n", p
->ident
, p
->ident
);
998 fprintf(outmk
, "\t( cd %s; printf '.PATH: ${%s_SRCDIR}\\n"
999 ".CURDIR:= ${%s_SRCDIR}\\n"
1000 ".include \"$${.CURDIR}/Makefile\"\\n",
1001 p
->ident
, p
->ident
, p
->ident
);
1002 for (lst
= vars
; lst
!= NULL
; lst
= lst
->next
)
1003 fprintf(outmk
, "%s\\n", lst
->str
);
1004 fprintf(outmk
, "'\\\n");
1005 fprintf(outmk
, "\t| ${MAKE} -f- CRUNCHEDPROG=1 DBG=\"${DBG}\" depend");
1006 fprintf(outmk
, " )\n");
1007 fprintf(outmk
, "\t( cd %s; printf '.PATH: ${%s_SRCDIR}\\n"
1008 ".CURDIR:= ${%s_SRCDIR}\\n"
1009 ".include \"$${.CURDIR}/Makefile\"\\n",
1010 p
->ident
, p
->ident
, p
->ident
);
1011 for (lst
= vars
; lst
!= NULL
; lst
= lst
->next
)
1012 fprintf(outmk
, "%s\\n", lst
->str
);
1013 fprintf(outmk
, "'\\\n");
1014 fprintf(outmk
, "\t| ${MAKE} -f- CRUNCHEDPROG=1 DBG=\"${DBG}\" ");
1016 fprintf(outmk
, "${%s_OBJS} ) \n\n", p
->ident
);
1018 fprintf(outmk
, "%s.ro ) \n\n", p
->name
);
1020 fprintf(outmk
, "%s_make:\n\t@echo \"** Using existing objs for %s\"\n\n",
1023 fprintf(outmk
, "%s.cro: %s .WAIT ${%s_OBJPATHS}\n",
1024 p
->name
, p
->ident
, p
->ident
);
1026 #ifdef NEW_TOOLCHAIN
1028 fprintf(outmk
, "\t${LD} -r -o %s/%s.ro $(%s_OBJPATHS)\n",
1029 p
->ident
, p
->name
, p
->ident
);
1030 /* Use one awk command.... */
1031 fprintf(outmk
, "\t${NM} -ng %s/%s.ro | ${AWK} '/^ *U / { next };",
1033 fprintf(outmk
, " /^[0-9a-fA-F]+ C/ { next };");
1034 for (lst
= p
->keepsymbols
; lst
!= NULL
; lst
= lst
->next
)
1035 fprintf(outmk
, " / %s$$/ { next };", lst
->str
);
1036 fprintf(outmk
, " / main$$/ { print \"main _crunched_%s_stub\"; next };",
1038 /* gdb thinks these are C++ and ignores everthing after the first $$. */
1039 fprintf(outmk
, " { print $$3 \" \" $$3 \"$$$$from$$$$%s\" }' "
1040 "> %s.cro.syms\n", p
->name
, p
->name
);
1041 fprintf(outmk
, "\t${OBJCOPY} --redefine-syms %s.cro.syms ", p
->name
);
1042 fprintf(outmk
, "%s/%s.ro %s.cro\n", p
->ident
, p
->name
, p
->name
);
1044 fprintf(outmk
, "\t${LD} -dc -r -o %s.cro $(%s_OBJPATHS)\n",
1046 fprintf(outmk
, "\t${CRUNCHIDE} -k _crunched_%s_stub ", p
->ident
);
1047 for (lst
= p
->keepsymbols
; lst
!= NULL
; lst
= lst
->next
)
1048 fprintf(outmk
, "-k %s ", lst
->str
);
1049 fprintf(outmk
, "%s.cro\n", p
->name
);
1050 fprintf(outmk
, "%s_stub.c:\n", p
->name
);
1051 fprintf(outmk
, "\techo \""
1052 "int _crunched_%s_stub(int argc, char **argv, char **envp)"
1053 "{return main(argc,argv,envp);}\" >%s_stub.c\n",
1059 output_strlst(FILE *outf
, strlst_t
*lst
)
1061 for (; lst
!= NULL
; lst
= lst
->next
)
1062 fprintf(outf
, " %s", lst
->str
);
1063 fprintf(outf
, "\n");
1068 * ========================================================================
1069 * general library routines
1074 status(const char *str
)
1076 static int lastlen
= 0;
1083 spaces
= lastlen
- len
;
1087 fprintf(stderr
, " [%s]%*.*s\r", str
, spaces
, spaces
, " ");
1096 fprintf(stderr
, "%s: %d: out of memory, stopping.\n", infilename
, linenum
);
1102 add_string(strlst_t
**listp
, char *str
)
1106 /* add to end, but be smart about dups */
1108 for (p1
= NULL
, p2
= *listp
; p2
!= NULL
; p1
= p2
, p2
= p2
->next
)
1109 if (!strcmp(p2
->str
, str
))
1112 p2
= malloc(sizeof(strlst_t
));
1114 p2
->str
= strdup(str
);
1115 if (!p2
|| !p2
->str
)
1127 is_dir(const char *pathname
)
1131 if (stat(pathname
, &buf
) == -1)
1133 return S_ISDIR(buf
.st_mode
);
1137 is_nonempty_file(const char *pathname
)
1141 if (stat(pathname
, &buf
) == -1)
1144 return S_ISREG(buf
.st_mode
) && buf
.st_size
> 0;