depend.c revision 38889
1/* depend.c - Handle dependency tracking. 2 Copyright (C) 1997, 1998 Free Software Foundation, Inc. 3 4 This file is part of GAS, the GNU Assembler. 5 6 GAS is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GAS 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 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GAS; see the file COPYING. If not, write to the Free 18 Software Foundation, 59 Temple Place - Suite 330, Boston, MA 19 02111-1307, USA. */ 20 21#include "as.h" 22 23/* The file to write to, or NULL if no dependencies being kept. */ 24static char *dep_file = NULL; 25 26struct dependency 27{ 28 char *file; 29 struct dependency *next; 30}; 31 32/* All the files we depend on. */ 33static struct dependency *dep_chain = NULL; 34 35/* Current column in output file. */ 36static int column = 0; 37 38static int quote_string_for_make PARAMS ((FILE *, char *)); 39static void wrap_output PARAMS ((FILE *, char *, int)); 40 41/* Number of columns allowable. */ 42#define MAX_COLUMNS 72 43 44 45 46/* Start saving dependencies, to be written to FILENAME. If this is 47 never called, then dependency tracking is simply skipped. */ 48 49void 50start_dependencies (filename) 51 char *filename; 52{ 53 dep_file = filename; 54} 55 56/* Noticed a new filename, so try to register it. */ 57 58void 59register_dependency (filename) 60 char *filename; 61{ 62 struct dependency *dep; 63 64 if (dep_file == NULL) 65 return; 66 67 for (dep = dep_chain; dep != NULL; dep = dep->next) 68 { 69 if (! strcmp (filename, dep->file)) 70 return; 71 } 72 73 dep = (struct dependency *) xmalloc (sizeof (struct dependency)); 74 dep->file = xstrdup (filename); 75 dep->next = dep_chain; 76 dep_chain = dep; 77} 78 79/* Quote a file name the way `make' wants it, and print it to FILE. 80 If FILE is NULL, do no printing, but return the length of the 81 quoted string. 82 83 This code is taken from gcc with only minor changes. */ 84 85static int 86quote_string_for_make (file, src) 87 FILE *file; 88 char *src; 89{ 90 char *p = src; 91 int i = 0; 92 for (;;) 93 { 94 char c = *p++; 95 switch (c) 96 { 97 case '\0': 98 case ' ': 99 case '\t': 100 { 101 /* GNU make uses a weird quoting scheme for white space. 102 A space or tab preceded by 2N+1 backslashes represents 103 N backslashes followed by space; a space or tab 104 preceded by 2N backslashes represents N backslashes at 105 the end of a file name; and backslashes in other 106 contexts should not be doubled. */ 107 char *q; 108 for (q = p - 1; src < q && q[-1] == '\\'; q--) 109 { 110 if (file) 111 putc ('\\', file); 112 i++; 113 } 114 } 115 if (!c) 116 return i; 117 if (file) 118 putc ('\\', file); 119 i++; 120 goto ordinary_char; 121 122 case '$': 123 if (file) 124 putc (c, file); 125 i++; 126 /* Fall through. This can mishandle things like "$(" but 127 there's no easy fix. */ 128 default: 129 ordinary_char: 130 /* This can mishandle characters in the string "\0\n%*?[\\~"; 131 exactly which chars are mishandled depends on the `make' version. 132 We know of no portable solution for this; 133 even GNU make 3.76.1 doesn't solve the problem entirely. 134 (Also, '\0' is mishandled due to our calling conventions.) */ 135 if (file) 136 putc (c, file); 137 i++; 138 break; 139 } 140 } 141} 142 143/* Append some output to the file, keeping track of columns and doing 144 wrapping as necessary. */ 145 146static void 147wrap_output (f, string, spacer) 148 FILE *f; 149 char *string; 150 int spacer; 151{ 152 int len = quote_string_for_make (NULL, string); 153 154 if (len == 0) 155 return; 156 157 if (column && MAX_COLUMNS - 1 /*spacer*/ - 2 /*` \'*/ < column + len) 158 { 159 fprintf (f, " \\\n "); 160 column = 0; 161 if (spacer == ' ') 162 spacer = '\0'; 163 } 164 165 if (spacer == ' ') 166 { 167 putc (spacer, f); 168 ++column; 169 } 170 171 quote_string_for_make (f, string); 172 column += len; 173 174 if (spacer == ':') 175 { 176 putc (spacer, f); 177 ++column; 178 } 179} 180 181/* Print dependency file. */ 182 183void 184print_dependencies () 185{ 186 FILE *f; 187 struct dependency *dep; 188 189 if (dep_file == NULL) 190 return; 191 192 f = fopen (dep_file, "w"); 193 if (f == NULL) 194 { 195 as_warn ("Can't open `%s' for writing", dep_file); 196 return; 197 } 198 199 column = 0; 200 wrap_output (f, out_file_name, ':'); 201 for (dep = dep_chain; dep != NULL; dep = dep->next) 202 wrap_output (f, dep->file, ' '); 203 204 putc ('\n', f); 205 206 if (fclose (f)) 207 as_warn ("Can't close %s", dep_file); 208} 209